7 Commits
Author SHA1 Message Date
mitchell 480445d31e update game results 2025-03-26 21:11:52 -05:00
mitchell 7d43f9957a rename purple to pink 2025-03-26 19:31:40 -05:00
mitchell ae1766b3b0 fix LVGL screen cleaning code 2025-03-26 19:28:33 -05:00
mitchell dc0efa74eb Clean Up calls to the leds driver 2025-03-26 18:39:35 -05:00
mitchell 7cdddb2c83 update LED driver 2025-03-26 17:13:30 -05:00
mitchell 51001d6bc4 move other drivers 2025-03-26 08:21:30 -05:00
mitchell d0d1a0bb0e Move tetris images to flash 2025-03-26 08:03:14 -05:00
88 changed files with 4385 additions and 2828 deletions
-8
View File
@@ -6,23 +6,15 @@ set(SOURCES
"esp_lcd_ili9488/esp_lcd_ili9488.c"
"bottom_half.cpp"
"char_lcd.cpp"
"game_info.cpp"
"game_timer.cpp"
"hwdata.cpp"
"i2c_lcd_pcf8574.c"
"i2c.cpp"
"leds.cpp"
"nvs.cpp"
"perh.cpp"
"power.cpp"
"sd.cpp"
"speaker.cpp"
"sseg.cpp"
"starcode.cpp"
"state_tracking.cpp"
"tft.cpp"
"wires.cpp"
"wlvgl.cpp"
)
target_sources(${COMPONENT_LIB} PRIVATE ${SOURCES})
@@ -32,7 +32,6 @@ Arduino Uno (any 'duino should do)
******************************************************************************/
#include "SparkFunBQ27441.h"
#include "../i2c.h"
/*****************************************************************************
************************** Initialization Functions *************************
@@ -711,9 +710,7 @@ bool BQ27441::writeExtendedData(uint8_t classID, uint8_t offset, uint8_t * data,
int16_t BQ27441::i2cReadBytes(uint8_t subAddress, uint8_t * dest, uint8_t count)
{
int16_t timeout = BQ72441_I2C_TIMEOUT;
xSemaphoreTake(main_i2c_mutex, portMAX_DELAY);
i2c_master_write_read_device(BQ72441_I2C_NUM, _deviceAddress, &subAddress, 1, dest, count, timeout);
xSemaphoreGive(main_i2c_mutex);
return timeout;
}
@@ -729,9 +726,7 @@ uint16_t BQ27441::i2cWriteBytes(uint8_t subAddress, uint8_t * src, uint8_t count
w_buff[i+1] = src[i];
}
xSemaphoreTake(main_i2c_mutex, portMAX_DELAY);
esp_err_t ret = i2c_master_write_to_device(BQ72441_I2C_NUM, _deviceAddress, src, count+1, timeout);
xSemaphoreGive(main_i2c_mutex);
return ret == ESP_OK;
}
+34 -3
View File
@@ -1,11 +1,12 @@
#include "all.h"
static const char *TAG = "driver_all";
static void init_i2c();
void init_drivers() {
init_i2c();
// init char_lcd so we can use it to report other initialization errors.
init_lcd();
init_nvs();
init_star_code_system();
// init the bottom half so that we can get user input.
init_bottom_half();
init_sd();
@@ -15,6 +16,36 @@ void init_drivers() {
init_tft();
init_leds();
init_power_board();
}
set_lcd_header_enabled(true);
/// @brief Initializes I2C_NUM_0.
///
/// This is hooked up the to:
/// - The bottom half
/// - The char lcd
/// - The power board
/// - The MPU6050
/// - The PERH port
/// - The Capacitive Touch Panel
static void init_i2c() {
ESP_LOGI(TAG, "Initializing i2c...");
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = GPIO_NUM_5,
.scl_io_num = GPIO_NUM_6,
.sda_pullup_en = GPIO_PULLUP_DISABLE,
.scl_pullup_en = GPIO_PULLUP_DISABLE,
// .sda_pullup_en = GPIO_PULLUP_ENABLE,
// .scl_pullup_en = GPIO_PULLUP_ENABLE,
.master = {
.clk_speed = 100*1000,
},
.clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL
};
ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &conf));
ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0));
ESP_LOGI(TAG, "i2c initialized!");
}
+5 -11
View File
@@ -1,20 +1,14 @@
#ifndef ALL_H
#define ALL_H
#include "bottom_half.h"
#include "char_lcd.h"
#include "game_timer.h"
#include "i2c.h"
#include "leds.h"
#include "nvs.h"
#include "power.h"
#include "bottom_half.h"
#include "sd.h"
#include "speaker.h"
#include "sseg.h"
#include "starcode.h"
#include "state_tracking.h"
#include "tft.h"
#include "wires.h"
#include "game_timer.h"
#include "drivers/tft.h"
#include "drivers/leds.h"
#include "drivers/power.h"
void init_drivers();
+15 -95
View File
@@ -1,7 +1,5 @@
#include "bottom_half.h"
#include <esp_log.h>
#include "state_tracking.h"
#include "starcode.h"
static const char *TAG = "bottom_half";
@@ -31,11 +29,6 @@ static void receive_keypad();
static void receive_button_switch();
static void receive_touch();
static bool replay_handler(const char* event, char* arg) {
// no reply neccesary
return false;
}
// TODO: add intrupt on bottom half delta pin
// static void IRAM_ATTR gpio_isr_handler(void* arg)
// {
@@ -46,14 +39,8 @@ static bool replay_handler(const char* event, char* arg) {
void init_bottom_half() {
ESP_LOGI(TAG, "Initializing bottom half...");
gpio_config_t int_conf = {
.pin_bit_mask = 1ULL << BOTTOM_PIN_INTERUPT,
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
ESP_ERROR_CHECK(gpio_config(&int_conf));
ESP_ERROR_CHECK(gpio_set_direction(BOTTOM_PIN_INTERUPT, GPIO_MODE_INPUT));
ESP_ERROR_CHECK(gpio_set_pull_mode(BOTTOM_PIN_INTERUPT, GPIO_PULLUP_ONLY));
// TODO: do interupt stuff.
// ESP_ERROR_CHECK(gpio_intr_enable(BOTTOM_PIN_INTERUPT));
@@ -69,64 +56,35 @@ void init_bottom_half() {
xTaskCreate(poll_bottom_task, "poll_bottom", 4096, NULL, 10, NULL);
register_replay_fn(replay_handler);
ESP_LOGI(TAG, "Bottom half initialized!");
}
static uint8_t receive_delta(void) {
uint8_t reg = 1;
xSemaphoreTake(main_i2c_mutex, portMAX_DELAY);
esp_err_t result = i2c_master_write_read_device(BOTTOM_I2C_NUM, BOTTOM_I2C_ADDR, &reg, 1, buf, 1, (100 / portTICK_PERIOD_MS));
ESP_ERROR_CHECK_WITHOUT_ABORT(result);
if (result != ESP_OK) {
return 0;
}
buf[0] = 0;
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_write_read_device(BOTTOM_I2C_NUM, BOTTOM_I2C_ADDR, &reg, 1, buf, 1, (100 / portTICK_PERIOD_MS)));
return buf[0];
}
static void receive_keypad(void) {
// TODO: change the bottom half polling scheme from a state-based protocol to an event based protocol
uint8_t reg = 2;
xSemaphoreTake(main_i2c_mutex, portMAX_DELAY);
esp_err_t result = i2c_master_write_read_device(BOTTOM_I2C_NUM, BOTTOM_I2C_ADDR, &reg, 1, buf, 2, (100 / portTICK_PERIOD_MS));
xSemaphoreGive(main_i2c_mutex);
ESP_ERROR_CHECK_WITHOUT_ABORT(result);
if (result != ESP_OK) {
return;
}
buf[0] = 0;
buf[1] = 0;
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_write_read_device(BOTTOM_I2C_NUM, BOTTOM_I2C_ADDR, &reg, 1, buf, 2, (100 / portTICK_PERIOD_MS)));
uint16_t new_keypad_state = buf[0] | (buf[1] << 8);
uint16_t just_pressed = new_keypad_state & ~keypad_state;
if (is_state_tracking() && just_pressed) {
char buf[6];
sprintf(buf, "%d", just_pressed);
event_occured("KP_PRESS", buf);
}
keypad_pressed |= just_pressed;
uint16_t just_released = ~new_keypad_state & keypad_state;
if (is_state_tracking() && just_released) {
char buf[6];
sprintf(buf, "%d", just_released);
event_occured("KP_RELEASE", buf);
}
star_code_handle_keypad(&just_pressed, &just_released);
keypad_pressed |= just_pressed;
keypad_released |= just_released;
keypad_state = new_keypad_state;
}
static void receive_button_switch(void) {
uint8_t reg = 3;
xSemaphoreTake(main_i2c_mutex, portMAX_DELAY);
esp_err_t result = i2c_master_write_read_device(BOTTOM_I2C_NUM, BOTTOM_I2C_ADDR, &reg, 1, buf, 2, (100 / portTICK_PERIOD_MS));
xSemaphoreGive(main_i2c_mutex);
ESP_ERROR_CHECK_WITHOUT_ABORT(result);
if (result != ESP_OK) {
return;
}
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_write_read_device(BOTTOM_I2C_NUM, BOTTOM_I2C_ADDR, &reg, 1, buf, 2, (100 / portTICK_PERIOD_MS)));
uint8_t new_button_state = buf[1] & 0xF;
uint8_t new_switch_state = (~buf[0]) & 0xF;
uint8_t new_switch_touch_state = (buf[1] >> 4) & 0xF;
@@ -134,57 +92,27 @@ static void receive_button_switch(void) {
// button
uint8_t just_pressed = new_button_state & ~button_state;
button_pressed |= just_pressed;
if (is_state_tracking() && just_pressed) {
char buf[4];
sprintf(buf, "%d", just_pressed);
event_occured("BTN_PRESS", buf);
}
uint8_t just_released = ~new_button_state & button_state;
button_released |= just_released;
if (is_state_tracking() && just_released) {
char buf[4];
sprintf(buf, "%d", just_released);
event_occured("BTN_RELEASE", buf);
}
button_state = new_button_state;
// switch
uint8_t just_flipped_up = new_switch_state & ~switch_state;
switch_flipped_up |= just_flipped_up;
if (is_state_tracking() && just_flipped_up) {
char buf[4];
sprintf(buf, "%d", just_flipped_up);
event_occured("SW_UP", buf);
}
uint8_t just_flipped_down = ~new_switch_state & switch_state;
switch_flipped_down |= just_flipped_down;
if (is_state_tracking() && just_flipped_down) {
char buf[4];
sprintf(buf, "%d", just_flipped_down);
event_occured("SW_DOWN", buf);
}
switch_state = new_switch_state;
// switch touch
uint8_t touch_just_pressed = new_switch_touch_state & ~switch_touch_state;
switch_touch_pressed |= touch_just_pressed;
if (is_state_tracking() && touch_just_pressed) {
char buf[4];
sprintf(buf, "%d", touch_just_pressed);
event_occured("SW_TOUCH", buf);
}
uint8_t touch_just_released = ~new_switch_touch_state & switch_touch_state;
switch_touch_released |= touch_just_released;
if (is_state_tracking() && touch_just_released) {
char buf[4];
sprintf(buf, "%d", touch_just_released);
event_occured("SW_UNTOUCH", buf);
}
switch_touch_state = new_switch_touch_state;
}
@@ -192,22 +120,14 @@ static void receive_button_switch(void) {
static void receive_touch(void) {
uint8_t reg = 4;
buf[0] = 0;
xSemaphoreTake(main_i2c_mutex, portMAX_DELAY);
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_write_read_device(BOTTOM_I2C_NUM, BOTTOM_I2C_ADDR, &reg, 1, buf, 1, (100 / portTICK_PERIOD_MS)));
xSemaphoreGive(main_i2c_mutex);
bool new_touch_state = buf[0] != 0;
bool just_pressed = new_touch_state & !touch_state;
touch_pressed |= just_pressed;
if (is_state_tracking() && just_pressed) {
event_occured("FINGER_TOUCHED", NULL);
}
bool just_released = (!new_touch_state) & touch_state;
touch_released |= just_released;
if (is_state_tracking() && just_released) {
event_occured("FINGER_UNTOUCHED", NULL);
}
touch_state = new_touch_state;
}
@@ -243,8 +163,7 @@ void clear_all_pressed_released(void) {
touch_released = 0;
}
// TODO: this is public, but it won't need to be after the event-based protocol refactor
bool take_key(KeypadKey* kp, uint16_t* keypad_bitfield) {
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) {
@@ -260,10 +179,10 @@ bool take_key(KeypadKey* kp, uint16_t* keypad_bitfield) {
}
bool get_keypad_pressed(KeypadKey* kp) {
return take_key(kp, &keypad_pressed);
return _take_key(kp, &keypad_pressed);
}
bool get_keypad_released(KeypadKey* kp) {
return take_key(kp, &keypad_released);
return _take_key(kp, &keypad_released);
}
char char_of_keypad_key(KeypadKey kp) {
@@ -388,6 +307,7 @@ uint8_t get_switch_touch_state(){
return switch_touch_state;
}
bool get_touch_state(void) {
return touch_state;
}
+13 -21
View File
@@ -6,7 +6,7 @@
#define BOTTOM_I2C_NUM I2C_NUM_0
#define BOTTOM_I2C_ADDR 126
#define BOTTOM_PIN_INTERUPT GPIO_NUM_13
#define BOTTOM_PIN_INTERUPT GPIO_NUM_0
#define DELTA_BIT_KP 0
#define DELTA_BIT_BUTTON_SWITCH 1
@@ -14,22 +14,22 @@
/// @brief An enum for the possible keypad buttons.
typedef enum {
kd = 0,
pound = 1,
k0 = 2,
k1 = 0,
k4 = 1,
k7 = 2,
star = 3,
kc = 4,
k9 = 5,
k2 = 4,
k5 = 5,
k8 = 6,
k7 = 7,
kb = 8,
k0 = 7,
k3 = 8,
k6 = 9,
k5 = 10,
k4 = 11,
k9 = 10,
pound = 11,
ka = 12,
k3 = 13,
k2 = 14,
k1 = 15,
kb = 13,
kc = 14,
kd = 15,
} KeypadKey;
/// @brief An enum for the possible buttons.
@@ -126,14 +126,6 @@ bool get_touch_pressed();
/// @return true if the touch sensor was just released
bool get_touch_released();
/// @brief A helper function for internal use.
///
/// Takes one key from the bitfield and sets the `kp` variable accordingly if the bitfield is not 0.
/// @param kp Out. The keypad key to set.
/// @param keypad_bitfield A pointer to the keypad bitfield to take a key from
/// @return true if a key was taken from the bitfield
bool take_key(KeypadKey* kp, uint16_t* keypad_bitfield);
// TODO: add touch sensor for switch
#endif /* BOTTOM_HALF_HPP */
+30 -269
View File
@@ -2,337 +2,98 @@
#include "./i2c_lcd_pcf8574.h"
#include <esp_log.h>
#include "state_tracking.h"
#include <cstring>
#include "power.h"
#include "starcode.h"
#include "game_info.h"
i2c_lcd_pcf8574_handle_t lcd;
SemaphoreHandle_t lcd_mutex;
static volatile bool cursor_visible = false;
static volatile uint8_t cursor_resting_row = 0;
static volatile uint8_t cursor_resting_col = 0;
static volatile bool header_enabled = false;
static const char *TAG = "char_lcd";
static const char* EMPTY_ROW = " ";
static char buf[65];
// TODO: move this to power.cpp
static void monitor_battery_task(void* _arg) {
(void) _arg;
while (true) {
vTaskDelay(pdMS_TO_TICKS(1'000));
lcd_print_header_bat();
}
}
static bool replay_handler(const char* event, char* arg) {
if (strcmp(event, "LCD_CLEAR") == 0) {
lcd_clear();
}
else if (strcmp(event, "LCD_SET_DISPLAY") == 0) {
lcd_set_display(strcmp(arg, "true") == 0);
}
else if (strcmp(event, "LCD_CURSOR_VIS") == 0) {
lcd_set_cursor_vis(strcmp(arg, "true") == 0);
}
else if (strcmp(event, "LCD_CURSOR_BLINK") == 0) {
lcd_set_cursor_blink(strcmp(arg, "true") == 0);
}
else if (strcmp(event, "LCD_SCROLL_DISPLAY_LEFT") == 0) {
lcd_scroll_display_left();
}
else if (strcmp(event, "LCD_SCROLL_DISPLAY_RIGHT") == 0) {
lcd_scroll_display_right();
}
else if (strcmp(event, "LCD_LEFT_TO_RIGHT") == 0) {
lcd_left_to_right();
}
else if (strcmp(event, "LCD_RIGHT_TO_LEFT") == 0) {
lcd_right_to_left();
}
else if (strcmp(event, "LCD_AUTOSCROLL") == 0) {
lcd_set_autoscroll(strcmp(arg, "true") == 0);
}
else if (strcmp(event, "LCD_BACKLIGHT") == 0) {
lcd_set_backlight(strcmp(arg, "true") == 0);
}
else if (strcmp(event, "LCD_CREATE_CHAR") == 0) {
char* location_str = strtok(arg, ",");
uint8_t location = atoi(location_str);
uint8_t charmap[8];
for (int i = 0; i < 8; i++) {
char* str = strtok(NULL, ",");
charmap[i] = atoi(str);
}
lcd_create_char(location, charmap);
}
else if (strcmp(event, "LCD_PRINT") == 0) {
char* str = strtok(arg, ",");
uint8_t row = atoi(str);
str = strtok(NULL, ",");
uint8_t col = atoi(str);
// get remaining part of string.
str = strtok(NULL, "");
// TODO: handle \r and \n
lcd_print(row, col, str);
} else {
return false;
}
return true;
}
void init_lcd() {
ESP_LOGI(TAG, "Initializing LCD...");
lcd_mutex = xSemaphoreCreateMutex();
assert(lcd_mutex != NULL);
lcd_init(&lcd, LCD_ADDR, CHAR_LCD_I2C_NUM);
lcd_begin(&lcd, LCD_COLS, LCD_ROWS);
lcd_set_backlight_to(&lcd, 1);
register_replay_fn(replay_handler);
xTaskCreate(monitor_battery_task, "bat_monitor", 1024*2, nullptr, 0, nullptr);
lcd_set_backlight(&lcd, 255);
ESP_LOGI(TAG, "LCD initialized!");
}
void lcd_clear(bool no_lock) {
if (!header_enabled) {
if (!no_lock) xSemaphoreTake(lcd_mutex, portMAX_DELAY);
lcd_clear(&lcd);
if (!no_lock) xSemaphoreGive(lcd_mutex);
if (is_state_tracking()) {
event_occured("LCD_CLEAR", NULL);
}
} else {
if (!no_lock) xSemaphoreTake(lcd_mutex, portMAX_DELAY);
lcd_print(1, 0, EMPTY_ROW, true);
lcd_print(2, 0, EMPTY_ROW, true);
lcd_print(3, 0, EMPTY_ROW, true);
if (!no_lock) xSemaphoreGive(lcd_mutex);
}
void lcd_clear() {
lcd_clear(&lcd);
}
void lcd_set_display(bool display, bool no_lock) {
if (!no_lock) xSemaphoreTake(lcd_mutex, portMAX_DELAY);
void lcd_cursor_home() {
lcd_home(&lcd);
}
void lcd_set_cursor_pos(uint8_t col, uint8_t row) {
lcd_set_cursor(&lcd, col, row);
}
void lcd_set_display(bool display) {
if (display) {
lcd_display(&lcd);
} else {
lcd_no_display(&lcd);
}
if (!no_lock) xSemaphoreGive(lcd_mutex);
if (is_state_tracking()) {
event_occured("LCD_SET_DISPLAY", display ? "true" : "false");
}
}
void lcd_set_cursor_vis(bool cursor, bool no_lock) {
if (!no_lock) xSemaphoreTake(lcd_mutex, portMAX_DELAY);
void lcd_set_cursor_vis(bool cursor) {
if (cursor) {
lcd_cursor(&lcd);
} else {
lcd_no_cursor(&lcd);
}
if (!no_lock) xSemaphoreGive(lcd_mutex);
cursor_visible = cursor;
if (is_state_tracking()) {
event_occured("LCD_CURSOR_VIS", cursor ? "true" : "false");
}
}
void lcd_set_cursor_blink(bool blink, bool no_lock) {
if (!no_lock) xSemaphoreTake(lcd_mutex, portMAX_DELAY);
void lcd_set_cursor_blink(bool blink) {
if (blink) {
lcd_blink(&lcd);
} else {
lcd_no_blink(&lcd);
}
if (!no_lock) xSemaphoreGive(lcd_mutex);
if (is_state_tracking()) {
event_occured("LCD_CURSOR_BLINK", blink ? "true" : "false");
}
}
void lcd_scroll_display_left(bool no_lock) {
if (!no_lock) xSemaphoreTake(lcd_mutex, portMAX_DELAY);
void lcd_scroll_display_left() {
lcd_scroll_display_left(&lcd);
if (!no_lock) xSemaphoreGive(lcd_mutex);
if (is_state_tracking()) {
event_occured("LCD_SCROLL_DISPLAY_LEFT", NULL);
}
}
void lcd_scroll_display_right(bool no_lock) {
if (!no_lock) xSemaphoreTake(lcd_mutex, portMAX_DELAY);
void lcd_scroll_display_right() {
lcd_scroll_display_right(&lcd);
if (!no_lock) xSemaphoreGive(lcd_mutex);
if (is_state_tracking()) {
event_occured("LCD_SCROLL_DISPLAY_RIGHT", NULL);
}
}
void lcd_left_to_right(bool no_lock) {
if (!no_lock) xSemaphoreTake(lcd_mutex, portMAX_DELAY);
void lcd_left_to_right() {
lcd_left_to_right(&lcd);
if (!no_lock) xSemaphoreGive(lcd_mutex);
if (is_state_tracking()) {
event_occured("LCD_LEFT_TO_RIGHT", NULL);
}
}
void lcd_right_to_left(bool no_lock) {
if (!no_lock) xSemaphoreTake(lcd_mutex, portMAX_DELAY);
void lcd_right_to_left() {
lcd_right_to_left(&lcd);
if (!no_lock) xSemaphoreGive(lcd_mutex);
if (is_state_tracking()) {
event_occured("LCD_RIGHT_TO_LEFT", NULL);
}
}
void lcd_set_autoscroll(bool autoscroll, bool no_lock) {
if (!no_lock) xSemaphoreTake(lcd_mutex, portMAX_DELAY);
void lcd_set_autoscroll(bool autoscroll) {
if (autoscroll) {
lcd_autoscroll(&lcd);
} else {
lcd_no_autoscroll(&lcd);
}
if (!no_lock) xSemaphoreGive(lcd_mutex);
if (is_state_tracking()) {
event_occured("LCD_AUTOSCROLL", autoscroll ? "true" : "false");
}
}
void lcd_set_backlight(bool backlight, bool no_lock) {
if (!no_lock) xSemaphoreTake(lcd_mutex, portMAX_DELAY);
lcd_set_backlight_to(&lcd, backlight);
if (!no_lock) xSemaphoreGive(lcd_mutex);
if (is_state_tracking()) {
sprintf(buf, "%d", backlight);
event_occured("LCD_BACKLIGHT", backlight ? "true" : "false");
}
void lcd_set_backlight(uint8_t brightness) {
lcd_set_backlight(&lcd, brightness);
}
void lcd_create_char(uint8_t location, const uint8_t charmap[], bool no_lock) {
if (location == 8) location = 0;
if (!no_lock) xSemaphoreTake(lcd_mutex, portMAX_DELAY);
void lcd_create_char(uint8_t location, uint8_t charmap[]) {
lcd_create_char(&lcd, location, charmap);
if (!no_lock) xSemaphoreGive(lcd_mutex);
if (is_state_tracking()) {
snprintf(buf, sizeof(buf),
"%d,%d,%d,%d,%d,%d,%d,%d,%d", location,
charmap[0], charmap[1], charmap[2], charmap[3], charmap[4], charmap[5], charmap[6], charmap[7]
);
event_occured("LCD_CREATE_CHAR", buf);
}
}
void lcd_print(uint8_t row, uint8_t col, const char* str, bool no_lock) {
if (!no_lock) xSemaphoreTake(lcd_mutex, portMAX_DELAY);
lcd_set_cursor(&lcd, col, row);
void lcd_write(uint8_t value) {
lcd_write(&lcd, value);
}
void lcd_print(const char* str) {
lcd_print(&lcd, str);
if (cursor_visible) {
lcd_set_cursor(&lcd, cursor_resting_col, cursor_resting_row);
}
if (!no_lock) xSemaphoreGive(lcd_mutex);
if (is_state_tracking()) {
// TODO: handle \r and \n and others
snprintf(buf, sizeof(buf), "%d,%d,%s", row, col, str);
event_occured("LCD_PRINT", buf);
}
}
void set_lcd_header_enabled(bool enable) {
bool old_header_enabled = header_enabled;
header_enabled = enable;
// update header in response to enabling/disabling the header
if (enable && !old_header_enabled) {
lcd_print_header();
} else if (!enable && old_header_enabled) {
lcd_print(0, 0, EMPTY_ROW);
}
}
bool lcd_header_enabled() {
return header_enabled;
}
void lcd_print_header() {
lcd_print_header_star_code();
lcd_print_header_step();
lcd_print_header_bat();
}
void lcd_do_splash() {
const uint8_t custom_char[6][8] = {
{ 0x01, 0x01, 0x02, 0x02, 0x07, 0x07, 0x0F, 0x0D },
{ 0x10, 0x10, 0x18, 0x18, 0x1C, 0x0C, 0x0E, 0x06 },
{ 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x07, 0x07 },
{ 0x19, 0x1B, 0x13, 0x17, 0x07, 0x0F, 0x0F, 0x1F },
{ 0x13, 0x1B, 0x1F, 0x1F, 0x00, 0x1F, 0x1F, 0x1F },
{ 0x00, 0x00, 0x10, 0x10, 0x00, 0x18, 0x1C, 0x1C },
};
// TODO: make the lcd_lib somehow support the custom character 0 which would otherwise be a null terminator
xSemaphoreTake(lcd_mutex, portMAX_DELAY);
lcd_create_char(1, custom_char[0], true);
lcd_create_char(2, custom_char[1], true);
lcd_create_char(3, custom_char[2], true);
lcd_create_char(4, custom_char[3], true);
lcd_create_char(5, custom_char[4], true);
lcd_create_char(6, custom_char[5], true);
lcd_print(1, 6, "\x01\x02Marino", true);
lcd_print(2, 5, "\x03\x04\x05\x06""DEV", true);
xSemaphoreGive(lcd_mutex);
}
bool lcd_lock(uint32_t ticks_to_wait) {
return xSemaphoreTake(lcd_mutex, ticks_to_wait);
}
void lcd_unlock() {
xSemaphoreGive(lcd_mutex);
}
void lcd_set_cursor_resting_position(uint8_t row, uint8_t col) {
cursor_resting_row = row;
cursor_resting_col = col;
}
void lcd_get_cursor_resting_position(uint8_t* row, uint8_t* col) {
if (row) *row = cursor_resting_row;
if (col) *col = cursor_resting_col;
}
bool lcd_is_cursor_visible() {
return cursor_visible;
void lcd_print(uint8_t col, uint8_t row, const char* str) {
lcd_set_cursor_pos(col, row);
lcd_print(&lcd, str);
}
+34 -69
View File
@@ -6,91 +6,56 @@
#define CHAR_LCD_I2C_NUM I2C_NUM_0
#define LCD_ADDR 0x27
#define LCD_ROWS 4
#define LCD_COLS 20
#define LCD_ROWS 4
/// @brief Initializes the 2004 Character LCD
/// Initializes the 2004 Character LCD
void init_lcd();
/// @brief Clear the LCD
void lcd_clear(bool no_lock = false);
/// Clear the LCD
void lcd_clear();
/// @brief Move cursor to home position
void lcd_cursor_home(bool no_lock = false);
/// Move cursor to home position
void lcd_cursor_home();
/// @brief Turn the display on/off
void lcd_set_display(bool display, bool no_lock = false);
/// Set cursor position
void lcd_set_cursor_pos(uint8_t col, uint8_t row);
/// @brief Turn the cursor's visibility on/off
void lcd_set_cursor_vis(bool cursor, bool no_lock = false);
/// Turn the display on/off
void lcd_set_display(bool display);
/// @brief Turn blinking cursor on/off
void lcd_set_cursor_blink(bool blink, bool no_lock = false);
/// Turn the cursor's visibility on/off
void lcd_set_cursor_vis(bool cursor);
/// @brief Scroll the display left
void lcd_scroll_display_left(bool no_lock = false);
/// @brief Scroll the display right
void lcd_scroll_display_right(bool no_lock = false);
/// Turn blinking cursor on/off
void lcd_set_cursor_blink(bool blink);
/// @brief Set the text to flows automatically left to right
void lcd_left_to_right(bool no_lock = false);
/// @brief Set the text to flows automatically right to left
void lcd_right_to_left(bool no_lock = false);
/// Scroll the display left
void lcd_scroll_display_left();
/// Scroll the display right
void lcd_scroll_display_right();
/// @brief Turn on/off autoscroll
void lcd_set_autoscroll(bool autoscroll, bool no_lock = false);
/// Set the text to flows automatically left to right
void lcd_left_to_right();
/// Set the text to flows automatically right to left
void lcd_right_to_left();
/// @brief Set backlight brightness
void lcd_set_backlight(bool backlight, bool no_lock = false);
// Turn on/off autoscroll
void lcd_set_autoscroll(bool autoscroll);
/// @brief Create a custom character. You get 8 custom characters.
/// You can print custom characters by using escape characters in strings:
/// use '\x01' - '\x07' for custom characters 1-7. Use '\x08' for custom char 0.
void lcd_create_char(uint8_t location, const uint8_t charmap[], bool no_lock = false);
// Set backlight brightness
void lcd_set_backlight(uint8_t brightness);
/// @brief Print a string to the LCD at a given pos.
/// @param row the row the print the string at.
/// @param col the column to print the string at.
/// @param str the string to print.
void lcd_print(uint8_t row, uint8_t col, const char* str, bool no_lock = false);
// Create a custom character
void lcd_create_char(uint8_t location, uint8_t charmap[]);
/// @brief Enables or disables the header on the LCD.
/// @param enable `true` to enable the header, `false` to disable.
void set_lcd_header_enabled(bool enable);
// Write a character to the LCD
void lcd_write(uint8_t value);
/// @brief Returns weather or not the lcd_header is enabled.
/// @return `true` if the header is enabled, `false` otherwise.
bool lcd_header_enabled();
// Print a string to the LCD
void lcd_print(const char* str);
/// @brief Prints the header in the LCD.
void lcd_print_header();
/// @brief Prints the splash screen for the BLK_BOX.
void lcd_do_splash();
/// @brief Locks the LCD to allow chaining multiple commands without interuptions.
///
/// Commands you call while you lock the LCD, you must call with the `no_lock` flag set to true.
///
/// Do not hold this lock for an extended period of time.
/// @return `true` iff the lock was aquired.
bool lcd_lock(uint32_t ticks_to_wait);
/// @brief Unlocks the LCD to give away the mutex access to it.
void lcd_unlock();
/// @brief Set the resting position for the cursor
/// @param row the row where the cursor should rest
/// @param col the column where the cursor should rest
void lcd_set_cursor_resting_position(uint8_t row, uint8_t col);
/// @brief Get the current resting position of the cursor
/// @param row pointer to store the resting row
/// @param col pointer to store the resting column
void lcd_get_cursor_resting_position(uint8_t* row, uint8_t* col);
/// @brief Check if the cursor is currently visible
/// @return true if cursor is visible, false otherwise
bool lcd_is_cursor_visible();
// Print a string to the LCD at a given pos
void lcd_print(uint8_t col, uint8_t row, const char* str);
#endif /* CHAR_LCD_H */
-21
View File
@@ -1,21 +0,0 @@
#include "game_info.h"
#include "starcode.h"
#include <stdio.h>
#include "char_lcd.h"
static char game_state[GAME_STATE_MAX_LEN+2] = " MENU ";
void set_game_state(const char* new_state) {
snprintf(game_state, sizeof(game_state), " %-5s", new_state);
}
void reset_game_state() {
set_game_state("");
}
void lcd_print_header_step() {
if (!lcd_header_enabled()) return;
if (lcd_starcode_displaying_result()) return;
lcd_print(0, 10, game_state);
}
-17
View File
@@ -1,17 +0,0 @@
#ifndef GAME_INFO_H
#define GAME_INFO_H
#define GAME_STATE_MAX_LEN 5
/// @brief Sets the game state, used for the header.
///
/// Must be <= 5 characters
void set_game_state(const char* new_state);
/// @brief Resets the game state to be blank.
void reset_game_state();
/// @brief Prints the game state section of the header to the char_lcd. (row 0, columns 11-15)
void lcd_print_header_step();
#endif /* GAME_INFO_H */
-494
View File
@@ -1,494 +0,0 @@
#include "hwdata.h"
#include "esp_err.h"
#include "esp_log.h"
#include "bottom_half.h"
#include "char_lcd.h"
#include "../helper.h"
#include "nvs.h"
static const char* TAG = "hwdata";
HWData::HWData()
: compat_mode(true)
{}
HWData::HWData(HWData1 data, bool compat_mode)
: compat_mode(compat_mode),
inner(data)
{}
esp_err_t HWData::save(nvs_handle_t handle, bool force) {
if (compat_mode && !force) {
ESP_LOGW(TAG, "Not saving due to being in compatability mode.");
return ESP_OK;
}
return inner.save(handle);
}
HWData HWData::load(nvs_handle_t handle) {
esp_err_t err;
uint16_t stored_version = 0;
err = nvs_get_u16(handle, "version", &stored_version);
if (err == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGE(TAG, "No NVS data found! using defaults");
return HWData();
} else if (err != ESP_OK) {
ESP_ERROR_CHECK_WITHOUT_ABORT(err);
ESP_LOGE(TAG, "Other esp error! using defaults");
return HWData();
}
HWData1 data;
switch (stored_version) {
case 0:
ESP_LOGE(TAG, "HWData version was 0! using defaults");
return HWData();
case 1:
data.load(handle);
return HWData(data, false);
default:
ESP_LOGW(TAG, "Max currently supported version is %d, but saved version is %d. Loading version %d anyway!", CURRENT_HWDATA_VERSION, stored_version, CURRENT_HWDATA_VERSION);
data.load(handle);
return HWData(data, true);
}
}
HWData1::HWData1() {}
esp_err_t HWData1::save(nvs_handle_t handle) const {
ESP_ERROR_CHECK(nvs_set_u16(handle, "version", 1));
// Serial number
ESP_ERROR_CHECK(nvs_set_str(handle, "serial_num", serial_num.c_str()));
// Revisions
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_ctrl_maj", rev_ctrl_maj));
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_ctrl_min", rev_ctrl_min));
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_exp_maj", rev_exp_maj));
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_exp_min", rev_exp_min));
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_ft_maj", rev_ft_maj));
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_ft_min", rev_ft_min));
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_fb_maj", rev_fb_maj));
ESP_ERROR_CHECK(nvs_set_u8(handle, "rev_fb_min", rev_fb_min));
// Enums
ESP_ERROR_CHECK(nvs_set_u8(handle, "sseg_color_t", static_cast<uint8_t>(sseg_color_t)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "sseg_color_b", static_cast<uint8_t>(sseg_color_b)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "lcd_color", static_cast<uint8_t>(lcd_color)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "button_type", static_cast<uint8_t>(button_type)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "tft_type", static_cast<uint8_t>(tft_type)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "bat_type", static_cast<uint8_t>(bat_type)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "shape1", static_cast<uint8_t>(shape1)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "shape2", static_cast<uint8_t>(shape2)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "shape3", static_cast<uint8_t>(shape3)));
ESP_ERROR_CHECK(nvs_set_u8(handle, "shape4", static_cast<uint8_t>(shape4)));
// Other fields
ESP_ERROR_CHECK(nvs_set_u8(handle, "switch_pos", switch_pos));
ESP_ERROR_CHECK(nvs_set_u8(handle, "has_speaker", has_speaker));
ESP_ERROR_CHECK(nvs_set_u8(handle, "has_mic", has_mic));
ESP_ERROR_CHECK(nvs_set_u8(handle, "has_ir", has_ir));
ESP_ERROR_CHECK(nvs_set_u8(handle, "has_rfid", has_rfid));
ESP_ERROR_CHECK(nvs_set_u8(handle, "has_fp", has_fp));
ESP_ERROR_CHECK(nvs_set_u8(handle, "has_fp_hall", has_fp_hall));
ESP_ERROR_CHECK(nvs_set_u8(handle, "has_close_hall", has_close_hall));
// Battery capacity
ESP_ERROR_CHECK(nvs_set_u16(handle, "bat_cap", bat_cap));
return nvs_commit(handle);
}
void HWData1::load(nvs_handle_t handle) {
char buf[128];
size_t required_size = sizeof(buf);
esp_err_t err = nvs_get_str(handle, "serial_num", buf, &required_size);
serial_num = (err == ESP_OK) ? std::string(buf) : "";
nvs_get_u8(handle, "rev_ctrl_maj", &rev_ctrl_maj);
nvs_get_u8(handle, "rev_ctrl_min", &rev_ctrl_min);
nvs_get_u8(handle, "rev_exp_maj", &rev_exp_maj);
nvs_get_u8(handle, "rev_exp_min", &rev_exp_min);
nvs_get_u8(handle, "rev_ft_maj", &rev_ft_maj);
nvs_get_u8(handle, "rev_ft_min", &rev_ft_min);
nvs_get_u8(handle, "rev_fb_maj", &rev_fb_maj);
nvs_get_u8(handle, "rev_fb_min", &rev_fb_min);
uint8_t tmp;
if (nvs_get_u8(handle, "sseg_color_t", &tmp) == ESP_OK) sseg_color_t = static_cast<SSegColor>(tmp);
if (nvs_get_u8(handle, "sseg_color_b", &tmp) == ESP_OK) sseg_color_b = static_cast<SSegColor>(tmp);
if (nvs_get_u8(handle, "lcd_color", &tmp) == ESP_OK) lcd_color = static_cast<LCDColor>(tmp);
if (nvs_get_u8(handle, "button_type", &tmp) == ESP_OK) button_type = static_cast<ButtonType>(tmp);
if (nvs_get_u8(handle, "tft_type", &tmp) == ESP_OK) tft_type = static_cast<TFTType>(tmp);
if (nvs_get_u8(handle, "bat_type", &tmp) == ESP_OK) bat_type = static_cast<BatType>(tmp);
nvs_get_u16(handle, "bat_cap", &bat_cap);
if (nvs_get_u8(handle, "shape1", &tmp) == ESP_OK) shape1 = static_cast<ShapeType>(tmp);
if (nvs_get_u8(handle, "shape2", &tmp) == ESP_OK) shape2 = static_cast<ShapeType>(tmp);
if (nvs_get_u8(handle, "shape3", &tmp) == ESP_OK) shape3 = static_cast<ShapeType>(tmp);
if (nvs_get_u8(handle, "shape4", &tmp) == ESP_OK) shape4 = static_cast<ShapeType>(tmp);
nvs_get_u8(handle, "switch_pos", &switch_pos);
nvs_get_u8(handle, "has_speaker", &tmp); has_speaker = tmp;
nvs_get_u8(handle, "has_mic", &tmp); has_mic = tmp;
nvs_get_u8(handle, "has_ir", &tmp); has_ir = tmp;
nvs_get_u8(handle, "has_rfid", &tmp); has_rfid = tmp;
nvs_get_u8(handle, "has_fp", &tmp); has_fp = tmp;
nvs_get_u8(handle, "has_fp_hall", &tmp); has_fp_hall = tmp;
nvs_get_u8(handle, "has_close_hall", &tmp); has_close_hall = tmp;
}
static void handle_uint8(KeypadKey key, uint8_t& val) {
char key_c = char_of_keypad_key(key);
bool is_digit = std::isdigit(static_cast<unsigned char>(key_c));
uint8_t digit = is_digit ? static_cast<uint8_t>(key_c - '0') : 0;
if (key == KeypadKey::star) {
val = 0;
} else if (is_digit) {
uint16_t new_digit = ((uint16_t) val) * 10 + (uint16_t) digit;
if (new_digit < 255) val = new_digit;
}
}
static void handle_uint16(KeypadKey key, uint16_t& val) {
char key_c = char_of_keypad_key(key);
bool is_digit = std::isdigit(static_cast<unsigned char>(key_c));
uint8_t digit = is_digit ? static_cast<uint8_t>(key_c - '0') : 0;
if (key == KeypadKey::star) {
val = 0;
} else if (is_digit) {
uint32_t new_digit = ((uint32_t) val) * 10 + (uint32_t) digit;
if (new_digit < 65535) val = new_digit;
}
}
static void handle_enum(ButtonKey key, uint8_t& val, uint8_t n_items) {
if (key == ButtonKey::b1) {
// dec
val = (val + n_items - 1) % n_items;
} else if (key == ButtonKey::b2) {
// inc
val = (val + 1) % n_items;
}
}
void hardware_config() {
clean_bomb();
uint8_t current_item = 0;
const uint8_t n_items = 28;
HWData1& hwdata = get_hw_data().inner;
ButtonKey btn;
KeypadKey key;
bool dirty = true;
while (true) {
if (dirty) {
// display
char name[21];
char value[21];
switch (current_item) {
case 0: // serial_num
snprintf(name, sizeof(name), "%-20s", "serial_num");
snprintf(value, sizeof(value), "%s", hwdata.serial_num.c_str());
break;
case 1: // rev_ctrl_maj
snprintf(name, sizeof(name), "%-20s", "rev_ctrl_maj");
snprintf(value, sizeof(value), "%d", hwdata.rev_ctrl_maj);
break;
case 2: // rev_ctrl_min
snprintf(name, sizeof(name), "%-20s", "rev_ctrl_min");
snprintf(value, sizeof(value), "%d", hwdata.rev_ctrl_min);
break;
case 3: // rev_exp_maj
snprintf(name, sizeof(name), "%-20s", "rev_exp_maj");
snprintf(value, sizeof(value), "%d", hwdata.rev_exp_maj);
break;
case 4: // rev_exp_min
snprintf(name, sizeof(name), "%-20s", "rev_exp_min");
snprintf(value, sizeof(value), "%d", hwdata.rev_exp_min);
break;
case 5: // rev_ft_maj
snprintf(name, sizeof(name), "%-20s", "rev_ft_maj");
snprintf(value, sizeof(value), "%d", hwdata.rev_ft_maj);
break;
case 6: // rev_ft_min
snprintf(name, sizeof(name), "%-20s", "rev_ft_min");
snprintf(value, sizeof(value), "%d", hwdata.rev_ft_min);
break;
case 7: // rev_fb_maj
snprintf(name, sizeof(name), "%-20s", "rev_fb_maj");
snprintf(value, sizeof(value), "%d", hwdata.rev_fb_maj);
break;
case 8: // rev_fb_min
snprintf(name, sizeof(name), "%-20s", "rev_fb_min");
snprintf(value, sizeof(value), "%d", hwdata.rev_fb_min);
break;
case 9: // sseg_color_t
snprintf(name, sizeof(name), "%-20s", "sseg_color_t");
snprintf(value, sizeof(value), "%s", SSEG_COLOR_NAMES[static_cast<uint8_t>(hwdata.sseg_color_t)]);
break;
case 10: // sseg_color_b
snprintf(name, sizeof(name), "%-20s", "sseg_color_b");
snprintf(value, sizeof(value), "%s", SSEG_COLOR_NAMES[static_cast<uint8_t>(hwdata.sseg_color_b)]);
break;
case 11: // lcd_color
snprintf(name, sizeof(name), "%-20s", "lcd_color");
snprintf(value, sizeof(value), "%s", LCD_COLOR_NAMES[static_cast<uint8_t>(hwdata.lcd_color)]);
break;
case 12: // switch_pos
snprintf(name, sizeof(name), "%-20s", "switch_pos");
snprintf(value, sizeof(value), "%d", hwdata.switch_pos);
break;
case 13: // button_type
snprintf(name, sizeof(name), "%-20s", "button_type");
snprintf(value, sizeof(value), "%s", BUTTON_TYPE_NAMES[static_cast<uint8_t>(hwdata.button_type)]);
break;
case 14: // tft_type
snprintf(name, sizeof(name), "%-20s", "tft_type");
snprintf(value, sizeof(value), "%s", TFT_TYPE_NAMES[static_cast<uint8_t>(hwdata.tft_type)]);
break;
case 15: // bat_type
snprintf(name, sizeof(name), "%-20s", "bat_type");
snprintf(value, sizeof(value), "%s", BAT_TYPE_NAMES[static_cast<uint8_t>(hwdata.bat_type)]);
break;
case 16: // bat_cap
snprintf(name, sizeof(name), "%-20s", "bat_cap");
snprintf(value, sizeof(value), "%d", hwdata.bat_cap);
break;
case 17: // shape1
snprintf(name, sizeof(name), "%-20s", "shape1");
snprintf(value, sizeof(value), "%s", SHAPE_TYPE_NAMES[static_cast<uint8_t>(hwdata.shape1)]);
break;
case 18: // shape2
snprintf(name, sizeof(name), "%-20s", "shape2");
snprintf(value, sizeof(value), "%s", SHAPE_TYPE_NAMES[static_cast<uint8_t>(hwdata.shape2)]);
break;
case 19: // shape3
snprintf(name, sizeof(name), "%-20s", "shape3");
snprintf(value, sizeof(value), "%s", SHAPE_TYPE_NAMES[static_cast<uint8_t>(hwdata.shape3)]);
break;
case 20: // shape4
snprintf(name, sizeof(name), "%-20s", "shape4");
snprintf(value, sizeof(value), "%s", SHAPE_TYPE_NAMES[static_cast<uint8_t>(hwdata.shape4)]);
break;
case 21: // has_speaker
snprintf(name, sizeof(name), "%-20s", "has_speaker");
snprintf(value, sizeof(value), "%s", hwdata.has_speaker ? "true" : "false");
break;
case 22: // has_mic
snprintf(name, sizeof(name), "%-20s", "has_mic");
snprintf(value, sizeof(value), "%s", hwdata.has_mic ? "true" : "false");
break;
case 23: // has_ir
snprintf(name, sizeof(name), "%-20s", "has_ir");
snprintf(value, sizeof(value), "%s", hwdata.has_ir ? "true" : "false");
break;
case 24: // has_rfid
snprintf(name, sizeof(name), "%-20s", "has_rfid");
snprintf(value, sizeof(value), "%s", hwdata.has_rfid ? "true" : "false");
break;
case 25: // has_fp
snprintf(name, sizeof(name), "%-20s", "has_fp");
snprintf(value, sizeof(value), "%s", hwdata.has_fp ? "true" : "false");
break;
case 26: // has_fp_hall
snprintf(name, sizeof(name), "%-20s", "has_fp_hall");
snprintf(value, sizeof(value), "%s", hwdata.has_fp_hall ? "true" : "false");
break;
case 27: // has_close_hall
snprintf(name, sizeof(name), "%-20s", "has_close_hall");
snprintf(value, sizeof(value), "%s", hwdata.has_close_hall ? "true" : "false");
break;
default:
break;
}
lcd_print(1, 0, name);
lcd_print(2, 0, value);
dirty = false;
}
if (get_button_pressed(&btn)) {
dirty = true;
switch (btn) {
case ButtonKey::b3: // dec
current_item = (current_item + n_items - 1) % n_items;
break;
case ButtonKey::b4: // inc
current_item = (current_item + 1) % n_items;
break;
default:
switch (current_item) {
case 9: // sseg_color_t
handle_enum(btn, reinterpret_cast<uint8_t&>(hwdata.sseg_color_t), SSEG_COLOR_COUNT);
break;
case 10: // sseg_color_b
handle_enum(btn, reinterpret_cast<uint8_t&>(hwdata.sseg_color_b), SSEG_COLOR_COUNT);
break;
case 11: // lcd_color
handle_enum(btn, reinterpret_cast<uint8_t&>(hwdata.lcd_color), LCD_COLOR_COUNT);
break;
case 13: // button_type
handle_enum(btn, reinterpret_cast<uint8_t&>(hwdata.button_type), BUTTON_TYPE_COUNT);
break;
case 14: // tft_type
handle_enum(btn, reinterpret_cast<uint8_t&>(hwdata.tft_type), TFT_TYPE_COUNT);
break;
case 15: // bat_type
handle_enum(btn, reinterpret_cast<uint8_t&>(hwdata.bat_type), BAT_TYPE_COUNT);
break;
case 17: // shape1
handle_enum(btn, reinterpret_cast<uint8_t&>(hwdata.shape1), SHAPE_TYPE_COUNT);
break;
case 18: // shape2
handle_enum(btn, reinterpret_cast<uint8_t&>(hwdata.shape2), SHAPE_TYPE_COUNT);
break;
case 19: // shape3
handle_enum(btn, reinterpret_cast<uint8_t&>(hwdata.shape3), SHAPE_TYPE_COUNT);
break;
case 20: // shape4
handle_enum(btn, reinterpret_cast<uint8_t&>(hwdata.shape4), SHAPE_TYPE_COUNT);
break;
case 21: // has_speaker
hwdata.has_speaker = btn == ButtonKey::button_green;
break;
case 22: // has_mic
hwdata.has_mic = btn == ButtonKey::button_green;
break;
case 23: // has_ir
hwdata.has_ir = btn == ButtonKey::button_green;
break;
case 24: // has_rfid
hwdata.has_rfid = btn == ButtonKey::button_green;
break;
case 25: // has_fp
hwdata.has_fp = btn == ButtonKey::button_green;
break;
case 26: // has_fp_hall
hwdata.has_fp_hall = btn == ButtonKey::button_green;
break;
case 27: // has_close_hall
hwdata.has_close_hall = btn == ButtonKey::button_green;
break;
default:
break;
}
break;
}
}
if (get_keypad_pressed(&key)) {
dirty = true;
if (key == KeypadKey::pound) {
// TODO: ask the user to save
return; // done
}
char key_c = char_of_keypad_key(key);
bool is_digit = std::isdigit(static_cast<unsigned char>(key_c));
uint8_t digit = is_digit ? static_cast<uint8_t>(key_c - '0') : 0;
// update the current value
switch (current_item) {
case 0: // serial_num
if (key == KeypadKey::star) {
hwdata.serial_num.clear();
} else {
hwdata.serial_num.push_back(char_of_keypad_key(key));
}
break;
case 1: // rev_ctrl_maj
handle_uint8(key, hwdata.rev_ctrl_maj);
break;
case 2: // rev_ctrl_min
handle_uint8(key, hwdata.rev_ctrl_min);
break;
case 3: // rev_exp_maj
handle_uint8(key, hwdata.rev_exp_maj);
break;
case 4: // rev_exp_min
handle_uint8(key, hwdata.rev_exp_min);
break;
case 5: // rev_ft_maj
handle_uint8(key, hwdata.rev_ft_maj);
break;
case 6: // rev_ft_min
handle_uint8(key, hwdata.rev_ft_min);
break;
case 7: // rev_fb_maj
handle_uint8(key, hwdata.rev_fb_maj);
break;
case 8: // rev_fb_min
handle_uint8(key, hwdata.rev_fb_min);
break;
case 12: // switch_pos
if (digit == 2 || digit == 3) hwdata.switch_pos = digit;
break;
case 16: // bat_cap
handle_uint16(key, hwdata.bat_cap);
break;
default:
break;
}
}
vTaskDelay(pdMS_TO_TICKS(10));
}
}
-199
View File
@@ -1,199 +0,0 @@
#ifndef HWDATA_H
#define HWDATA_H
#include <string>
#include <cstdint>
#include <cstring>
#include "esp_err.h"
#include "nvs_flash.h"
#define CURRENT_HWDATA_VERSION 1
#define CURRENT_HWDATA_STRUCT HWData1
#define SSEG_COLOR_COUNT 10
static constexpr const char* SSEG_COLOR_NAMES[SSEG_COLOR_COUNT] = {
"UNKNOWN",
"NONE",
"OTHER",
"RED",
"ORANGE",
"YELLOW",
"GREEN",
"BLUE",
"PURPLE",
"WHITE"
};
enum class SSegColor : uint8_t {
UNKNOWN = 0,
NONE = 1,
OTHER = 2,
RED = 3,
ORANGE = 4,
YELLOW = 5,
GREEN = 6,
BLUE = 7,
PURPLE = 8,
WHITE = 9,
};
#define LCD_COLOR_COUNT 8
static constexpr const char* LCD_COLOR_NAMES[LCD_COLOR_COUNT] = {
"UNKNOWN",
"NONE",
"OTHER",
"BLACK_GREEN",
"WHITE_BLUE",
"BLACK_SKY",
"BLACK_WHITE",
"WHITE_BLACK"
};
enum class LCDColor : uint8_t {
UNKNOWN = 0,
NONE = 1,
OTHER = 2,
BLACK_GREEN = 3,
WHITE_BLUE = 4,
BLACK_SKY = 5,
BLACK_WHITE = 6,
WHITE_BLACK = 7,
};
#define BUTTON_TYPE_COUNT 6
static constexpr const char* BUTTON_TYPE_NAMES[BUTTON_TYPE_COUNT] = {
"UNKNOWN",
"NONE",
"OTHER",
"WHITE",
"BROWN",
"RED"
};
enum class ButtonType : uint8_t {
UNKNOWN = 0,
NONE = 1,
OTHER = 2,
WHITE = 3,
BROWN = 4,
RED = 5,
};
#define TFT_TYPE_COUNT 5
static constexpr const char* TFT_TYPE_NAMES[TFT_TYPE_COUNT] = {
"UNKNOWN",
"NONE",
"OTHER",
"EAST_RISING",
"SHENZHEN"
};
enum class TFTType : uint8_t {
UNKNOWN = 0,
NONE = 1,
OTHER = 2,
EAST_RISING = 3,
SHENZHEN = 4,
};
#define BAT_TYPE_COUNT 5
static constexpr const char* BAT_TYPE_NAMES[BAT_TYPE_COUNT] = {
"UNKNOWN",
"NONE",
"OTHER",
"BAT_18650",
"LIPO"
};
enum class BatType : uint8_t {
UNKNOWN = 0,
NONE = 1,
OTHER = 2,
BAT_18650 = 3,
LIPO = 4,
};
#define SHAPE_TYPE_COUNT 11
static constexpr const char* SHAPE_TYPE_NAMES[SHAPE_TYPE_COUNT] = {
"UNKNOWN",
"OTHER",
"CIRCLE",
"SQUARE",
"TRIANGLE",
"X",
"STAR",
"SPADE",
"DIAMOND",
"CLUB",
"HEART"
};
enum class ShapeType : uint8_t {
UNKNOWN = 0,
OTHER = 1,
CIRCLE = 2,
SQUARE = 3,
TRIANGLE = 4,
X = 5,
STAR = 6,
SPADE = 7,
DIAMOND = 8,
CLUB = 9,
HEART = 10,
};
/// @brief Version 1 of HWData, kept constant for migrations
struct HWData1 {
std::string serial_num;
uint8_t rev_ctrl_maj;
uint8_t rev_ctrl_min;
uint8_t rev_exp_maj;
uint8_t rev_exp_min;
uint8_t rev_ft_maj;
uint8_t rev_ft_min;
uint8_t rev_fb_maj;
uint8_t rev_fb_min;
SSegColor sseg_color_t;
SSegColor sseg_color_b;
LCDColor lcd_color;
uint8_t switch_pos;
ButtonType button_type;
TFTType tft_type;
BatType bat_type;
uint16_t bat_cap;
ShapeType shape1;
ShapeType shape2;
ShapeType shape3;
ShapeType shape4;
bool has_speaker;
bool has_mic;
bool has_ir;
bool has_rfid;
bool has_fp;
bool has_fp_hall;
bool has_close_hall;
HWData1();
esp_err_t save(nvs_handle_t handle) const;
void load(nvs_handle_t handle);
// Add migration method as necessary
};
/// @brief The current version of HWData, to be stored
struct HWData {
/// @brief `true` if there is some issue in loading, and we are doing a "best effort" to be compatible
/// We should make no writes to NVS if this is `true`.
volatile bool compat_mode;
HWData1 inner;
HWData();
HWData(HWData1 data, bool compat_mode);
esp_err_t save(nvs_handle_t handle, bool force = false);
static HWData load(nvs_handle_t handle);
};
void hardware_config();
#endif /* HWDATA_H */
-35
View File
@@ -1,35 +0,0 @@
#include "i2c.h"
#include "esp_log.h"
#include "esp_err.h"
#include "driver/i2c.h"
static const char *TAG = "i2c";
SemaphoreHandle_t main_i2c_mutex;
void init_i2c() {
ESP_LOGI(TAG, "Initializing i2c...");
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = PIN_I2C_SDA,
.scl_io_num = PIN_I2C_SCL,
.sda_pullup_en = GPIO_PULLUP_DISABLE,
.scl_pullup_en = GPIO_PULLUP_DISABLE,
// .sda_pullup_en = GPIO_PULLUP_ENABLE,
// .scl_pullup_en = GPIO_PULLUP_ENABLE,
.master = {
// TODO: 400k?
.clk_speed = 100*1000,
},
.clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL
};
ESP_ERROR_CHECK(i2c_param_config(MAIN_I2C_BUS_NUM, &conf));
ESP_ERROR_CHECK(i2c_driver_install(MAIN_I2C_BUS_NUM, conf.mode, 0, 0, 0));
main_i2c_mutex = xSemaphoreCreateMutex();
assert(main_i2c_mutex != NULL);
ESP_LOGI(TAG, "i2c initialized!");
}
-26
View File
@@ -1,26 +0,0 @@
#ifndef I2C_H
#define I2C_H
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#define MAIN_I2C_BUS_NUM I2C_NUM_0
#define PIN_I2C_SDA GPIO_NUM_7
#define PIN_I2C_SCL GPIO_NUM_15
/// The mutex for accessing `I2C_NUM_0`.
extern SemaphoreHandle_t main_i2c_mutex;
/// @brief Initializes `I2C_NUM_0`.
///
/// This is hooked up the to:
/// - The bottom half
/// - The char lcd
/// - The power board
/// - The MPU6050
/// - The PERH port
/// - The Capacitive Touch Panel
void init_i2c();
#endif /* I2C_H */
+6 -17
View File
@@ -12,7 +12,6 @@
#include "esp_check.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "i2c.h"
#define TAG "I2C_LCD_PCF8574"
@@ -59,7 +58,6 @@ void lcd_begin(i2c_lcd_pcf8574_handle_t* lcd, uint8_t cols, uint8_t rows) {
lcd->entrymode = 0x02;
// The following are the reset sequence: Please see "Initialization instruction in the PCF8574 datasheet."
xSemaphoreTake(main_i2c_mutex, portMAX_DELAY);
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
// We left-shift the device addres and add the read/write command
@@ -97,7 +95,6 @@ void lcd_begin(i2c_lcd_pcf8574_handle_t* lcd, uint8_t cols, uint8_t rows) {
i2c_master_stop(cmd);
i2c_master_cmd_begin(lcd->i2c_port, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
xSemaphoreGive(main_i2c_mutex);
// Instruction: function set = 0x20
lcd_send(lcd, 0x20 | (rows > 1 ? 0x08 : 0x00), false);
@@ -113,7 +110,7 @@ void lcd_clear(i2c_lcd_pcf8574_handle_t* lcd) {
// Instruction: Clear display = 0x01
lcd_send(lcd, 0x01, false);
// Clearing the display takes a while: takes approx. 1.5ms
esp_rom_delay_us(2000);
esp_rom_delay_us(1600);
} // lcd_clear()
// Set the display to home
@@ -121,7 +118,7 @@ void lcd_home(i2c_lcd_pcf8574_handle_t* lcd) {
// Instruction: Return home = 0x02
lcd_send(lcd, 0x02, false);
// Same as clearing the display: takes approx. 1.5ms
esp_rom_delay_us(2000);
esp_rom_delay_us(1600);
} // lcd_home()
// Set the cursor to a new position.
@@ -233,7 +230,7 @@ void lcd_no_autoscroll(i2c_lcd_pcf8574_handle_t* lcd) {
// Setting the backlight: It can only be turn on or off.
// Current backlight value is saved in the i2c_lcd_pcf8574_handle_t struct for further data transfers
void lcd_set_backlight_to(i2c_lcd_pcf8574_handle_t* lcd, uint8_t brightness) {
void lcd_set_backlight(i2c_lcd_pcf8574_handle_t* lcd, uint8_t brightness) {
// Place the backlight value in the lcd struct
lcd->backlight = brightness;
// Send no data
@@ -241,7 +238,7 @@ void lcd_set_backlight_to(i2c_lcd_pcf8574_handle_t* lcd, uint8_t brightness) {
} // lcd_set_backlight()
// Custom character creation: allows us to create up to 8 custom characters in the CGRAM locations
void lcd_create_char(i2c_lcd_pcf8574_handle_t* lcd, uint8_t location, const uint8_t charmap[]) {
void lcd_create_char(i2c_lcd_pcf8574_handle_t* lcd, uint8_t location, uint8_t charmap[]) {
location &= 0x7; // Only 8 locations are available
// Set the CGRAM address
lcd_send(lcd, 0x40 | (location << 3), false);
@@ -258,12 +255,7 @@ void lcd_write(i2c_lcd_pcf8574_handle_t* lcd, uint8_t value) {
// Print characters to the LCD: cursor set or clear instruction must preceded this instruction, or it will write on the current text.
void lcd_print(i2c_lcd_pcf8574_handle_t* lcd, const char* str) {
while (*str) {
if (*str == '\x08') {
lcd_write(lcd, '\x00');
str++;
} else {
lcd_write(lcd, *str++);
}
lcd_write(lcd, *str++);
}
} // lcd_print()
@@ -301,16 +293,15 @@ void lcd_print_number(i2c_lcd_pcf8574_handle_t* lcd, uint8_t col, uint8_t row, u
// Private functions: derived from the esp32 i2c_master driver
static void lcd_send(i2c_lcd_pcf8574_handle_t* lcd, uint8_t value, bool is_data) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (lcd->i2c_addr << 1) | I2C_MASTER_WRITE, true);
xSemaphoreTake(main_i2c_mutex, portMAX_DELAY);
lcd_write_nibble(lcd, (value >> 4 & 0x0F), is_data, cmd);
lcd_write_nibble(lcd, (value & 0x0F), is_data, cmd);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(lcd->i2c_port, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
xSemaphoreGive(main_i2c_mutex);
i2c_cmd_link_delete(cmd);
if (ret != ESP_OK) {
@@ -355,9 +346,7 @@ static void lcd_write_i2c(i2c_lcd_pcf8574_handle_t* lcd, uint8_t data, bool is_d
i2c_master_write_byte(cmd, (lcd->i2c_addr << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, data, true);
i2c_master_stop(cmd);
xSemaphoreTake(main_i2c_mutex, portMAX_DELAY);
esp_err_t ret = i2c_master_cmd_begin(lcd->i2c_port, cmd, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
xSemaphoreGive(main_i2c_mutex);
i2c_cmd_link_delete(cmd);
if (ret != ESP_OK) {
+2 -2
View File
@@ -91,10 +91,10 @@ void lcd_autoscroll(i2c_lcd_pcf8574_handle_t* lcd);
void lcd_no_autoscroll(i2c_lcd_pcf8574_handle_t* lcd);
// Set backlight brightness
void lcd_set_backlight_to(i2c_lcd_pcf8574_handle_t* lcd, uint8_t brightness);
void lcd_set_backlight(i2c_lcd_pcf8574_handle_t* lcd, uint8_t brightness);
// Create a custom character
void lcd_create_char(i2c_lcd_pcf8574_handle_t* lcd, uint8_t location, const uint8_t charmap[]);
void lcd_create_char(i2c_lcd_pcf8574_handle_t* lcd, uint8_t location, uint8_t charmap[]);
// Write a character to the LCD
void lcd_write(i2c_lcd_pcf8574_handle_t* lcd, uint8_t value);
+2 -40
View File
@@ -1,33 +1,11 @@
#include "leds.h"
#include "led_strip.h"
#include <esp_log.h>
#include "state_tracking.h"
#include <cstring>
static const char* TAG = "leds";
static led_strip_handle_t leds;
// TODO: rename these to playback_handler
static bool replay_handler(const char* event, char* arg) {
if (strcmp(event, "LED_SET") == 0) {
uint32_t led = atoi(strtok(arg, ","));
uint32_t color = atoi(strtok(NULL, ","));
led_set(led, color);
return true;
}
if (strcmp(event, "LED_FLUSH") == 0) {
leds_flush();
return true;
}
if (strcmp(event, "LED_CLR") == 0) {
leds_clear();
return true;
}
return false;
}
void init_leds() {
ESP_LOGI(TAG, "Initializing LEDs...");
@@ -46,20 +24,11 @@ void init_leds() {
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &leds));
register_replay_fn(replay_handler);
ESP_LOGI(TAG, "LEDs initialized!");
}
void led_set(uint32_t led, uint8_t r, uint8_t g, uint8_t b) {
led_strip_set_pixel(leds, led, r, g, b);
if (is_state_tracking()) {
char buf[32];
uint32_t color = (r << 16) | (g << 8) | b;
sprintf(buf, "%ld,%ld", led, color);
event_occured("LED_SET", buf);
}
}
void led_set(uint32_t led, uint32_t color) {
@@ -68,16 +37,9 @@ void led_set(uint32_t led, uint32_t color) {
void leds_flush() {
led_strip_refresh(leds);
if (is_state_tracking()) {
event_occured("LED_FLUSH", NULL);
}
}
void leds_clear() {
void leds_clear()
{
led_strip_clear(leds);
if (is_state_tracking()) {
event_occured("LED_CLR", NULL);
}
}
+1 -2
View File
@@ -4,7 +4,7 @@
#include <stdint.h>
#define LED_COUNT 21
#define NEOPIXEL_PIN GPIO_NUM_0
#define NEOPIXEL_PIN GPIO_NUM_7
// 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution)
#define LED_STRIP_RMT_RES_HZ (10 * 1000 * 1000)
@@ -26,7 +26,6 @@ enum LEDColor: uint32_t {
LED_COLOR_WHITE_STRONG = 0xFF'FF'FF,
};
// TODO: sepperate the indicator leds from the shape display.
enum IndicatorLED {
LED_SHAPE1 = 0u,
LED_SHAPE2 = 1u,
-63
View File
@@ -1,63 +0,0 @@
#include "nvs.h"
#include "esp_log.h"
#include "bottom_half.h"
#include "char_lcd.h"
static const char* TAG = "nvs";
static const char* HWDATA_NAMESPACE = "hwdata";
static HWData hw_data;
bool init_nvs() {
ESP_LOGI(TAG, "Initializing NVS...");
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// NVS partition was truncated, erase and retry
ESP_LOGE(TAG, "Failed to init nvs flash: %s.", esp_err_to_name(ret));
lcd_print(1, 0, "NVS: ");
lcd_print(1, 4, esp_err_to_name(ret));
lcd_print(2, 0, "Press Yellow to skip");
lcd_print(3, 0, "Press Red to erase");
ButtonKey button;
while (!( get_button_pressed(&button) && (button == ButtonKey::button_red || button == ButtonKey::button_yellow) )) vTaskDelay(pdMS_TO_TICKS(10));
lcd_clear();
if (button == ButtonKey::button_yellow) {
return false;
}
if (button == ButtonKey::button_red) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
}
ESP_ERROR_CHECK(ret);
nvs_handle_t hw_handle;
ret = nvs_open(HWDATA_NAMESPACE, NVS_READONLY, &hw_handle);
if (ret == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGW(TAG, "Partition \"%s\" has not been initialized. Loading defaults.", HWDATA_NAMESPACE);
hw_data = HWData();
} else {
ESP_ERROR_CHECK(ret);
hw_data = HWData::load(hw_handle);
nvs_close(hw_handle);
}
ESP_LOGI(TAG, "NVS initialized!");
return true;
}
HWData& get_hw_data() {
return hw_data;
}
void save_hw_data(bool force) {
nvs_handle_t hw_handle;
ESP_ERROR_CHECK(nvs_open(HWDATA_NAMESPACE, NVS_READWRITE, &hw_handle));
hw_data.save(hw_handle);
nvs_close(hw_handle);
}
-13
View File
@@ -1,13 +0,0 @@
#ifndef NVS_H
#define NVS_H
#include "nvs_flash.h"
#include "hwdata.h"
/// @brief Initializes the NVS.
bool init_nvs();
/// Gets the HWData stored in NVS.
HWData& get_hw_data();
#endif /* NVS_H */
-2
View File
@@ -1,2 +0,0 @@
#include "perh.h"
-12
View File
@@ -1,12 +0,0 @@
#ifndef PERH_H
#define PERH_H
#include "driver/gpio.h"
#define PIN_PERH0 GPIO_NUM_6
#define PIN_PERH1 GPIO_NUM_5
#define PIN_PERH2 GPIO_NUM_4
#define PIN_PERH3 GPIO_NUM_2
#define PIN_PERH4 GPIO_NUM_1
#endif /* PERH_H */
+4 -51
View File
@@ -1,6 +1,5 @@
#include "power.h"
#include "char_lcd.h"
#include "starcode.h"
#include <esp_log.h>
static const char* TAG = "power";
@@ -12,9 +11,9 @@ void bat_monitor_task(void* arg) {
sprintf(str_buf, "%d.%03dV", voltage / 1000, voltage % 1000);
lcd_clear();
lcd_print(0, 1, str_buf);
lcd_print(1, 0, str_buf);
int16_t current = lipo.current();
int16_t current = lipo.current(current_measure::AVG);
sprintf(str_buf, "%dmA", current);
lcd_print(1, 1, str_buf);
@@ -23,12 +22,12 @@ void bat_monitor_task(void* arg) {
int16_t total_cap = lipo.capacity(capacity_measure::FULL);
sprintf(str_buf, "%dmAh", total_cap);
lcd_print(2, 1, str_buf);
lcd_print(1, 2, str_buf);
int16_t soc = lipo.soc(soc_measure::FILTERED);
sprintf(str_buf, "%d%%", soc);
lcd_print(3, 1, str_buf);
lcd_print(1, 3, str_buf);
vTaskDelay(pdMS_TO_TICKS(250));
@@ -51,50 +50,4 @@ void init_power_board() {
ESP_LOGI(TAG, "Power board initialized!");
}
uint16_t get_bat_voltage() {
return lipo.voltage();
}
void lcd_print_header_bat() {
if (!lcd_header_enabled()) return;
if (lcd_starcode_displaying_result()) return;
uint8_t soc = lipo.soc();
int16_t current = lipo.current();
char buf[6];
if (soc < 5 && current <= 0) {
snprintf(buf, sizeof(buf), " LOW");
} else if (soc == 100) {
snprintf(buf, sizeof(buf), " 100");
} else {
if (current > 0) {
snprintf(buf, sizeof(buf), " %2d+", soc);
} else {
snprintf(buf, sizeof(buf), " %2d%%", soc);
}
}
lcd_print(0, 16, buf);
}
// memory version
// void lcd_print_header_bat() {
// if (!lcd_header_enabled()) return;
// if (lcd_starcode_displaying_result()) return;
// // Show memory usage percentage instead of battery percentage
// char buf[6];
// size_t free_heap = heap_caps_get_free_size(MALLOC_CAP_DEFAULT);
// size_t total_heap = heap_caps_get_total_size(MALLOC_CAP_DEFAULT);
// uint8_t mem_percent = 0;
// if (total_heap > 0) {
// mem_percent = (uint8_t)(100 - ((free_heap * 100) / total_heap));
// }
// if (mem_percent >= 100) {
// snprintf(buf, sizeof(buf), " 100");
// } else {
// snprintf(buf, sizeof(buf), " %2d%%", mem_percent);
// }
// lcd_print(0, 16, buf);
// }
+1 -6
View File
@@ -3,18 +3,13 @@
#include "SparkFunBQ27441/SparkFunBQ27441.h"
extern volatile uint32_t battery_charge;
void bat_monitor_task(void* arg);
/// Initializes the battery gas guage for getting battery stats.
void init_power_board();
/// @brief Gets the battery voltage.
/// @brief Gets the battery voltage
/// @return battery voltage in mV.
uint16_t get_bat_voltage();
/// @brief Prints the battery section of the header to the char_lcd. (row 0, columns 17-19)
void lcd_print_header_bat();
#endif /* POWER_H */
+4 -4
View File
@@ -51,10 +51,10 @@ bool init_sd() {
ESP_LOGE(TAG, "Failed to mount sd card: %s.", esp_err_to_name(ret));
lcd_print(0, 0, "SD: ");
lcd_print(0, 4, esp_err_to_name(ret));
lcd_print(1, 0, "Press Green to retry");
lcd_print(2, 0, "Press Yellow to skip");
lcd_print(3, 0, "Press Red to format");
lcd_print(4, 0, esp_err_to_name(ret));
lcd_print(0, 1, "Press Green to retry");
lcd_print(0, 2, "Press Yellow to skip");
lcd_print(0, 3, "Press Red to format");
ButtonKey button;
while (!( get_button_pressed(&button) && (button == ButtonKey::button_green || button == ButtonKey::button_red || button == ButtonKey::button_yellow) )) vTaskDelay(pdMS_TO_TICKS(10));
+6 -6
View File
@@ -12,12 +12,12 @@
extern sdmmc_card_t *card;
#define SD_PIN_CLK GPIO_NUM_39
#define SD_PIN_CMD GPIO_NUM_40
#define SD_PIN_D0 GPIO_NUM_38
#define SD_PIN_D1 GPIO_NUM_45
#define SD_PIN_D2 GPIO_NUM_42
#define SD_PIN_D3 GPIO_NUM_41
#define SD_PIN_CLK GPIO_NUM_48
#define SD_PIN_CMD GPIO_NUM_45
#define SD_PIN_D0 GPIO_NUM_47
#define SD_PIN_D1 GPIO_NUM_21
#define SD_PIN_D2 GPIO_NUM_39
#define SD_PIN_D3 GPIO_NUM_38
/// @brief Initializes the SD card
///
+3 -37
View File
@@ -1,5 +1,4 @@
#include "speaker.h"
#include "state_tracking.h"
static const char *TAG = "speaker";
@@ -30,27 +29,6 @@ QueueHandle_t play_clip_queue;
/// The clips that are currently playing
std::vector<playing_audio_clip_t> playing_clips;
static bool replay_handler(const char* event, char* arg) {
if (strcmp(event, "PLAY_WAV") == 0) {
char* file_name = strtok(arg, ":");
char* play_immediately_str = strtok(NULL, ":");
char* repeat_str = strtok(NULL, ":");
char* prescaler_str = strtok(NULL, ":");
bool play_immediately = strcmp(play_immediately_str, "true") == 0;
bool repeat = strcmp(repeat_str, "true") == 0;
uint8_t prescaler = atoi(prescaler_str);
play_clip_wav(file_name, play_immediately, repeat, prescaler, 0);
return true;
}
if (strcmp(event, "STOP_WAV") == 0) {
stop_clip(arg, 0);
return true;
}
return false;
}
static bool push_clip(audio_clip_t clip) {
ESP_LOGD(TAG, "playing %s", clip.file_name);
FILE* fh = fopen(clip.file_name, "rb");
@@ -178,7 +156,7 @@ static void speaker_task(void* arg) {
vTaskDelete(NULL);
}
bool play_clip_wav(const char* file_name, bool play_immediately, bool repeat, uint8_t prescaler, TickType_t ticks_to_wait) {
bool play_clip_wav(const char* file_name, bool play_immediatly, bool repeat, uint8_t prescaler, TickType_t ticks_to_wait) {
// clone the passed in string to the heap.
size_t len = strlen(file_name);
char* dynamic_file_name = (char*) malloc(len+1);
@@ -188,16 +166,10 @@ bool play_clip_wav(const char* file_name, bool play_immediately, bool repeat, ui
.file_name = dynamic_file_name,
.prescaler = prescaler,
.repeat = repeat,
.play_immediatly = play_immediately,
.play_immediatly = play_immediatly,
};
if (is_state_tracking()) {
char buf[64];
sprintf(buf, "%s:%d:%d:%d", file_name, play_immediately, repeat, prescaler);
event_occured("PLAY_WAV", buf);
}
if (play_immediately) {
if (play_immediatly) {
return xQueueSendToFront(play_clip_queue, &clip, ticks_to_wait) == pdTRUE;
}
return xQueueSend(play_clip_queue, &clip, ticks_to_wait) == pdTRUE;
@@ -209,10 +181,6 @@ bool stop_clip(const char* file_name, TickType_t ticks_to_wait) {
char* dynamic_file_name = (char*) malloc(len+1);
strcpy(dynamic_file_name, file_name);
if (is_state_tracking()) {
event_occured("STOP_WAV", file_name);
}
return xQueueSend(stop_clip_queue, &dynamic_file_name, ticks_to_wait) == pdTRUE;
}
@@ -255,7 +223,5 @@ void init_speaker(void) {
play_clip_wav(MOUNT_POINT "/startup.wav", true, false, 4, 0);
register_replay_fn(replay_handler);
ESP_LOGI(TAG, "Speaker initialized!");
}
+3 -3
View File
@@ -15,8 +15,8 @@
#include "sdkconfig.h"
#include "sd.h"
#define SPEAKER_PIN_BCLK GPIO_NUM_11
#define SPEAKER_PIN_WS GPIO_NUM_12
#define SPEAKER_PIN_BCLK GPIO_NUM_46
#define SPEAKER_PIN_WS GPIO_NUM_9
#define SPEAKER_PIN_DOUT GPIO_NUM_3
#define SAMPLE_RATE 44100
// The maximum number of clips that can be queued at one time.
@@ -52,7 +52,7 @@ void init_speaker();
/// loud. Useful for loud audio files.
/// @param ticks_to_wait The number of ticks to wait if the queue is full.
/// @return true if the clip was added to the queue.
bool play_clip_wav(const char* file_name, bool play_immediately, bool repeat, uint8_t prescaler, TickType_t ticks_to_wait);
bool play_clip_wav(const char* file_name, bool play_immediatly, bool repeat, uint8_t prescaler, TickType_t ticks_to_wait);
/// @brief Stops an audio clip from playing.
/// @param file_name The file name of the audio clip that was played.
+1 -82
View File
@@ -1,62 +1,15 @@
#include "sseg.h"
#include <esp_log.h>
#include "state_tracking.h"
#include <cstring>
#include "esp_log.h"
TM1640* sseg = nullptr;
static const char *TAG = "sseg";
static bool replay_handler(const char* event, char* arg) {
if (strcmp(event, "SSEG_G_RAW") == 0) {
uint8_t segments[4];
segments[0] = atoi(strtok(arg, ","));
for (int i = 1; i < 4; i++) {
segments[i] = atoi(strtok(NULL, ","));
}
set_game_sseg_raw(segments);
return true;
}
if (strcmp(event, "SSEG_G_CLR") == 0) {
clear_game_sseg();
return true;
}
if (strcmp(event, "SSEG_M_RAW") == 0) {
uint8_t segments[4];
segments[0] = atoi(strtok(arg, ","));
for (int i = 1; i < 4; i++) {
segments[i] = atoi(strtok(NULL, ","));
}
set_module_sseg_raw(segments);
return true;
}
if (strcmp(event, "SSEG_M_CLR") == 0) {
clear_module_sseg();
return true;
}
if (strcmp(event, "SSEG_G") == 0) {
uint32_t value = atoi(strtok(arg, ","));
uint8_t dot_pos = atoi(strtok(NULL, ","));
set_game_sseg_num(value, dot_pos);
return true;
}
if (strcmp(event, "SSEG_M") == 0) {
uint32_t value = atoi(strtok(arg, ","));
uint8_t dot_pos = atoi(strtok(NULL, ","));
set_module_sseg_num(value, dot_pos);
return true;
}
return false;
}
void init_sseg() {
ESP_LOGI(TAG, "Initializing sseg...");
sseg = new TM1640(SSEG_PIN_DATA, SSEG_PIN_CLK, 8);
register_replay_fn(replay_handler);
ESP_LOGI(TAG, "Sseg initialized!");
}
@@ -65,22 +18,12 @@ void set_game_sseg_raw(const uint8_t* segments) {
sseg->setSegments(segments[1], 1);
sseg->setSegments(segments[2], 2);
sseg->setSegments(segments[3], 3);
if (is_state_tracking()) {
char buf[32];
sprintf(buf, "%d,%d,%d,%d", segments[0], segments[1], segments[2], segments[3]);
event_occured("SSEG_G_RAW", buf);
}
}
void clear_game_sseg() {
sseg->setSegments(0, 0);
sseg->setSegments(0, 1);
sseg->setSegments(0, 2);
sseg->setSegments(0, 3);
if (is_state_tracking()) {
event_occured("SSEG_G_CLR", NULL);
}
}
void set_module_sseg_raw(const uint8_t* segments) {
@@ -88,12 +31,6 @@ void set_module_sseg_raw(const uint8_t* segments) {
sseg->setSegments(segments[1], 5);
sseg->setSegments(segments[2], 6);
sseg->setSegments(segments[3], 7);
if (is_state_tracking()) {
char buf[32];
sprintf(buf, "%d,%d,%d,%d", segments[0], segments[1], segments[2], segments[3]);
event_occured("SSEG_M_RAW", buf);
}
}
void clear_module_sseg() {
@@ -101,38 +38,20 @@ void clear_module_sseg() {
sseg->setSegments(0, 5);
sseg->setSegments(0, 6);
sseg->setSegments(0, 7);
if (is_state_tracking()) {
event_occured("SSEG_M_CLR", NULL);
}
}
void set_game_sseg_num(uint32_t value, uint8_t dot_pos) {
uint32_t initial_value = value;
for (int i = 0; i < 4; i++) {
auto idx = value % 10;
sseg->sendChar(3-i, TM16XX_NUMBER_FONT[idx], i == dot_pos);
value = value / 10;
}
if (is_state_tracking()) {
char buf[16];
sprintf(buf, "%ld,%d", initial_value, dot_pos);
event_occured("SSEG_G", buf);
}
}
void set_module_sseg_num(uint32_t value, uint8_t dot_pos) {
uint32_t initial_value = value;
for (int i = 0; i < 4; i++) {
auto idx = value % 10;
sseg->sendChar(7-i, TM16XX_NUMBER_FONT[idx], i == dot_pos);
value = value / 10;
}
if (is_state_tracking()) {
char buf[16];
sprintf(buf, "%ld,%d", initial_value, dot_pos);
event_occured("SSEG_M", buf);
}
}
+2 -2
View File
@@ -4,8 +4,8 @@
#include "TM1640/TM1640.h"
#include <esp_log.h>
#define SSEG_PIN_DATA GPIO_NUM_46
#define SSEG_PIN_CLK GPIO_NUM_48
#define SSEG_PIN_DATA GPIO_NUM_10
#define SSEG_PIN_CLK GPIO_NUM_11
extern TM1640* sseg;
-275
View File
@@ -1,275 +0,0 @@
#include "starcode.h"
#include <vector>
#include <algorithm>
#include <string.h>
#include <stdint.h>
#include <esp_log.h>
#include "drivers/bottom_half.h"
#include "char_lcd.h"
#include "esp_timer.h"
#include "freertos/task.h"
static const char* TAG = "star_code";
volatile bool handling_new_starcodes = false;
static volatile bool system_initialized = false;
// TODO: use the semaphore, convert to RWLock?
static volatile SemaphoreHandle_t star_codes_mutex;
static std::vector<StarCodeEntry> star_codes;
static const char EMPTY_STAR_CODE_HEADER[] = " ";
esp_timer_handle_t starcode_delay_timer;
/// @brief `true` if we are delaying for a starcode
static volatile bool delaying_for_starcode;
static volatile StarCodeEntry* current_starcode = nullptr;
/// @brief `true` when we are handling user input for a starcode
static volatile bool doing_starcode = false;
static uint16_t starcode_waiting_on_release;
static char current[STARCODE_MAX_LEN + 1];
static size_t current_idx;
// Task handle for the starcode callback task
static TaskHandle_t starcode_callback_task_handle = nullptr;
static void starcode_callback_task(void* arg) {
(void) arg;
while (true) {
// Wait for notification from starcode_trigger_cb
uint32_t notification_value;
if (xTaskNotifyWait(0, ULONG_MAX, &notification_value, portMAX_DELAY) == pdTRUE) {
// Process the starcode callback
delaying_for_starcode = false;
lcd_print_header();
if (current_starcode != nullptr) {
if (current_starcode->triggered_sem != nullptr)
xSemaphoreGive(current_starcode->triggered_sem);
if (current_starcode->callback != nullptr)
(current_starcode->callback)();
current_starcode = nullptr;
}
}
}
}
static void starcode_trigger_cb(void* arg) {
(void) arg;
if (starcode_callback_task_handle != nullptr) {
xTaskNotify(starcode_callback_task_handle, 1, eSetBits);
}
}
// TODO: rename star code everywhere to starcode
void star_code_handle_keypad(uint16_t* just_pressed, uint16_t* just_released) {
if ((!delaying_for_starcode) && handling_new_starcodes && (*just_pressed & (1 << KeypadKey::star))) {
current_idx = 0;
current[current_idx] = '\0';
doing_starcode = true;
}
if (doing_starcode) {
// If we get a press while handling a starcode, we also want to capture the release of that key.
starcode_waiting_on_release |= *just_pressed;
KeypadKey key;
while (take_key(&key, just_pressed)) {
if (key == KeypadKey::star) {
current_idx = 0;
current[current_idx] = '\0';
} else if (key == KeypadKey::pound) {
doing_starcode = false;
if (current_idx != 0) {
trigger_star_code(current);
}
} else {
// shift the digits left if neccesary
if (current_idx >= STARCODE_MAX_LEN) {
for (int i = 1; i < current_idx; i++) {
current[i-1] = current[i];
}
current_idx--;
}
// append the character
current[current_idx++] = char_of_keypad_key(key);
current[current_idx] = '\0';
}
lcd_print_header_star_code();
}
}
// capture any releases from starcodes
uint16_t new_just_released = (*just_released) & (~starcode_waiting_on_release);
starcode_waiting_on_release = starcode_waiting_on_release & (~*just_released);
*just_released = new_just_released;
}
void init_star_code_system() {
star_codes_mutex = xSemaphoreCreateMutex();
xTaskCreate(starcode_callback_task, "starcode_cb", 4096, NULL, 3, &starcode_callback_task_handle);
const esp_timer_create_args_t timer_args = {
.callback = &starcode_trigger_cb,
.arg = nullptr,
.dispatch_method = ESP_TIMER_TASK,
.name = "starcode_trigger",
.skip_unhandled_events = false,
};
ESP_ERROR_CHECK(esp_timer_create(&timer_args, &starcode_delay_timer));
handling_new_starcodes = true;
system_initialized = true;
}
/// Checks if a triggered code matches an expected code.
/// @return true iff the codes match, where '*'s in the expected code can match any character in the triggered code
static bool check_code_match(const char* triggered, const char* expected) {
size_t triggered_len = strlen(triggered);
size_t match_len = strlen(triggered);
if (triggered_len != match_len)
return false;
for (int i = 0; i < triggered_len; i++) {
if (!(expected[i] == '*' || expected[i] == triggered[i])) {
return false;
}
}
return true;
}
bool add_star_code(StarCodeEntry code) {
ESP_LOGI(TAG, "Adding starcode: %s", code.code);
if (code.code == nullptr || strlen(code.code) > STARCODE_MAX_LEN) {
ESP_LOGW(TAG, "invalid code");
return false;
}
if (code.display_text != nullptr && strlen(code.display_text) > STARCODE_DISPLAY_TEXT_MAX_LEN) {
ESP_LOGW(TAG, "invalid display_text");
return false;
}
// check for a existing entry
auto it = std::find_if(star_codes.begin(), star_codes.end(), [&](const StarCodeEntry& other) {
return check_code_match(code.code, other.code);
});
if (it != star_codes.end()) {
// existing star code found!
ESP_LOGW(TAG, "Duplicate starcode %s", code.code);
return false;
}
star_codes.push_back(code);
return true;
}
bool add_star_codes(const StarCodeEntry* codes, size_t len) {
bool success = true;
for (int i = 0; i < len; i++) {
if (!add_star_code(codes[i])) {
success = false;
}
}
return success;
}
bool rm_star_code(const char* code) {
ESP_LOGI(TAG, "Removing starcode: %s", code);
auto it = std::find_if(star_codes.begin(), star_codes.end(), [&](const StarCodeEntry& star_code) {
return strcmp(code, star_code.code) == 0;
});
if (it == star_codes.end()) {
ESP_LOGW(TAG, "Failed to remove star code %s", code);
return false;
}
star_codes.erase(it);
return true;
}
bool rm_star_codes(const StarCodeEntry* codes, size_t len) {
bool success = true;
for (int i = 0; i < len; i++) {
if (!rm_star_code(codes[i].code)) {
success = false;
}
}
return success;
}
bool rm_star_codes_str(const char** codes, size_t len) {
bool success = true;
for (int i = 0; i < len; i++) {
if (!rm_star_code(codes[i])) {
success = false;
}
}
return success;
}
void clear_star_codes() {
star_codes.clear();
}
bool trigger_star_code(const char* code) {
auto it = std::find_if(star_codes.begin(), star_codes.end(), [&](const StarCodeEntry& other) {
return check_code_match(code, other.code);
});
uint64_t delay_us = 2'000'000;
delaying_for_starcode = true;
if (it != star_codes.end()) {
current_starcode = &*it;
delay_us = current_starcode->delay_us;
}
ESP_ERROR_CHECK(esp_timer_start_once(starcode_delay_timer, delay_us));
return current_starcode != nullptr;
}
void pause_star_code_system() {
doing_starcode = false;
handling_new_starcodes = false;
}
void resume_star_code_system() {
handling_new_starcodes = system_initialized;
}
void lcd_print_header_star_code() {
if (!lcd_header_enabled()) return;
// TODO: consider upping the display text size to be able to overwrite the game_state area.
if (delaying_for_starcode) {
if (current_starcode == nullptr) {
lcd_print(0, 0, "Invalid starcode ");
} else if (current_starcode->display_text != nullptr) {
char buf[21];
snprintf(buf, sizeof(buf), "%-20s", current_starcode->display_text);
lcd_print(0, 0, buf);
} else {
lcd_print(0, 0, EMPTY_STAR_CODE_HEADER);
}
} else if (doing_starcode) {
char buf[STARCODE_MAX_LEN + 2];
snprintf(buf, sizeof(buf), "*%-9s", current);
lcd_print(0, 0, buf);
} else {
lcd_print(0, 0, EMPTY_STAR_CODE_HEADER);
}
}
bool lcd_starcode_displaying_result() {
return delaying_for_starcode;
}
-90
View File
@@ -1,90 +0,0 @@
#ifndef STAR_CODE_H
#define STAR_CODE_H
#include <stddef.h>
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
/// The max length of a starcode (not counting the star)
#define STARCODE_MAX_LEN 9
#define STARCODE_DISPLAY_TEXT_MAX_LEN 20
/// @brief A handler for a specific star code
struct StarCodeEntry {
/// @brief The star code without the star
///
/// This must be <= 9 characters.
///
/// You may include a * in the code to match on any character
const char* code;
/// @brief The text to display when the star code is entered (or null).
///
/// This must be <= 20 characters.
const char* display_text;
/// @brief The number of microseconds to delay when the star code is entered before calling the handler.
uint64_t delay_us;
/// @brief The function to call when the star code is entered.
/// Can be null.
void (*callback)(void);
/// @brief The binary semaphore that will be given when this star code is triggered.
/// Can be null.
SemaphoreHandle_t triggered_sem;
};
/// @brief Initializes the star code system.
void init_star_code_system();
/// @brief Handles any keypad presses and releases before they bubble up to the rest of the BLK_BOX.
void star_code_handle_keypad(uint16_t* just_pressed, uint16_t* just_released);
/// @brief Adds a star code to be handled.
/// @param code the star code to add
/// @return true iff the star code was added
bool add_star_code(StarCodeEntry code);
/// @brief Adds a list of star codes to be handled.
/// @param codes the list of star codes to add
/// @param len the length of the list
/// @return true iff all the star codes were added
bool add_star_codes(const StarCodeEntry* codes, size_t len);
/// @brief removes a star code to stop handling it.
/// @param code the star code to remove
/// @return true iff the star code was removed
bool rm_star_code(const char* code);
/// @brief removes all given star codes to stop handling them.
/// @param codes the list of star codes to remove
/// @param len the length of the list
/// @return true iff all star codes were removed
bool rm_star_codes(const StarCodeEntry* codes, size_t len);
/// @brief removes all given star codes to stop handling them.
/// @param codes the list of star codes to remove
/// @param len the length of the list
/// @return true iff all star codes were removed
bool rm_star_codes_str(const char** codes, size_t len);
/// @brief clears all star codes.
void clear_star_codes();
/// @brief Triggers the given star code.
/// @param code the star code to trigger (without the *)
/// @return true iff a star code was triggered
bool trigger_star_code(const char* code);
/// @brief Starts/stops the star code system from handling new star codes.
/// If one is being handled currently, it is canceled.
void set_star_code_sys_enabled(bool enable);
/// @return `true` iff the star code system is handling star codes.
bool star_code_sys_enabled();
/// @brief Prints the star code section of the header to the char_lcd. (row 0, columns 0-9)
void lcd_print_header_star_code();
/// @return `true` iff the starcode system is using the full header.
bool lcd_starcode_displaying_result();
#endif /* STAR_CODE_H */
-225
View File
@@ -1,225 +0,0 @@
#include "state_tracking.h"
#include <unistd.h>
#include <vector>
#include "wlvgl.h"
static const char* PLAYBACK_TAG = "playback";
enum state_t {
STATE_IDLE = 0,
STATE_RECORDING = 1,
STATE_PLAYBACK = 2,
};
static std::vector<bool(*)(const char*, char*)> replay_fns;
static bool should_close_recording_stream;
static FILE* recording_stream;
static uint32_t recording_start_time;
TaskHandle_t flush_file_task_handle;
static bool should_close_playback_stream;
static FILE* playback_stream;
static uint32_t playback_start_time;
TaskHandle_t playback_task_handle;
static volatile state_t state = STATE_IDLE;
/// @brief Periodically flushes and syncs (if neccesary) the output stream.
/// @param arg unused.
static void flush_file_task(void* arg) {
while (state == STATE_RECORDING && recording_stream != nullptr) {
fflush(recording_stream);
int fd = fileno(recording_stream);
if (fd != -1) {
fsync(fd);
}
vTaskDelay(pdMS_TO_TICKS(5000));
}
flush_file_task_handle = NULL;
vTaskDelete(NULL);
}
static void playback_task(void* arg) {
const size_t size = 16*1024;
char* buf = (char*) malloc(size*sizeof(char));
if (buf == nullptr) {
ESP_LOGE(PLAYBACK_TAG, "buf alloc failure");
vTaskDelete(NULL);
}
while (state == STATE_PLAYBACK && playback_stream != nullptr) {
char* ret = fgets(buf, size, playback_stream);
if (ret == nullptr) {
break;
}
if (buf[0] == '\0') {
ESP_LOGI(PLAYBACK_TAG, "playback done");
break;
}
// get rid of the '\n' and possibly '\r' in the string
for (int i = 0; i < size; i++) {
if (buf[i] == '\0') break;
if (buf[i] == '\r' || buf[i] == '\n') {
buf[i] = '\0';
break;
}
}
ESP_LOGI(PLAYBACK_TAG, "handling: %s", buf);
// look for a comma, indicating the end of the "ticks" part
// TODO: replace with strtok
size_t comma_pos = 0;
for (int i = 0; i < 11; i++) {
if (buf[i] == ',') {
comma_pos = i;
break;
}
}
if (comma_pos == 0) {
ESP_LOGE(PLAYBACK_TAG, "Failed to find comma in playback line");
continue;
}
buf[comma_pos] = '\0';
uint32_t tick = atoi(buf);
// now look for the colon to indicate the end of the event name
size_t colon_pos = 0;
int i = comma_pos + 1; // start looking right after the comma
while (i < size) {
if (buf[i] == ':') {
colon_pos = i;
break;
}
i++;
}
if (colon_pos == 0) {
ESP_LOGE(PLAYBACK_TAG, "Failed to find colon in playback line");
continue;
}
buf[colon_pos] = '\0';
char* event_name = buf + (comma_pos + 1);
char* arg = buf + (colon_pos + 1);
int32_t ticks_to_wait = ((int32_t) tick) - (int32_t)(xTaskGetTickCount() - playback_start_time);
if (ticks_to_wait < 0) {
ESP_LOGW(PLAYBACK_TAG, "Playback is behind by %ld ticks!", ticks_to_wait);
}
if (ticks_to_wait > 0) {
vTaskDelay(ticks_to_wait);
}
bool matched = false;
for (const auto& fn : replay_fns) {
matched = (fn)(event_name, arg);
if (matched) break;
}
if (!matched) {
ESP_LOGW(PLAYBACK_TAG, "Failed to match event: %s!", event_name);
}
}
free(buf);
playback_task_handle = NULL;
stop_playback();
vTaskDelete(NULL);
}
void register_replay_fn(bool (*replay_fn)(const char*, char*)) {
replay_fns.push_back(replay_fn);
}
void event_occured(const char* name, const char* arg) {
if (state != STATE_RECORDING) return;
if (name == nullptr) return;
if (recording_stream == nullptr) {
ESP_LOGE("state_tracking", "We are in state recording, but recording stream is null");
return;
}
arg = (arg == nullptr) ? "" : arg;
uint32_t ticks = xTaskGetTickCount() - recording_start_time;
fprintf(recording_stream, "%ld,%s:%s\n", ticks, name, (arg == nullptr) ? "" : arg);
}
bool set_recording_source(FILE* stream, bool should_close) {
if (state == STATE_RECORDING) return false;
recording_stream = stream;
should_close_recording_stream = should_close;
return true;
}
bool set_playback_source(FILE* stream, bool should_close) {
if (state == STATE_PLAYBACK) return false;
playback_stream = stream;
should_close_playback_stream = should_close;
return true;
}
bool start_recording() {
if (state != STATE_IDLE) return false;
if (recording_stream == nullptr) return false;
state = STATE_RECORDING;
recording_start_time = xTaskGetTickCount();
xTaskCreate(flush_file_task, "flush_recording", 2048, NULL, 2, &flush_file_task_handle);
reset_wlv_tables(); // TODO: generify this
return true;
}
bool stop_recording() {
if (state != STATE_RECORDING) return false;
state = STATE_IDLE;
fflush(recording_stream);
if (should_close_recording_stream) {
fclose(recording_stream);
recording_stream = nullptr;
}
if (flush_file_task_handle != nullptr) {
vTaskDelete(flush_file_task_handle);
flush_file_task_handle = NULL;
}
return true;
}
bool start_playback() {
if (state != STATE_IDLE) return false;
if (playback_stream == nullptr) return false;
state = STATE_PLAYBACK;
playback_start_time = xTaskGetTickCount();
xTaskCreate(playback_task, "playback", 4096, NULL, 2, &playback_task_handle);
reset_wlv_tables(); // TODO: generify this
return true;
}
bool stop_playback() {
if (state != STATE_PLAYBACK) return false;
state = STATE_IDLE;
if (should_close_playback_stream) {
fclose(playback_stream);
playback_stream = nullptr;
}
if (playback_task_handle != nullptr) {
// TODO: NO!! This leaks the malloc. Instead, use a queue to request a graceful stop
vTaskDelete(playback_task_handle);
playback_task_handle = NULL;
}
return true;
}
bool is_state_tracking() {
return state == STATE_RECORDING;
}
-53
View File
@@ -1,53 +0,0 @@
#ifndef STATE_TRACKING_H
#define STATE_TRACKING_H
#include <stdint.h>
#include "esp_vfs_fat.h"
/// @brief Registers function to be called on replay.
/// @param replay_callback A function to call to playback the event.
void register_replay_fn(bool (*replay_fn)(const char*, char*));
// TODO: add one for generically responding to all events.
/// @brief Call this to indicate that the bomb state has transitioned.
/// @param name The name of the event that has occured.
/// @param arg The serialized data associated with the event.
/// This must not contain newline characters such as '\n' or '\r'
void event_occured(const char* name, const char* arg);
/// @brief Sets the recording source.
/// @param stream The stream to record to.
/// @param should_close whether or not the stream should be closed when finished.
/// @return true if the source was updated.
bool set_recording_source(FILE* stream, bool should_close);
/// @brief Sets the playback source.
/// @param stream The stream to playback from.
/// @param should_close whether or not the stream should be closed when finished.
/// @return true if the source was updated.
bool set_playback_source(FILE* stream, bool should_close);
/// @brief Starts recording to the stream specified by `set_recording_source()`.
/// @return true if starting recording is successful.
bool start_recording();
/// @brief Stops recording the state.
/// @return true if stopping the recording is successful.
bool stop_recording();
/// @brief Starts playing back the recording specified by `set_playback_source()`.
/// @return true if starting playback is successful.
bool start_playback();
/// @brief Stops playing back the recording.
/// @return true if stopping the playback is successful.
bool stop_playback();
/// @brief Gets weather or not we are tracking the state
/// This can be helpful to conditionally do extra computation only
/// when we are tracking the state.
/// @return
bool is_state_tracking();
#endif /* STATE_TRACKING_H */
+12 -56
View File
@@ -1,5 +1,4 @@
#include "tft.h"
#include "state_tracking.h"
static const char* TAG = "tft";
@@ -17,28 +16,16 @@ static lv_style_t style_screen;
SemaphoreHandle_t xGuiSemaphore;
static bool replay_handler(const char* event, char* arg) {
return false;
}
static bool notify_lvgl_flush_ready(
esp_lcd_panel_io_handle_t panel_io,
esp_lcd_panel_io_event_data_t *edata,
void *user_ctx
) {
lv_disp_drv_t* disp_driver = (lv_disp_drv_t *)user_ctx;
lv_disp_drv_t *disp_driver = (lv_disp_drv_t *)user_ctx;
lv_disp_flush_ready(disp_driver);
return false;
}
const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/// Base 64 encodes a u16... sort of. This doesn't do any of the fancy padding stuff.
static void encode_base64(char* buf, size_t start_idx, uint16_t value) {
buf[start_idx+0] = base64_chars[(value >> 10) & 0x3F];
buf[start_idx+1] = base64_chars[(value >> 4) & 0x3F];
buf[start_idx+2] = base64_chars[(value << 2) & 0x3F];
}
static void lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) {
esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data;
@@ -46,46 +33,7 @@ static void lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t
int offsetx2 = area->x2;
int offsety1 = area->y1;
int offsety2 = area->y2;
esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);
// TODO: change this to be a kconfig value
#if false
if (is_state_tracking()) {
size_t size = (offsetx2 + 1 - offsetx1) * (offsety2 + 1 - offsety1) + 1;
// if (size > 1024) {
// ESP_LOGW("tft_track_state", "Write too big (%d)! truncating to 1024!", size);
// }
// size = MIN(1024, size);
// 24 bytes for the offsets
// 3 bytes per encoded color
// 1 byte for null terminator
size_t alloc_size = 24 + size * 3 + 1;
char* buf = (char*)malloc(alloc_size);
if (buf != nullptr) {
size_t initial_offset = sprintf(buf, "%d,%d,%d,%d:", offsetx1, offsety1, offsetx2 + 1, offsety2 + 1);
for (size_t i = 0; i < size; i++) {
size_t index = initial_offset + i * 3;
// we assume that the size of the color data is 16b
static_assert(sizeof(lv_color_t) == sizeof(uint16_t), "lv_color_t must be 16b wide");
encode_base64(buf, index, color_map[i].full);
}
buf[initial_offset + (size-1) * 3 + 1] = '\0';
event_occured("TFT_W", buf);
free(buf);
} else {
ESP_LOGE("tft_track_state", "buffer alloc failed!");
}
}
#endif
}
static void IRAM_ATTR lv_tick_task(void *param) {
@@ -202,10 +150,10 @@ static void guiTask(void *pvParameter) {
ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &periodic_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, LVGL_UPDATE_PERIOD_MS * 1000));
screen = lv_scr_act();
screen = lv_disp_get_scr_act(NULL);
lv_style_init(&style_screen);
lv_style_set_bg_color(&style_screen, lv_color_black());
lv_obj_add_style(screen, &style_screen, LV_STATE_DEFAULT);
lv_obj_add_style(lv_scr_act(), &style_screen, LV_STATE_DEFAULT);
while (1) {
/* Delay 1 tick (assumes FreeRTOS tick is 10ms */
@@ -221,6 +169,14 @@ static void guiTask(void *pvParameter) {
vTaskDelete(NULL);
}
static void tick_timer_task(void* arg) {
while (1)
{
lv_task_handler();
vTaskDelay(pdMS_TO_TICKS(10));
}
}
void init_tft() {
ESP_LOGI(TAG, "Initializing TFT...");
@@ -228,7 +184,7 @@ void init_tft() {
initialize_display();
xTaskCreatePinnedToCore(guiTask, "gui", 4096*2, NULL, 5, NULL, 1);
register_replay_fn(replay_handler);
// xTaskCreatePinnedToCore(tick_timer_task, "tick_lvgl", 4096, NULL, 5, NULL, 1);
ESP_LOGI(TAG, "TFT initialized!");
}
+4 -4
View File
@@ -44,11 +44,11 @@
#define SPI_MAX_TRANSFER_SIZE 32768
#define TFT_PIN_MOSI GPIO_NUM_17
#define TFT_PIN_MISO GPIO_NUM_16
#define TFT_PIN_CLK GPIO_NUM_18
#define TFT_PIN_MISO GPIO_NUM_18
#define TFT_PIN_CLK GPIO_NUM_16
#define TFT_PIN_CS GPIO_NUM_NC
#define TFT_PIN_DC GPIO_NUM_8
#define TFT_PIN_RESET GPIO_NUM_9
#define TFT_PIN_DC GPIO_NUM_15
#define TFT_PIN_RESET GPIO_NUM_8
#define TFT_INVERT_COLOR false
+6 -23
View File
@@ -2,9 +2,6 @@
extern uint32_t current_step;
/// The mutex for accessing `I2C_NUM_1` (wires I2C bus).
SemaphoreHandle_t wires_i2c_mutex;
uint32_t total_strikes;
uint32_t step_strikes[N_STEPS] = {0};
uint32_t step_finish_times[N_STEPS] = {0};
@@ -29,25 +26,21 @@ static void receive_button(void);
void init_wires(void) {
i2c_config_t wires_conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = PIN_WIRES_SDA,
.scl_io_num = PIN_WIRES_SCL,
.sda_io_num = GPIO_NUM_41,
.scl_io_num = GPIO_NUM_42,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master = {
.clk_speed = 100000,
},
}
};
gpio_reset_pin(PIN_WIRES_SDA);
gpio_reset_pin(PIN_WIRES_SCL);
gpio_reset_pin(GPIO_NUM_41);
gpio_reset_pin(GPIO_NUM_42);
ESP_ERROR_CHECK(i2c_param_config(WIRES_I2C_NUM, &wires_conf));
ESP_ERROR_CHECK(i2c_driver_install(WIRES_I2C_NUM, wires_conf.mode, 0, 0, 0));
// Create mutex for wires I2C bus
wires_i2c_mutex = xSemaphoreCreateMutex();
assert(wires_i2c_mutex != NULL);
gpio_config_t int_pin_conf = {};
// delta_pin_conf.intr_type = GPIO_INTR_LOW_LEVEL;
int_pin_conf.mode = GPIO_MODE_INPUT;
@@ -92,41 +85,33 @@ void clear_wires_pressed_released_cut(void) {
void strike(const char* reason) {
ESP_LOGW("strike!", "%s", reason);
lcd_print(3, 0, reason);
lcd_print(0, 3, reason);
time_penalty(STRIKE_TIME_PENALTY);
if (current_step > 0 && current_step <= N_STEPS) {
total_strikes += 1;
step_strikes[current_step - 1] += 1;
}
uint8_t reg = 6;
xSemaphoreTake(wires_i2c_mutex, portMAX_DELAY);
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_write_to_device(WIRES_I2C_NUM, WIRES_I2C_ADDR, &reg, 1, (100 / portTICK_PERIOD_MS)));
xSemaphoreGive(wires_i2c_mutex);
}
void set_leds(uint8_t led_states) {
buf[0] = 5; // register 5
buf[1] = led_states;
xSemaphoreTake(wires_i2c_mutex, portMAX_DELAY);
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_write_to_device(WIRES_I2C_NUM, WIRES_I2C_ADDR, buf, 2, (100 / portTICK_PERIOD_MS)));
xSemaphoreGive(wires_i2c_mutex);
}
static uint8_t receive_delta(void) {
uint8_t reg = 1;
buf[0] = 0;
xSemaphoreTake(wires_i2c_mutex, portMAX_DELAY);
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_write_read_device(WIRES_I2C_NUM, WIRES_I2C_ADDR, &reg, 1, buf, 1, (100 / portTICK_PERIOD_MS)));
xSemaphoreGive(wires_i2c_mutex);
return buf[0];
}
static void receive_wires(void) {
uint8_t reg = 2;
buf[0] = 0;
xSemaphoreTake(wires_i2c_mutex, portMAX_DELAY);
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_write_read_device(WIRES_I2C_NUM, WIRES_I2C_ADDR, &reg, 1, buf, 1, (100 / portTICK_PERIOD_MS)));
xSemaphoreGive(wires_i2c_mutex);
uint8_t new_wires = buf[0];
uint8_t just_cut = ~new_wires & wires_state;
@@ -138,9 +123,7 @@ static void receive_wires(void) {
static void receive_button(void) {
uint8_t reg = 3;
buf[0] = 0;
xSemaphoreTake(wires_i2c_mutex, portMAX_DELAY);
ESP_ERROR_CHECK_WITHOUT_ABORT(i2c_master_write_read_device(WIRES_I2C_NUM, WIRES_I2C_ADDR, &reg, 1, buf, 1, (100 / portTICK_PERIOD_MS)));
xSemaphoreGive(wires_i2c_mutex);
bool new_button = buf[0] != 0;
bool just_pressed = new_button & !button_state;
+1 -9
View File
@@ -5,22 +5,14 @@
#include <driver/i2c.h>
#include <driver/gpio.h>
#include <esp_log.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "drivers/char_lcd.h"
#include "drivers/game_timer.h"
#include "main.h"
#include "perh.h"
#define WIRES_PIN_DELTA PIN_PERH3
#define PIN_WIRES_SDA PIN_PERH1
#define PIN_WIRES_SCL PIN_PERH2
#define WIRES_PIN_DELTA GPIO_NUM_2
#define WIRES_I2C_NUM I2C_NUM_1
#define WIRES_I2C_ADDR 125
/// The mutex for accessing `I2C_NUM_1` (wires I2C bus).
extern SemaphoreHandle_t wires_i2c_mutex;
#define DELTA_BIT_WIRES 0
#define DELTA_BIT_BUTTON 1
-152
View File
@@ -1,152 +0,0 @@
#include "wlvgl.h"
#include <vector>
/// A table that maps an incrementing integer to a style reference
static std::vector<lv_style_t*> style_table;
/// A table that maps an incrementing integer to a style reference
static std::vector<lv_obj_t*> obj_table;
static int index_of_style(lv_style_t* style) {
for (size_t i = 0; i < style_table.size(); i++) {
if (style_table[i] == style) {
return i;
}
}
return -1;
}
static int index_of_obj(lv_obj_t* obj) {
for (size_t i = 0; i < obj_table.size(); i++) {
if (obj_table[i] == obj) {
return i;
}
}
return -1;
}
void reset_wlv_tables() {
style_table.clear();
obj_table.clear();
}
lv_obj_t * wlv_obj_create(lv_obj_t* parent) {
// initialize the obj
lv_obj_t* value = lv_obj_create(parent);
if (is_state_tracking()) {
// add the style to the table
obj_table.push_back(value);
size_t obj_index = obj_table.size();
char buf[8];
sprintf(buf, "%d", obj_index);
event_occured("lv_obj_create", buf);
}
return value;
}
void wlv_style_init(lv_style_t* style) {
// initialize the style
lv_style_init(style);
if (is_state_tracking()) {
// add the style to the table
style_table.push_back(style);
size_t style_index = style_table.size();
char buf[8];
sprintf(buf, "%d", style_index);
event_occured("lv_style_init", buf);
}
}
void wlv_obj_set_style_bg_color(lv_obj_t* obj, lv_color_t value, lv_style_selector_t selector) {
lv_obj_set_style_bg_color(obj, value, selector);
if (is_state_tracking()) {
int obj_index = index_of_obj(obj);
char buf[64];
sprintf(buf, "%d,%d,%ld", obj_index, value.full, selector);
event_occured("lv_obj_set_style_bg_color", buf);
}
}
void wlv_style_set_text_color() {
}
void wlv_style_set_text_align() {
}
void wlv_obj_align() {
}
void wlv_obj_set_size() {
}
void wlv_obj_add_style() {
}
void wlv_obj_set_style_text_align() {
}
void wlv_label_set_text() {
}
void wlv_scr_load() {
}
void wlv_scr_act() {
}
void wlv_style_set_bg_color() {
}
void wlv_style_set_bg_opa() {
}
void wlv_obj_set_width() {
}
void wlv_style_set_text_font() {
}
void wlv_label_create() {
}
void wlv_obj_del() {
}
void wlv_obj_center() {
}
void wlv_obj_remove_style() {
}
void wlv_obj_add_flag() {
}
void wlv_obj_clear_flag() {
}
-32
View File
@@ -1,32 +0,0 @@
#ifndef WLVGL_H
#define WLVGL_H
#include "lvgl.h"
#include "state_tracking.h"
void reset_wlv_tables();
lv_obj_t* wlv_obj_create(lv_obj_t* parent);
void wlv_style_init(lv_style_t* style);
void wlv_obj_set_style_bg_color(struct _lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector);
void wlv_style_set_text_color();
void wlv_style_set_text_align();
void wlv_obj_align();
void wlv_obj_set_size();
void wlv_obj_add_style();
void wlv_obj_set_style_text_align();
void wlv_label_set_text();
void wlv_scr_load();
void wlv_scr_act();
void wlv_style_set_bg_color();
void wlv_style_set_bg_opa();
void wlv_obj_set_width();
void wlv_style_set_text_font();
void wlv_label_create();
void wlv_obj_del();
void wlv_obj_center();
void wlv_obj_remove_style();
void wlv_obj_add_flag();
void wlv_obj_clear_flag();
#endif /* WLVGL_H */
+69 -2
View File
@@ -17,10 +17,76 @@ void clean_bomb(void) {
set_module_sseg_raw(clear);
// clear char lcd
lcd_set_cursor_vis(false);
lcd_clear();
lcd_set_cursor_vis(false);
lcd_cursor_home();
}
// TODO: add stuff for starcode system
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_keypad_pressed(&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_print(1, 2, sch.display_text);
vTaskDelay(pdMS_TO_TICKS(2000));
if (sch.callback != nullptr) {
(sch.callback)();
}
if (sch.should_exit) {
return;
}
break;
}
}
if (!hit) {
lcd_print(1, 2, "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_print(1, 1, current);
}
vTaskDelay(pdMS_TO_TICKS(10));
}
}
static lv_obj_t* old_scr;
@@ -54,6 +120,7 @@ void display_game_results(void) {
lv_style_init(&game_results_style);
lv_style_set_text_color(&game_results_style, lv_color_white());
// lv_style_set_bg_color(&game_results_style, lv_color_black());
lv_style_set_text_align(&game_results_style, LV_TEXT_ALIGN_LEFT);
overall_results_label = lv_label_create(scr);
+9
View File
@@ -10,11 +10,20 @@
#include "drivers/speaker.h"
#include "drivers/tft.h"
struct StarCodeHandler {
const char* code;
const char* display_text;
bool should_exit;
void (*callback)(void);
};
// TODO: add something for RNG.
// TODO: add something for colors, to make everything consistant.
/// 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);
void display_game_results();
#endif /* HELPER_H */
-15
View File
@@ -5,10 +5,8 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_rom_gpio.h"
#include "esp_heap_caps.h"
#include "drivers/all.h"
#include "drivers/state_tracking.h"
#include "helper.h"
@@ -34,20 +32,9 @@ extern "C" void app_main(void) {
// TODO: get wires out of the drivers
// TODO: generify the strike system out of wires
init_wires();
vTaskDelay(pdMS_TO_TICKS(1000));
clean_bomb();
lcd_do_splash();
step0();
// set_recording_source(stdout, false);
FILE* record_file = fopen(MOUNT_POINT "/record.txt", "w");
if (record_file == nullptr) {
ESP_LOGE("main", "failed to open record.txt");
}
set_recording_source(record_file, true);
start_recording();
set_game_time(initial_game_time);
start_game_timer();
total_strikes = 0;
@@ -83,6 +70,4 @@ extern "C" void app_main(void) {
play_clip_wav(MOUNT_POINT "/diffuse.wav", true, false, 3, 0);
display_game_results();
stop_recording();
}
+4 -5
View File
@@ -11,7 +11,7 @@ void print_wires(WireColor* wires, int editing_idx) {
lcd_print(1, 1, string_buf);
cut_to_string(cut, string_buf);
lcd_print(2, 1, string_buf);
lcd_print(1, 2, string_buf);
wires_state = get_wires();
for (int i = 0; i < NUM_WIRES; i++) {
@@ -21,17 +21,16 @@ void print_wires(WireColor* wires, int editing_idx) {
string_buf[i] = '!';
}
}
lcd_print(3, 1, string_buf);
lcd_print(1, 3, string_buf);
lcd_set_cursor_vis(true);
lcd_set_cursor_resting_position(1, editing_idx+1);
lcd_set_cursor_pos(editing_idx+1, 1);
}
void setup_wires(void) {
clear_all_pressed_released();
get_cut_wires();
lcd_clear();
lcd_set_cursor_vis(true);
lcd_set_cursor_vis(false);
WireColor wires[NUM_WIRES];
load_wires_from_sd_card(wires);
+54 -108
View File
@@ -1,5 +1,4 @@
#include "step0.h"
#include "drivers/state_tracking.h"
static const char* TAG = "step0";
@@ -35,184 +34,132 @@ static void battery_stats() {
}
}
// TODO: remove. This is temperary
static void replay_last() {
FILE* record_file = fopen(MOUNT_POINT "/record.txt", "r");
if (record_file == nullptr) {
ESP_LOGE("main", "failed to open record.txt");
}
set_playback_source(record_file, true);
start_playback();
}
/// Wait for "*9819"
void step0() {
led_set(IndicatorLED::LED_SPEAKER, LEDColor::LED_COLOR_BLUE);
leds_flush();
SemaphoreHandle_t continue_sem = xSemaphoreCreateBinary();
if (continue_sem == nullptr) {
ESP_LOGE(TAG, "could not create semaphore");
return;
}
StarCodeEntry star_codes[] = {
StarCodeHandler star_codes[] = {
{
.code = "9819",
.code = "*9819",
.display_text = "Diffusal Initiated",
.delay_us = 2'000'000,
.should_exit = true,
.callback = nullptr,
.triggered_sem = continue_sem,
},
{
.code = "59860",
.display_text = "Hardware Config",
.delay_us = 2'000'000,
.callback = hardware_config,
.triggered_sem = nullptr,
},
{
.code = "59861",
.display_text = "Setup Wires",
.delay_us = 2'000'000,
.code = "*59861",
.display_text = "Set Up Wires",
.should_exit = false,
.callback = setup_wires,
.triggered_sem = nullptr,
},
{
.code = "59862",
.code = "*59862",
.display_text = "Set Game Time",
.delay_us = 2'000'000,
.should_exit = false,
.callback = set_game_time,
.triggered_sem = nullptr,
},
{
.code = "59863",
.display_text = "Debug switches",
.delay_us = 2'000'000,
.code = "*59863",
.display_text = "Debug Switches",
.should_exit = false,
.callback = debug_switches,
.triggered_sem = nullptr,
},
{
.code = "59864",
.code = "*59864",
.display_text = "Battery Stats",
.delay_us = 2'000'000,
.should_exit = false,
.callback = battery_stats,
.triggered_sem = nullptr,
},
{
.code = "59871",
.code = "*59871",
.display_text = "Try Step 1",
.delay_us = 2'000'000,
.should_exit = false,
.callback = try_step1,
.triggered_sem = nullptr,
},
{
.code = "59872",
.code = "*59872",
.display_text = "Try Step 2",
.delay_us = 2'000'000,
.should_exit = false,
.callback = try_step2,
.triggered_sem = nullptr,
},
{
.code = "59873",
.code = "*59873",
.display_text = "Try Step 3",
.delay_us = 2'000'000,
.should_exit = false,
.callback = try_step3,
.triggered_sem = nullptr,
},
{
.code = "59874",
.code = "*59874",
.display_text = "Try Step 4",
.delay_us = 2'000'000,
.should_exit = false,
.callback = try_step4,
.triggered_sem = nullptr,
},
{
.code = "59875",
.code = "*59875",
.display_text = "Try Step 5",
.delay_us = 2'000'000,
.should_exit = false,
.callback = try_step5,
.triggered_sem = nullptr,
},
{
.code = "59876",
.code = "*59876",
.display_text = "Try Step 6",
.delay_us = 2'000'000,
.should_exit = false,
.callback = try_step6,
.triggered_sem = nullptr,
},
{
.code = "59881",
.code = "*59881",
.display_text = "Skip To Step 1",
.delay_us = 2'000'000,
.should_exit = true,
.callback = skip_to_step1,
.triggered_sem = continue_sem,
},
{
.code = "59882",
.code = "*59882",
.display_text = "Skip To Step 2",
.delay_us = 2'000'000,
.should_exit = true,
.callback = skip_to_step2,
.triggered_sem = continue_sem,
},
{
.code = "59883",
.code = "*59883",
.display_text = "Skip To Step 3",
.delay_us = 2'000'000,
.should_exit = true,
.callback = skip_to_step3,
.triggered_sem = continue_sem,
},
{
.code = "59884",
.code = "*59884",
.display_text = "Skip To Step 4",
.delay_us = 2'000'000,
.should_exit = true,
.callback = skip_to_step4,
.triggered_sem = continue_sem,
},
{
.code = "59885",
.code = "*59885",
.display_text = "Skip To Step 5",
.delay_us = 2'000'000,
.should_exit = true,
.callback = skip_to_step5,
.triggered_sem = continue_sem,
},
{
.code = "59886",
.code = "*59886",
.display_text = "Skip To Step 6",
.delay_us = 2'000'000,
.should_exit = true,
.callback = skip_to_step6,
.triggered_sem = continue_sem,
},
{
.code = "1111",
.code = "*1111",
.display_text = "Issue Strike",
.delay_us = 2'000'000,
.should_exit = false,
.callback = issue_strike,
.triggered_sem = nullptr,
},
{
.code = "1112",
.code = "*1112",
.display_text = "????",
.delay_us = 2'000'000,
.should_exit = false,
.callback = flashbang,
.triggered_sem = nullptr,
},
{
.code = "1113",
.display_text = "replay",
.delay_us = 2'000'000,
.callback = replay_last,
.triggered_sem = continue_sem,
},
};
size_t len = sizeof(star_codes)/sizeof(star_codes[0]);
add_star_codes(star_codes, len);
xSemaphoreTake(continue_sem, portMAX_DELAY);
rm_star_codes(star_codes, len);
vSemaphoreDelete(continue_sem);
int len = sizeof(star_codes)/sizeof(StarCodeHandler);
do_star_codes(star_codes, len);
}
static const int CURSOR_POS_MAP[5] = {1, 3, 4, 6, 7};
static char str_buf[18] = {0};
static void _update_display(uint8_t* digits, uint8_t cursor_pos) {
@@ -221,8 +168,7 @@ static void _update_display(uint8_t* digits, uint8_t cursor_pos) {
lcd_print(1, 1, str_buf);
cursor_pos = MAX(0, MIN(4, cursor_pos));
int mapped_cursor_pos = CURSOR_POS_MAP[cursor_pos];
lcd_set_cursor_resting_position(1, mapped_cursor_pos);
lcd_set_cursor_pos(mapped_cursor_pos, 1);
}
static void set_game_time() {
@@ -343,32 +289,32 @@ static void debug_switches() {
while (1) {
if (get_button_pressed(&button)) {
sprintf(buf, "Button Pressed: %d ", button);
lcd_print(3, 0, buf);
lcd_print(0, 3, buf);
ESP_LOGI(TAG, "%s", buf);
}
if (get_button_released(&button)) {
sprintf(buf, "Button Released: %d", button);
lcd_print(3, 0, buf);
lcd_print(0, 3, buf);
ESP_LOGI(TAG, "%s", buf);
}
if (get_switch_flipped_down(&switch_)) {
sprintf(buf, "Switch Down: %d ", switch_);
lcd_print(3, 0, buf);
lcd_print(0, 3, buf);
ESP_LOGI(TAG, "%s", buf);
}
if (get_switch_flipped_up(&switch_)) {
sprintf(buf, "Switch Up: %d ", switch_);
lcd_print(3, 0, buf);
lcd_print(0, 3, buf);
ESP_LOGI(TAG, "%s", buf);
}
if (get_switch_touch_pressed(&switch_)) {
sprintf(buf, "Switch Touch: %d ", switch_);
lcd_print(3, 0, buf);
lcd_print(0, 3, buf);
ESP_LOGI(TAG, "%s", buf);
}
if (get_switch_touch_released(&switch_)) {
sprintf(buf, "Switch Un-touch: %d", switch_);
lcd_print(3, 0, buf);
lcd_print(0, 3, buf);
ESP_LOGI(TAG, "%s", buf);
}
@@ -377,7 +323,7 @@ static void debug_switches() {
switch_touch_state = new_switch_touch_state;
print_4bin_rev(bin_buf, switch_touch_state);
sprintf(buf, "t: %s", bin_buf);
lcd_print(0, 1, buf);
lcd_print(1, 0, buf);
ESP_LOGI(TAG, "%s", buf);
}
@@ -395,7 +341,7 @@ static void debug_switches() {
button_state = new_button_state;
print_4bin_rev(bin_buf, button_state);
sprintf(buf, "b: %s", bin_buf);
lcd_print(2, 1, buf);
lcd_print(1, 2, buf);
ESP_LOGI(TAG, "%s", buf);
}
+6 -2
View File
@@ -1,9 +1,13 @@
#ifndef STEP_0_H
#define STEP_0_H
#include "../drivers/all.h"
#include "../drivers/bottom_half.h"
#include "../drivers/char_lcd.h"
#include "../drivers/wires.h"
#include "../drivers/power.h"
#include "setup_wires.h"
#include "../helper.h"
#include "step1.h"
#include "step2.h"
#include "step3.h"
+5 -4
View File
@@ -199,24 +199,25 @@ static int generate_part(void) {
static void update_lcd_count(int times) {
char buf[16] = {0};
sprintf(buf, "%d/15", times);
lcd_print(1, 14, buf);
lcd_print(14, 1, buf);
}
static bool play_part(uint32_t time) {
set_module_time(time);
lcd_clear();
lcd_set_cursor_pos(1, 1);
switch (part) {
case 0:
lcd_print(1, 1, "COLOR");
lcd_print("COLOR");
led_set(IndicatorLED::LED_LCD, LEDColor::LED_COLOR_PINK);
break;
case 1:
lcd_print(1, 1, "NUMBER");
lcd_print("NUMBER");
led_set(IndicatorLED::LED_LCD, LEDColor::LED_COLOR_BLUE);
break;
case 2:
lcd_print(1, 1, "SWITCH");
lcd_print("SWITCH");
led_set(IndicatorLED::LED_LCD, LEDColor::LED_COLOR_YELLOW);
break;
}
+7 -2
View File
@@ -2,8 +2,13 @@
#define STEP_1_H
#include <random>
#include "../drivers/all.h"
#include "../helper.h"
#include "../drivers/bottom_half.h"
#include "../drivers/tft.h"
#include "../drivers/leds.h"
#include "../drivers/wires.h"
#include "../drivers/speaker.h"
#include "../drivers/game_timer.h"
#include "../drivers/char_lcd.h"
void step1(void);
+1 -1
View File
@@ -88,7 +88,6 @@ static void new_puzzle(void) {
// ESP_LOGI(TAG, "Flipping bit %i on display %i", i, display);
}
}
set_module_sseg_raw(display_map);
}
void step2(void) {
@@ -99,6 +98,7 @@ void step2(void) {
int strike_time = 0;
while(solved_times < NUM_SOLVES) {
// for every bit in the answer-
set_module_sseg_raw(display_map);
if (get_keypad_pressed(&key)) {
lcd_clear();
char c = char_of_keypad_key(key);
+5 -1
View File
@@ -1,7 +1,11 @@
#ifndef STEP_2_H
#define STEP_2_H
#include "../drivers/all.h"
#include "../drivers/bottom_half.h"
#include "../drivers/wires.h"
#include "../drivers/game_timer.h"
#include "../drivers/leds.h"
#include "../drivers/speaker.h"
#include "../helper.h"
#include <iostream>
#include <random>
+21 -38
View File
@@ -21,8 +21,6 @@ static const char* TONE_FILES[] = {
MOUNT_POINT "/high-6.wav",
};
static const size_t LCD_STRING_SOMETHING = 0;
static const size_t LCD_STRING_NOTHING = 1;
static const char* LCD_STRINGS[] = {
"something",
"nothing",
@@ -51,20 +49,13 @@ static std::uniform_int_distribution<> lcd_rand_char_dist(0, sizeof(lcd_random_c
static std::uniform_int_distribution<> has_coconut_dist(0, 2);
static std::uniform_int_distribution<> coconut_position_dist(0, 13);
const static uint32_t NEOPIXEL_COLOR_IDX_RED = 0;
const static uint32_t NEOPIXEL_COLOR_IDX_YELLOW = 1;
const static uint32_t NEOPIXEL_COLOR_IDX_GREEN = 2;
const static uint32_t NEOPIXEL_COLOR_IDX_BLUE = 3;
const static uint32_t NEOPIXEL_COLOR_IDX_PINK = 4;
const static uint32_t NEOPIXEL_COLOR_IDX_WHITE = 5;
const static uint32_t NEOPIXEL_COLOR_IDX_OFF = 6;
static uint32_t NEOPIXEL_COLORS[7] = {
LEDColor::LED_COLOR_RED,
LEDColor::LED_COLOR_ORANGE,
LEDColor::LED_COLOR_YELLOW,
LEDColor::LED_COLOR_GREEN,
LEDColor::LED_COLOR_BLUE,
LEDColor::LED_COLOR_PINK,
LEDColor::LED_COLOR_WHITE,
LEDColor::LED_COLOR_OFF,
};
@@ -73,24 +64,16 @@ static bool three_second();
static bool six_second();
void step3(void) {
SemaphoreHandle_t continue_sem = xSemaphoreCreateBinary();
if (continue_sem == nullptr) {
ESP_LOGE(TAG, "could not create semaphore");
return;
}
StarCodeEntry start_code = {
.code = "1642",
.display_text = "Starting...",
.delay_us = 2'000'000,
.callback = nullptr,
.triggered_sem = continue_sem,
StarCodeHandler star_codes[] = {
{
.code = "*1642",
.display_text = "Starting...",
.should_exit = true,
.callback = nullptr,
},
};
add_star_code(start_code);
xSemaphoreTake(continue_sem, portMAX_DELAY);
rm_star_code(start_code.code);
vSemaphoreDelete(continue_sem);
int len = sizeof(star_codes)/sizeof(StarCodeHandler);
do_star_codes(star_codes, len);
while (times < TIMES_TO_COMPLETE) {
tone = tone_dist(gen);
@@ -99,7 +82,7 @@ void step3(void) {
play_clip_wav(MOUNT_POINT "/ready.wav", true, false, 3, 0);
// The high pitched tones need to be scaled down by 3 more
play_clip_wav(TONE_FILES[tone], false, false, 1 + (tone/3) * 4, 0);
play_clip_wav(TONE_FILES[tone], false, false, 2 + (tone/3) * 3, 0);
bool correct = false;
switch (tone % 3) {
@@ -238,16 +221,16 @@ static bool one_second() {
int red_led_count = 0;
int blue_led_count = 0;
for (int i = 0; i < LED_COUNT; i++) {
if (indicator_led_idxs[i] == NEOPIXEL_COLOR_IDX_RED) {
if (indicator_led_idxs[i] == 0) {
red_led_count++;
} else if (indicator_led_idxs[i] == NEOPIXEL_COLOR_IDX_BLUE) {
} else if (indicator_led_idxs[i] == 4) {
blue_led_count++;
}
}
uint8_t correct_switches = four_bit_flag(
speaker_color == NEOPIXEL_COLOR_IDX_RED || speaker_color == NEOPIXEL_COLOR_IDX_YELLOW || speaker_color == NEOPIXEL_COLOR_IDX_PINK,
lcd_string_idx == LCD_STRING_SOMETHING || lcd_string_idx == LCD_STRING_NOTHING,
speaker_color == 0 || speaker_color == 1 || speaker_color == 2,
lcd_string_idx == 0 || lcd_string_idx == 1,
was_high,
!was_high
);
@@ -297,9 +280,9 @@ static bool three_second() {
int red_led_count = 0;
int blue_led_count = 0;
for (int i = 0; i < LED_COUNT; i++) {
if (indicator_led_idxs[i] == NEOPIXEL_COLOR_IDX_RED) {
if (indicator_led_idxs[i] == 0) {
red_led_count++;
} else if (indicator_led_idxs[i] == NEOPIXEL_COLOR_IDX_BLUE) {
} else if (indicator_led_idxs[i] == 4) {
blue_led_count++;
}
}
@@ -362,7 +345,7 @@ static bool six_second() {
bool was_high = (tone / 3) == 1;
bool second_switch_correct_state = (indicator_led_idxs[IndicatorLED::LED_S2] == NEOPIXEL_COLOR_IDX_RED) || (indicator_led_idxs[IndicatorLED::LED_S2] == NEOPIXEL_COLOR_IDX_OFF);
bool second_switch_correct_state = (indicator_led_idxs[IndicatorLED::LED_S2] == 0) || (indicator_led_idxs[IndicatorLED::LED_S2] == 6);
second_switch_correct_state = second_switch_correct_state || was_high;
rng_leds();
@@ -371,16 +354,16 @@ static bool six_second() {
int green_led_count = 0;
int blue_led_count = 0;
for (int i = 0; i < LED_COUNT; i++) {
if (indicator_led_idxs[i] == NEOPIXEL_COLOR_IDX_BLUE) {
if (indicator_led_idxs[i] == 4) {
blue_led_count++;
} else if (indicator_led_idxs[i] == NEOPIXEL_COLOR_IDX_GREEN) {
} else if (indicator_led_idxs[i] == 3) {
green_led_count++;
}
}
int pink_led_on_bottom_count = 0;
for (int i = IndicatorLED::LED_RFID; i < LED_COUNT; i++) {
if (indicator_led_idxs[i] == NEOPIXEL_COLOR_IDX_PINK) {
if (indicator_led_idxs[i] == 5) {
pink_led_on_bottom_count++;
}
}
+6 -1
View File
@@ -2,7 +2,12 @@
#define STEP_3_H
#include <random>
#include "../drivers/all.h"
#include "../drivers/bottom_half.h"
#include "../drivers/wires.h"
#include "../drivers/speaker.h"
#include "../drivers/leds.h"
#include "../drivers/char_lcd.h"
#include "../drivers/game_timer.h"
#include "../helper.h"
void step3(void);
+4 -17
View File
@@ -380,29 +380,16 @@ static void fail() {
}
void step4() {
// TODO: extract to helper function
SemaphoreHandle_t continue_sem = xSemaphoreCreateBinary();
if (continue_sem == nullptr) {
ESP_LOGE(TAG, "could not create semaphore");
}
StarCodeEntry start_code = {
.code = "3850",
StarCodeHandler star_code = {
.code = "*3850",
.display_text = "Starting...",
.delay_us = 2'000'000,
.should_exit = true,
.callback = nullptr,
.triggered_sem = continue_sem,
};
add_star_code(start_code);
xSemaphoreTake(continue_sem, portMAX_DELAY);
rm_star_code(start_code.code);
vSemaphoreDelete(continue_sem);
do_star_codes(&star_code, 1);
init_screen();
while (!play_game(4*60*1000, 2)) fail();
// TODO: create constants for common assets, and put them in a folder.
play_clip_wav(MOUNT_POINT "/partdone.wav", true, false, 0, 0);
complete();
while (!play_game(4*60*1000, 4)) fail();
+6 -2
View File
@@ -2,9 +2,13 @@
#define STEP_4_H
#include <random>
#include "../drivers/all.h"
#include "../drivers/tft.h"
#include "../drivers/speaker.h"
#include "../drivers/bottom_half.h"
#include "../drivers/game_timer.h"
#include "../drivers/wires.h"
#include "../drivers/char_lcd.h"
#include "../helper.h"
#include "esp_log.h"
#define TETRIS_USE_FLASH_IMG
#define TETRIS_USE_FLASH_BG_IMG
+27 -32
View File
@@ -179,23 +179,16 @@ bool submit_6(bool* buttons_cycling, bool button_turned_on, int led_off) {
}
void step5(void) {
SemaphoreHandle_t continue_sem = xSemaphoreCreateBinary();
if (continue_sem == nullptr) {
ESP_LOGE(TAG, "could not create semaphore");
}
StarCodeEntry start_code = {
.code = "2648",
.display_text = "Starting...",
.delay_us = 2'000'000,
.callback = nullptr,
.triggered_sem = continue_sem,
StarCodeHandler star_codes[] = {
{
.code = "*2648",
.display_text = "Starting...",
.should_exit = true,
.callback = nullptr,
},
};
add_star_code(start_code);
xSemaphoreTake(continue_sem, portMAX_DELAY);
rm_star_code(start_code.code);
vSemaphoreDelete(continue_sem);
int len = sizeof(star_codes)/sizeof(StarCodeHandler);
do_star_codes(star_codes, len);
std::vector<int> all_leds;
@@ -229,13 +222,15 @@ void step5(void) {
clean_bomb();
int solved_puzzles = 0;
while (solved_puzzles < TIMES_TO_SOLVE) {
lcd_set_cursor_pos(1, 1);
bool solved_correctly = false;
int puzzle = puzzle_dist(gen);
// int puzzle = 2;
switch (puzzle) {
case 0: {
lcd_print(1, 1, "Clear");
lcd_print("Clear");
set_module_time(TIME_CLEAR);
start_module_timer();
@@ -270,7 +265,7 @@ void step5(void) {
break;
}
case 1: {
lcd_print(1, 1, "Blank");
lcd_print("Blank");
set_module_time(TIME_BLANK);
start_module_timer();
@@ -384,7 +379,7 @@ void step5(void) {
break;
}
case 3: {
lcd_print(1, 1, "Nothing");
lcd_print("Nothing");
set_module_time(TIME_NOTHING);
start_module_timer();
@@ -443,7 +438,7 @@ void step5(void) {
break;
}
case 4: {
lcd_print(1, 1, "Blink");
lcd_print("Blink");
set_module_time(TIME_BLINK);
start_module_timer();
@@ -507,7 +502,7 @@ void step5(void) {
break;
}
case 5: {
lcd_print(1, 1, "Ummm");
lcd_print("Ummm");
set_module_time(TIME_UMMM);
start_module_timer();
@@ -563,7 +558,7 @@ void step5(void) {
break;
}
case 6: {
lcd_print(1, 1, "Plank");
lcd_print("Plank");
set_module_time(TIME_PLANK);
start_module_timer();
@@ -656,7 +651,7 @@ void step5(void) {
break;
}
case 7: {
lcd_print(1, 1, "What");
lcd_print("What");
set_module_time(TIME_WHAT);
start_module_timer();
@@ -729,7 +724,7 @@ void step5(void) {
}
// display expression
lcd_print(2, 1, display_expression.c_str());
lcd_print(1, 2, display_expression.c_str());
// set LEDs
const uint32_t COLORS[] = {
@@ -790,8 +785,8 @@ void step5(void) {
lcd_clear();
lcd_print(1, 1, "What");
lcd_print(2, 1, display_expression.c_str());
lcd_print(3, 1, entered_string.c_str());
lcd_print(1, 2, display_expression.c_str());
lcd_print(1, 3, entered_string.c_str());
}
if (get_module_time() <= 0) {
strike("Ran out of time!");
@@ -804,7 +799,7 @@ void step5(void) {
break;
}
case 8: {
lcd_print(1, 1, "Plink");
lcd_print("Plink");
set_module_time(TIME_PLINK);
start_module_timer();
@@ -849,7 +844,7 @@ void step5(void) {
// ESP_LOGI(TAG, "color string: %s", color_string.c_str());
lcd_print(2, 1, color_string.c_str());
lcd_print(1, 2, color_string.c_str());
std::string entered_string;
@@ -880,8 +875,8 @@ void step5(void) {
lcd_clear();
lcd_print(1, 1, "Plink");
lcd_print(2, 1, color_string.c_str());
lcd_print(3, 1, entered_string.c_str());
lcd_print(1, 2, color_string.c_str());
lcd_print(1, 3, entered_string.c_str());
}
if (get_module_time() <= 0) {
strike("Ran out of time!");
@@ -905,13 +900,13 @@ void step5(void) {
stop_module_timer();
if (solved_correctly) {
solved_puzzles++;
play_clip_wav(MOUNT_POINT "/partdone.wav", true, false, 0, 0);
play_clip_wav(MOUNT_POINT "/correct.wav", true, false, 3, 0);
vTaskDelay(pdMS_TO_TICKS(500));
solved_correctly = false;
} else {
vTaskDelay(pdMS_TO_TICKS(3000));
}
play_clip_wav(MOUNT_POINT "/stepdone.wav", true, false, 1, 0);
clear_all_pressed_released();
clean_bomb();
}
}
+5 -1
View File
@@ -1,7 +1,11 @@
#ifndef STEP_5_H
#define STEP_5_H
#include "../drivers/all.h"
#include "../drivers/bottom_half.h"
#include "../drivers/game_timer.h"
#include "../drivers/char_lcd.h"
#include "../drivers/leds.h"
#include "../drivers/wires.h"
#include "../helper.h"
#include <random>
#include <iostream>
+4 -2
View File
@@ -2,8 +2,10 @@
#define STEP_6_H
#include "wires_puzzle.h"
#include "../drivers/all.h"
#include "../helper.h"
#include "drivers/wires.h"
#include "drivers/bottom_half.h"
#include "drivers/sd.h"
#include "drivers/speaker.h"
void step6(void);
-8
View File
@@ -1,8 +0,0 @@
# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs,data,nvs,0x9000,0x6000,,
phy_init,data,phy,0xf000,0x1000,,
ota,data,ota,0x10000,0x2000,,
factory,app,factory,0x20000,2M,,
ota0,app,ota_0,0x220000,2M,,
ota1,app,ota_1,0x420000,2M,,
1 # ESP-IDF Partition Table
2 # Name, Type, SubType, Offset, Size, Flags
3 nvs,data,nvs,0x9000,0x6000,,
4 phy_init,data,phy,0xf000,0x1000,,
5 ota,data,ota,0x10000,0x2000,,
6 factory,app,factory,0x20000,2M,,
7 ota0,app,ota_0,0x220000,2M,,
8 ota1,app,ota_1,0x420000,2M,,
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+550
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
+3366
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
+10 -49
View File
@@ -527,11 +527,11 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
# Partition Table
#
# CONFIG_PARTITION_TABLE_SINGLE_APP is not set
# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
# CONFIG_PARTITION_TABLE_TWO_OTA is not set
CONFIG_PARTITION_TABLE_CUSTOM=y
# CONFIG_PARTITION_TABLE_CUSTOM is not set
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp_large.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_PARTITION_TABLE_MD5=y
# end of Partition Table
@@ -539,7 +539,7 @@ CONFIG_PARTITION_TABLE_MD5=y
#
# BLK_BOX Config
#
# CONFIG_USE_NEW_DISPLAY is not set
CONFIG_USE_NEW_DISPLAY=y
# end of BLK_BOX Config
#
@@ -920,8 +920,8 @@ CONFIG_ESP32S3_UNIVERSAL_MAC_ADDRESSES=4
#
# Sleep Config
#
# CONFIG_ESP_SLEEP_POWER_DOWN_FLASH is not set
CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND=y
CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND=y
CONFIG_ESP_SLEEP_MSPI_NEED_ALL_IO_PU=y
CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y
CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND=y
@@ -1030,39 +1030,7 @@ CONFIG_PM_RESTORE_CACHE_TAGMEM_AFTER_LIGHT_SLEEP=y
#
# ESP PSRAM
#
CONFIG_SPIRAM=y
#
# SPI RAM config
#
CONFIG_SPIRAM_MODE_QUAD=y
# CONFIG_SPIRAM_MODE_OCT is not set
CONFIG_SPIRAM_TYPE_AUTO=y
# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set
CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y
CONFIG_SPIRAM_CLK_IO=30
CONFIG_SPIRAM_CS_IO=26
# CONFIG_SPIRAM_XIP_FROM_PSRAM is not set
# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set
# CONFIG_SPIRAM_RODATA is not set
# CONFIG_SPIRAM_SPEED_120M is not set
# CONFIG_SPIRAM_SPEED_80M is not set
CONFIG_SPIRAM_SPEED_40M=y
CONFIG_SPIRAM_SPEED=40
CONFIG_SPIRAM_BOOT_INIT=y
# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set
# CONFIG_SPIRAM_USE_MEMMAP is not set
# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
CONFIG_SPIRAM_USE_MALLOC=y
CONFIG_SPIRAM_MEMTEST=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384
# CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is not set
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768
# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
# CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY is not set
# end of SPI RAM config
# CONFIG_SPIRAM is not set
# end of ESP PSRAM
#
@@ -1216,9 +1184,9 @@ CONFIG_ESP_WIFI_ENABLED=y
CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=10
CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32
CONFIG_ESP_WIFI_STATIC_TX_BUFFER=y
# CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER is not set
CONFIG_ESP_WIFI_TX_BUFFER_TYPE=0
CONFIG_ESP_WIFI_STATIC_TX_BUFFER_NUM=16
CONFIG_ESP_WIFI_CACHE_TX_BUFFER_NUM=32
CONFIG_ESP_WIFI_STATIC_RX_MGMT_BUFFER=y
# CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUFFER is not set
CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF=0
@@ -1228,7 +1196,6 @@ CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP_WIFI_TX_BA_WIN=6
CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP_WIFI_RX_BA_WIN=6
# CONFIG_ESP_WIFI_AMSDU_TX_ENABLED is not set
CONFIG_ESP_WIFI_NVS_ENABLED=y
CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_0=y
# CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_1 is not set
@@ -1318,7 +1285,6 @@ CONFIG_FATFS_CODEPAGE=437
CONFIG_FATFS_FS_LOCK=0
CONFIG_FATFS_TIMEOUT_MS=10000
CONFIG_FATFS_PER_FILE_CACHE=y
CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y
# CONFIG_FATFS_USE_FASTSEEK is not set
CONFIG_FATFS_VFS_FSTAT_BLKSIZE=0
# CONFIG_FATFS_IMMEDIATE_FSYNC is not set
@@ -1623,7 +1589,6 @@ CONFIG_LWIP_HOOK_IP6_INPUT_NONE=y
# mbedTLS
#
CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
# CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set
# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
@@ -1786,8 +1751,6 @@ CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y
# CONFIG_NEWLIB_TIME_SYSCALL_USE_NONE is not set
# end of Newlib
CONFIG_STDATOMIC_S32C1I_SPIRAM_WORKAROUND=y
#
# NVS
#
@@ -2414,6 +2377,7 @@ CONFIG_POST_EVENTS_FROM_IRAM_ISR=y
CONFIG_GDBSTUB_SUPPORT_TASKS=y
CONFIG_GDBSTUB_MAX_TASKS=32
# CONFIG_OTA_ALLOW_HTTP is not set
# CONFIG_ESP_SYSTEM_PD_FLASH is not set
CONFIG_ESP32S3_DEEP_SLEEP_WAKEUP_DELAY=2000
CONFIG_ESP_SLEEP_DEEP_SLEEP_WAKEUP_DELAY=2000
CONFIG_ESP32S3_RTC_CLK_SRC_INT_RC=y
@@ -2429,9 +2393,7 @@ CONFIG_ESP32_PHY_MAX_TX_POWER=20
# CONFIG_ESP32_REDUCE_PHY_TX_POWER is not set
CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU=y
CONFIG_PM_POWER_DOWN_TAGMEM_IN_LIGHT_SLEEP=y
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_DEFAULT_PSRAM_CLK_IO=30
CONFIG_DEFAULT_PSRAM_CS_IO=26
# CONFIG_ESP32S3_SPIRAM_SUPPORT is not set
# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_80 is not set
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_160=y
# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240 is not set
@@ -2482,9 +2444,9 @@ CONFIG_ESP32_WIFI_ENABLED=y
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y
# CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER is not set
CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16
CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32
# CONFIG_ESP32_WIFI_CSI_ENABLED is not set
CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP32_WIFI_TX_BA_WIN=6
@@ -2492,7 +2454,6 @@ CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP32_WIFI_RX_BA_WIN=6
CONFIG_ESP32_WIFI_RX_BA_WIN=6
# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set
CONFIG_ESP32_WIFI_NVS_ENABLED=y
CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y
# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set