Add mutexes for I2C access in multiple drivers and update cursor handling in char_lcd and wires. Adjust task stack sizes for better resource management.
This commit is contained in:
parent
da781c23f1
commit
dcd4f5bb62
@ -729,7 +729,9 @@ 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;
|
||||
}
|
||||
|
||||
@ -76,6 +76,7 @@ void init_bottom_half() {
|
||||
|
||||
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, ®, 1, buf, 1, (100 / portTICK_PERIOD_MS));
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(result);
|
||||
if (result != ESP_OK) {
|
||||
@ -85,10 +86,11 @@ static uint8_t receive_delta(void) {
|
||||
}
|
||||
|
||||
static void receive_keypad(void) {
|
||||
// TODO: use mutex
|
||||
// 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, ®, 1, buf, 2, (100 / portTICK_PERIOD_MS));
|
||||
xSemaphoreGive(main_i2c_mutex);
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(result);
|
||||
if (result != ESP_OK) {
|
||||
return;
|
||||
@ -117,7 +119,9 @@ static void receive_keypad(void) {
|
||||
|
||||
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, ®, 1, buf, 2, (100 / portTICK_PERIOD_MS));
|
||||
xSemaphoreGive(main_i2c_mutex);
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(result);
|
||||
if (result != ESP_OK) {
|
||||
return;
|
||||
@ -188,7 +192,9 @@ 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, ®, 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;
|
||||
|
||||
@ -11,6 +11,10 @@
|
||||
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";
|
||||
@ -147,6 +151,8 @@ void lcd_set_cursor_vis(bool cursor, bool no_lock) {
|
||||
}
|
||||
if (!no_lock) xSemaphoreGive(lcd_mutex);
|
||||
|
||||
cursor_visible = cursor;
|
||||
|
||||
if (is_state_tracking()) {
|
||||
event_occured("LCD_CURSOR_VIS", cursor ? "true" : "false");
|
||||
}
|
||||
@ -249,6 +255,11 @@ 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);
|
||||
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()) {
|
||||
@ -311,3 +322,17 @@ bool lcd_lock(uint32_t 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;
|
||||
}
|
||||
@ -79,4 +79,18 @@ 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();
|
||||
|
||||
#endif /* CHAR_LCD_H */
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
#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";
|
||||
|
||||
@ -120,10 +124,10 @@ void HWData1::load(nvs_handle_t handle) {
|
||||
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<Shape>(tmp);
|
||||
if (nvs_get_u8(handle, "shape2", &tmp) == ESP_OK) shape2 = static_cast<Shape>(tmp);
|
||||
if (nvs_get_u8(handle, "shape3", &tmp) == ESP_OK) shape3 = static_cast<Shape>(tmp);
|
||||
if (nvs_get_u8(handle, "shape4", &tmp) == ESP_OK) shape4 = static_cast<Shape>(tmp);
|
||||
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;
|
||||
@ -135,4 +139,356 @@ void HWData1::load(nvs_handle_t handle) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,19 @@
|
||||
#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,
|
||||
@ -23,6 +36,17 @@ enum class SSegColor : uint8_t {
|
||||
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,
|
||||
@ -34,6 +58,15 @@ enum class LCDColor : uint8_t {
|
||||
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,
|
||||
@ -43,6 +76,14 @@ enum class ButtonType : uint8_t {
|
||||
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,
|
||||
@ -51,6 +92,14 @@ enum class TFTType : uint8_t {
|
||||
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,
|
||||
@ -59,7 +108,21 @@ enum class BatType : uint8_t {
|
||||
LIPO = 4,
|
||||
};
|
||||
|
||||
enum class Shape : uint8_t {
|
||||
#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,
|
||||
@ -74,6 +137,7 @@ enum class Shape : uint8_t {
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// @brief Version 1 of HWData, kept constant for migrations
|
||||
struct HWData1 {
|
||||
std::string serial_num;
|
||||
@ -95,10 +159,10 @@ struct HWData1 {
|
||||
BatType bat_type;
|
||||
uint16_t bat_cap;
|
||||
|
||||
Shape shape1;
|
||||
Shape shape2;
|
||||
Shape shape3;
|
||||
Shape shape4;
|
||||
ShapeType shape1;
|
||||
ShapeType shape2;
|
||||
ShapeType shape3;
|
||||
ShapeType shape4;
|
||||
|
||||
bool has_speaker;
|
||||
bool has_mic;
|
||||
@ -130,4 +194,6 @@ struct HWData {
|
||||
static HWData load(nvs_handle_t handle);
|
||||
};
|
||||
|
||||
void hardware_config();
|
||||
|
||||
#endif /* HWDATA_H */
|
||||
|
||||
@ -76,3 +76,25 @@ void lcd_print_header_bat() {
|
||||
|
||||
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);
|
||||
// }
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include "drivers/bottom_half.h"
|
||||
#include "char_lcd.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
static const char* TAG = "star_code";
|
||||
|
||||
@ -14,7 +15,7 @@ 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_sem;
|
||||
static volatile SemaphoreHandle_t star_codes_mutex;
|
||||
static std::vector<StarCodeEntry> star_codes;
|
||||
|
||||
static const char EMPTY_STAR_CODE_HEADER[] = " ";
|
||||
@ -29,10 +30,19 @@ static uint16_t starcode_waiting_on_release;
|
||||
static char current[STARCODE_MAX_LEN + 1];
|
||||
static size_t current_idx;
|
||||
|
||||
static void starcode_trigger_cb(void* arg) {
|
||||
// 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, ¬ification_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)
|
||||
@ -42,10 +52,18 @@ static void starcode_trigger_cb(void* arg) {
|
||||
|
||||
current_starcode = nullptr;
|
||||
}
|
||||
|
||||
// TODO: rename star code everywhere to starcode
|
||||
lcd_print_header();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -91,8 +109,9 @@ void star_code_handle_keypad(uint16_t* just_pressed, uint16_t* just_released) {
|
||||
}
|
||||
|
||||
void init_star_code_system() {
|
||||
star_codes_sem = xSemaphoreCreateBinary();
|
||||
xSemaphoreGive(star_codes_sem);
|
||||
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,
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
|
||||
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};
|
||||
@ -41,6 +44,10 @@ void init_wires(void) {
|
||||
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,26 +99,34 @@ void strike(const char* reason) {
|
||||
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, ®, 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, ®, 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, ®, 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;
|
||||
@ -123,7 +138,9 @@ 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, ®, 1, buf, 1, (100 / portTICK_PERIOD_MS)));
|
||||
xSemaphoreGive(wires_i2c_mutex);
|
||||
bool new_button = buf[0] != 0;
|
||||
|
||||
bool just_pressed = new_button & !button_state;
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
#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"
|
||||
@ -16,6 +18,9 @@
|
||||
#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
|
||||
|
||||
|
||||
@ -23,8 +23,8 @@ void print_wires(WireColor* wires, int editing_idx) {
|
||||
}
|
||||
lcd_print(3, 1, string_buf);
|
||||
|
||||
// TODO: find a way to indicate without a cursor.
|
||||
// lcd_set_cursor_pos(editing_idx+1, 1);
|
||||
lcd_set_cursor_vis(true);
|
||||
lcd_set_cursor_resting_position(1, editing_idx+1);
|
||||
}
|
||||
|
||||
void setup_wires(void) {
|
||||
|
||||
@ -34,9 +34,6 @@ static void battery_stats() {
|
||||
vTaskDelete(xHandle);
|
||||
}
|
||||
}
|
||||
static void hardware_config() {
|
||||
|
||||
}
|
||||
|
||||
// TODO: remove. This is temperary
|
||||
static void replay_last() {
|
||||
@ -224,8 +221,8 @@ 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];
|
||||
// TODO: find some way to indicate without a cursor.
|
||||
// lcd_set_cursor_pos(mapped_cursor_pos, 1);
|
||||
|
||||
lcd_set_cursor_resting_position(1, mapped_cursor_pos);
|
||||
}
|
||||
|
||||
static void set_game_time() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user