adding flasher
This commit is contained in:
227
main/bt_app.c
227
main/bt_app.c
@@ -109,24 +109,11 @@ static void bt_app_av_sm_hdlr(uint16_t event, void *param);
|
||||
/* utils for transfer BLuetooth Deveice Address into string form */
|
||||
static char *bda2str(esp_bd_addr_t bda, char *str, size_t size);
|
||||
|
||||
/* NVS storage functions for paired devices */
|
||||
typedef struct {
|
||||
esp_bd_addr_t bda;
|
||||
char name[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
|
||||
uint32_t last_connected;
|
||||
} paired_device_t;
|
||||
|
||||
static esp_err_t nvs_save_paired_device(const paired_device_t *device);
|
||||
static esp_err_t nvs_load_paired_devices(paired_device_t *devices, size_t *count);
|
||||
static esp_err_t nvs_remove_paired_device(esp_bd_addr_t bda);
|
||||
static bool nvs_is_device_known(esp_bd_addr_t bda);
|
||||
static esp_err_t nvs_get_known_device_count(size_t *count);
|
||||
static esp_err_t nvs_try_connect_known_devices(void);
|
||||
static void nvs_debug_print_known_devices(void);
|
||||
static esp_err_t nvs_add_discovered_device(esp_bd_addr_t bda, const char *name);
|
||||
static esp_err_t nvs_update_connection_timestamp(esp_bd_addr_t bda);
|
||||
static esp_err_t nvs_try_connect_all_known_devices(void);
|
||||
static esp_err_t nvs_try_next_known_device(void);
|
||||
static esp_err_t bt_try_connect_known_devices(void);
|
||||
static void bt_debug_print_known_devices(void);
|
||||
static esp_err_t bt_add_discovered_device(esp_bd_addr_t bda, const char *name);
|
||||
static esp_err_t bt_try_connect_all_known_devices(void);
|
||||
static esp_err_t bt_try_next_known_device(void);
|
||||
|
||||
/* A2DP application state machine handler for each state */
|
||||
static void bt_app_av_state_unconnected_hdlr(uint16_t event, void *param);
|
||||
@@ -167,145 +154,18 @@ static bool s_volume_control_available = false; /* Whether AVRC vo
|
||||
* NVS STORAGE FUNCTION DEFINITIONS
|
||||
********************************/
|
||||
|
||||
static esp_err_t nvs_save_paired_device(const paired_device_t *device)
|
||||
{
|
||||
nvs_handle_t nvs_handle;
|
||||
esp_err_t ret;
|
||||
size_t count = 0;
|
||||
char key[32];
|
||||
|
||||
if (!device) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ret = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(BT_AV_TAG, "Error opening NVS handle: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get current device count
|
||||
size_t required_size = sizeof(size_t);
|
||||
nvs_get_blob(nvs_handle, NVS_KEY_COUNT, &count, &required_size);
|
||||
|
||||
// Check if device already exists
|
||||
paired_device_t existing_devices[MAX_PAIRED_DEVICES];
|
||||
size_t existing_count = MAX_PAIRED_DEVICES;
|
||||
nvs_load_paired_devices(existing_devices, &existing_count);
|
||||
|
||||
int device_index = -1;
|
||||
for (int i = 0; i < existing_count; i++) {
|
||||
if (memcmp(existing_devices[i].bda, device->bda, ESP_BD_ADDR_LEN) == 0) {
|
||||
device_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If device not found and we have space, add it
|
||||
if (device_index == -1) {
|
||||
if (count >= MAX_PAIRED_DEVICES) {
|
||||
ESP_LOGW(BT_AV_TAG, "Maximum paired devices reached");
|
||||
nvs_close(nvs_handle);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
device_index = count;
|
||||
count++;
|
||||
}
|
||||
|
||||
// Save device data
|
||||
snprintf(key, sizeof(key), "%s%d", NVS_KEY_PREFIX, device_index);
|
||||
ret = nvs_set_blob(nvs_handle, key, device, sizeof(paired_device_t));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(BT_AV_TAG, "Error saving device: %s", esp_err_to_name(ret));
|
||||
nvs_close(nvs_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Save device count
|
||||
ret = nvs_set_blob(nvs_handle, NVS_KEY_COUNT, &count, sizeof(size_t));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(BT_AV_TAG, "Error saving device count: %s", esp_err_to_name(ret));
|
||||
nvs_close(nvs_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nvs_commit(nvs_handle);
|
||||
nvs_close(nvs_handle);
|
||||
|
||||
char bda_str[18];
|
||||
ESP_LOGI(BT_AV_TAG, "Saved paired device: %s (%s)",
|
||||
device->name, bda2str(device->bda, bda_str, sizeof(bda_str)));
|
||||
|
||||
return ret;
|
||||
}
|
||||
// This function is no longer used - replaced by system_savePairedDevice
|
||||
|
||||
static esp_err_t nvs_load_paired_devices(paired_device_t *devices, size_t *count)
|
||||
{
|
||||
nvs_handle_t nvs_handle;
|
||||
esp_err_t ret;
|
||||
size_t device_count = 0;
|
||||
char key[32];
|
||||
|
||||
if (!devices || !count || *count == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ret = nvs_open(NVS_NAMESPACE, NVS_READONLY, &nvs_handle);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGD(BT_AV_TAG, "NVS namespace not found (first run): %s", esp_err_to_name(ret));
|
||||
*count = 0;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// Get device count
|
||||
size_t required_size = sizeof(size_t);
|
||||
ret = nvs_get_blob(nvs_handle, NVS_KEY_COUNT, &device_count, &required_size);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGD(BT_AV_TAG, "No paired devices found");
|
||||
nvs_close(nvs_handle);
|
||||
*count = 0;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// Load each device
|
||||
size_t loaded = 0;
|
||||
for (int i = 0; i < device_count && loaded < *count; i++) {
|
||||
snprintf(key, sizeof(key), "%s%d", NVS_KEY_PREFIX, i);
|
||||
required_size = sizeof(paired_device_t);
|
||||
ret = nvs_get_blob(nvs_handle, key, &devices[loaded], &required_size);
|
||||
if (ret == ESP_OK) {
|
||||
loaded++;
|
||||
}
|
||||
}
|
||||
|
||||
nvs_close(nvs_handle);
|
||||
*count = loaded;
|
||||
return ESP_OK;
|
||||
}
|
||||
// This function is no longer used - replaced by system_loadPairedDevices
|
||||
|
||||
static bool nvs_is_device_known(esp_bd_addr_t bda)
|
||||
// This function is no longer used - replaced by system_isDeviceKnown
|
||||
|
||||
static esp_err_t bt_try_connect_known_devices(void)
|
||||
{
|
||||
paired_device_t devices[MAX_PAIRED_DEVICES];
|
||||
size_t count = MAX_PAIRED_DEVICES;
|
||||
|
||||
if (nvs_load_paired_devices(devices, &count) != ESP_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (memcmp(devices[i].bda, bda, ESP_BD_ADDR_LEN) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static esp_err_t nvs_try_connect_known_devices(void)
|
||||
{
|
||||
paired_device_t devices[MAX_PAIRED_DEVICES];
|
||||
size_t count = MAX_PAIRED_DEVICES;
|
||||
|
||||
esp_err_t ret = nvs_load_paired_devices(devices, &count);
|
||||
esp_err_t ret = system_loadPairedDevices(devices, &count);
|
||||
if (ret != ESP_OK || count == 0) {
|
||||
ESP_LOGI(BT_AV_TAG, "No known devices to connect to");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
@@ -355,14 +215,14 @@ static esp_err_t nvs_try_connect_known_devices(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void nvs_debug_print_known_devices(void)
|
||||
static void bt_debug_print_known_devices(void)
|
||||
{
|
||||
paired_device_t devices[MAX_PAIRED_DEVICES];
|
||||
size_t count = MAX_PAIRED_DEVICES;
|
||||
const paired_device_t* devices;
|
||||
size_t count = 0;
|
||||
|
||||
esp_err_t ret = nvs_load_paired_devices(devices, &count);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(BT_AV_TAG, "Failed to load devices for debug: %s", esp_err_to_name(ret));
|
||||
devices = system_getPairedDevices(&count);
|
||||
if (!devices) {
|
||||
ESP_LOGE(BT_AV_TAG, "Failed to load devices for debug");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -377,12 +237,12 @@ static void nvs_debug_print_known_devices(void)
|
||||
ESP_LOGI(BT_AV_TAG, "=== End Device List ===");
|
||||
}
|
||||
|
||||
static esp_err_t nvs_remove_paired_device(esp_bd_addr_t bda)
|
||||
static esp_err_t __attribute__((unused)) nvs_remove_paired_device(esp_bd_addr_t bda)
|
||||
{
|
||||
paired_device_t devices[MAX_PAIRED_DEVICES];
|
||||
size_t count = MAX_PAIRED_DEVICES;
|
||||
|
||||
esp_err_t ret = nvs_load_paired_devices(devices, &count);
|
||||
esp_err_t ret = system_loadPairedDevices(devices, &count);
|
||||
if (ret != ESP_OK || count == 0) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
@@ -438,7 +298,7 @@ static esp_err_t nvs_remove_paired_device(esp_bd_addr_t bda)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t nvs_get_known_device_count(size_t *count)
|
||||
static esp_err_t __attribute__((unused)) nvs_get_known_device_count(size_t *count)
|
||||
{
|
||||
if (!count) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@@ -462,14 +322,14 @@ static esp_err_t nvs_get_known_device_count(size_t *count)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t nvs_add_discovered_device(esp_bd_addr_t bda, const char *name)
|
||||
static esp_err_t bt_add_discovered_device(esp_bd_addr_t bda, const char *name)
|
||||
{
|
||||
if (!bda || !name) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Check if device is already known
|
||||
if (nvs_is_device_known(bda)) {
|
||||
if (system_isDeviceKnown(bda)) {
|
||||
char bda_str[18];
|
||||
ESP_LOGD(BT_AV_TAG, "Device %s (%s) already known, skipping",
|
||||
name, bda2str(bda, bda_str, sizeof(bda_str)));
|
||||
@@ -479,12 +339,12 @@ static esp_err_t nvs_add_discovered_device(esp_bd_addr_t bda, const char *name)
|
||||
// Create paired_device_t structure for discovered device
|
||||
paired_device_t device;
|
||||
memcpy(device.bda, bda, ESP_BD_ADDR_LEN);
|
||||
strncpy(device.name, name, ESP_BT_GAP_MAX_BDNAME_LEN);
|
||||
device.name[ESP_BT_GAP_MAX_BDNAME_LEN] = '\0';
|
||||
strncpy(device.name, name, DEVICE_NAME_MAX_LEN - 1);
|
||||
device.name[DEVICE_NAME_MAX_LEN - 1] = '\0';
|
||||
device.last_connected = 0; // Never connected, set to 0
|
||||
|
||||
// Save to NVS
|
||||
esp_err_t ret = nvs_save_paired_device(&device);
|
||||
esp_err_t ret = system_savePairedDevice(&device);
|
||||
if (ret == ESP_OK) {
|
||||
char bda_str[18];
|
||||
ESP_LOGI(BT_AV_TAG, "Added discovered device to NVS: %s (%s)",
|
||||
@@ -496,7 +356,7 @@ static esp_err_t nvs_add_discovered_device(esp_bd_addr_t bda, const char *name)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t nvs_update_connection_timestamp(esp_bd_addr_t bda)
|
||||
static esp_err_t __attribute__((unused)) nvs_update_connection_timestamp(esp_bd_addr_t bda)
|
||||
{
|
||||
if (!bda) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@@ -505,7 +365,7 @@ static esp_err_t nvs_update_connection_timestamp(esp_bd_addr_t bda)
|
||||
paired_device_t devices[MAX_PAIRED_DEVICES];
|
||||
size_t count = MAX_PAIRED_DEVICES;
|
||||
|
||||
esp_err_t ret = nvs_load_paired_devices(devices, &count);
|
||||
esp_err_t ret = system_loadPairedDevices(devices, &count);
|
||||
if (ret != ESP_OK || count == 0) {
|
||||
ESP_LOGW(BT_AV_TAG, "No devices found to update timestamp");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
@@ -529,7 +389,7 @@ static esp_err_t nvs_update_connection_timestamp(esp_bd_addr_t bda)
|
||||
devices[device_index].last_connected = (uint32_t)(esp_timer_get_time() / 1000000); // Convert to seconds
|
||||
|
||||
// Save updated device
|
||||
ret = nvs_save_paired_device(&devices[device_index]);
|
||||
ret = system_savePairedDevice(&devices[device_index]);
|
||||
if (ret == ESP_OK) {
|
||||
char bda_str[18];
|
||||
ESP_LOGI(BT_AV_TAG, "Updated connection timestamp for device: %s (%s)",
|
||||
@@ -541,11 +401,11 @@ static esp_err_t nvs_update_connection_timestamp(esp_bd_addr_t bda)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t nvs_try_connect_all_known_devices(void)
|
||||
static esp_err_t bt_try_connect_all_known_devices(void)
|
||||
{
|
||||
// Load all known devices into cache
|
||||
s_known_device_count = MAX_PAIRED_DEVICES;
|
||||
esp_err_t ret = nvs_load_paired_devices(s_known_devices, &s_known_device_count);
|
||||
esp_err_t ret = system_loadPairedDevices(s_known_devices, &s_known_device_count);
|
||||
if (ret != ESP_OK || s_known_device_count == 0) {
|
||||
ESP_LOGI(BT_AV_TAG, "No known devices to connect to");
|
||||
s_current_device_index = -1;
|
||||
@@ -587,7 +447,7 @@ static esp_err_t nvs_try_connect_all_known_devices(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t nvs_try_next_known_device(void)
|
||||
static esp_err_t bt_try_next_known_device(void)
|
||||
{
|
||||
if (s_current_device_index < 0 || s_known_device_count == 0) {
|
||||
ESP_LOGI(BT_AV_TAG, "No more devices to try");
|
||||
@@ -714,7 +574,7 @@ static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
|
||||
get_name_from_eir(eir, s_peer_bdname, NULL);
|
||||
|
||||
// Save discovered audio device to NVS (but don't connect to it)
|
||||
nvs_add_discovered_device(param->disc_res.bda, (char *)s_peer_bdname);
|
||||
bt_add_discovered_device(param->disc_res.bda, (char *)s_peer_bdname);
|
||||
|
||||
// Add to device list for GUI
|
||||
add_device_to_list(param->disc_res.bda, (char *)s_peer_bdname, false, rssi);
|
||||
@@ -754,7 +614,8 @@ static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
|
||||
} else {
|
||||
/* not discovered, continue to discover */
|
||||
ESP_LOGI(BT_AV_TAG, "Device discovery failed, continue to discover...");
|
||||
esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
|
||||
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
||||
//esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
|
||||
}
|
||||
} else if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STARTED) {
|
||||
ESP_LOGI(BT_AV_TAG, "Discovery started.");
|
||||
@@ -854,10 +715,10 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
|
||||
esp_bt_gap_get_device_name();
|
||||
|
||||
// Print list of saved devices from NVS
|
||||
nvs_debug_print_known_devices();
|
||||
bt_debug_print_known_devices();
|
||||
|
||||
// Try to connect to all known devices sequentially
|
||||
esp_err_t connect_ret = nvs_try_connect_all_known_devices();
|
||||
esp_err_t connect_ret = bt_try_connect_all_known_devices();
|
||||
if (connect_ret != ESP_OK) {
|
||||
// No known devices found, start discovery to find new devices
|
||||
ESP_LOGI(BT_AV_TAG, "No known devices found, starting discovery...");
|
||||
@@ -1222,7 +1083,8 @@ static void bt_app_av_state_unconnected_hdlr(uint16_t event, void *param)
|
||||
break;
|
||||
case BT_APP_HEART_BEAT_EVT: {
|
||||
// Try to connect to known devices, or start discovery if none available
|
||||
esp_err_t connect_ret = nvs_try_connect_all_known_devices();
|
||||
esp_err_t connect_ret = bt_try_connect_all_known_devices();
|
||||
|
||||
if (connect_ret != ESP_OK) {
|
||||
// No known devices, start discovery
|
||||
ESP_LOGI(BT_AV_TAG, "No known devices available, starting discovery...");
|
||||
@@ -1257,14 +1119,17 @@ static void bt_app_av_state_connecting_hdlr(uint16_t event, void *param)
|
||||
s_media_state = APP_AV_MEDIA_STATE_IDLE;
|
||||
|
||||
// Update connection timestamp for this device
|
||||
nvs_update_connection_timestamp(s_peer_bda);
|
||||
system_updateConnectionTimestamp(s_peer_bda);
|
||||
} else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
|
||||
ESP_LOGI(BT_AV_TAG, "Connection failed, trying next device...");
|
||||
// Try next known device before giving up
|
||||
esp_err_t next_ret = nvs_try_next_known_device();
|
||||
esp_err_t next_ret = bt_try_next_known_device();
|
||||
if (next_ret != ESP_OK) {
|
||||
// No more devices to try, go to unconnected state
|
||||
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
||||
//s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
||||
ESP_LOGI(BT_AV_TAG, "No known devices available, starting discovery...");
|
||||
s_a2d_state = APP_AV_STATE_DISCOVERING;
|
||||
esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1281,7 +1146,7 @@ static void bt_app_av_state_connecting_hdlr(uint16_t event, void *param)
|
||||
if (++s_connecting_intv >= 2) {
|
||||
ESP_LOGI(BT_AV_TAG, "Connection timeout, trying next device...");
|
||||
// Try next known device before giving up
|
||||
esp_err_t next_ret = nvs_try_next_known_device();
|
||||
esp_err_t next_ret = bt_try_next_known_device();
|
||||
if (next_ret != ESP_OK) {
|
||||
// No more devices to try, go to unconnected state
|
||||
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
||||
@@ -1834,7 +1699,7 @@ static void load_paired_devices_to_list(void) {
|
||||
size_t count = MAX_PAIRED_DEVICES;
|
||||
|
||||
ESP_LOGI(BT_AV_TAG, "Attempting to load paired devices from NVS");
|
||||
esp_err_t err = nvs_load_paired_devices(paired_devices, &count);
|
||||
esp_err_t err = system_loadPairedDevices(paired_devices, &count);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(BT_AV_TAG, "Successfully loaded %d paired devices from NVS", (int)count);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
|
||||
101
main/gui.c
101
main/gui.c
@@ -72,6 +72,13 @@ static lv_obj_t* create_volume_page(void);
|
||||
static void update_volume_display(int volume);
|
||||
static void ensure_menu_styles(void);
|
||||
|
||||
// Menu stack management functions
|
||||
static void menu_stack_push(lv_obj_t *page);
|
||||
static lv_obj_t* menu_stack_pop(void);
|
||||
static void menu_stack_clear(void);
|
||||
static bool menu_stack_is_empty(void);
|
||||
static void menu_go_back(void);
|
||||
|
||||
#define MAX_ITEMS 10
|
||||
#define VISIBLE_ITEMS 3
|
||||
#define MENU_MAX_STRING_LENGTH 30
|
||||
@@ -91,6 +98,15 @@ static lv_obj_t *_currentPage = NULL;
|
||||
|
||||
static GuiMode_t _mode = GUI_BUBBLE;
|
||||
|
||||
// Menu navigation stack
|
||||
#define MAX_MENU_STACK_SIZE 8
|
||||
typedef struct {
|
||||
lv_obj_t *pages[MAX_MENU_STACK_SIZE];
|
||||
int count;
|
||||
} menu_stack_t;
|
||||
|
||||
static menu_stack_t _menuStack = {0};
|
||||
|
||||
/* 1. Prepare a default (unfocused) style */
|
||||
static lv_style_t _styleUnfocusedBtn;
|
||||
|
||||
@@ -135,6 +151,9 @@ static void show_menu(void) {
|
||||
lv_obj_t* menu = create_menu_container();
|
||||
lv_obj_t* main_page = create_main_page();
|
||||
|
||||
// Clear the menu stack when starting fresh menu navigation
|
||||
menu_stack_clear();
|
||||
|
||||
lv_menu_set_page(menu, main_page);
|
||||
_currentPage = main_page;
|
||||
|
||||
@@ -180,7 +199,8 @@ static void lcd_init(void)
|
||||
.miso_io_num = -1,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = LCD_H_RES * LCD_V_RES * 2
|
||||
//.max_transfer_sz = LCD_H_RES * LCD_V_RES * 2
|
||||
.max_transfer_sz = LCD_H_RES * 25 * (LCD_BITS_PER_PIXEL/8),
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(LCD_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
@@ -236,7 +256,8 @@ static void lvgl_init(void)
|
||||
const lvgl_port_display_cfg_t disp_cfg = {
|
||||
.io_handle = io_handle,
|
||||
.panel_handle = panel_handle,
|
||||
.buffer_size = LCD_H_RES * LCD_V_RES * 2,
|
||||
// .buffer_size = LCD_H_RES * LCD_V_RES * 2,
|
||||
.buffer_size = LCD_H_RES * 25 * (LCD_BITS_PER_PIXEL/8), // was full screen
|
||||
.double_buffer = false,
|
||||
.hres = LCD_H_RES,
|
||||
.vres = LCD_V_RES,
|
||||
@@ -347,12 +368,20 @@ static void btn_click_cb(lv_event_t * e) {
|
||||
// Handle specific menu items
|
||||
if (strcmp(txt, "Bluetooth") == 0) {
|
||||
LOCK();
|
||||
// Push current page onto stack before navigating
|
||||
menu_stack_push(_currentPage);
|
||||
show_bt_device_list();
|
||||
UNLOCK();
|
||||
} else if (strcmp(txt, "Volume") == 0) {
|
||||
LOCK();
|
||||
// Push current page onto stack before navigating
|
||||
menu_stack_push(_currentPage);
|
||||
show_volume_control();
|
||||
UNLOCK();
|
||||
} else if (strcmp(txt, "Back") == 0) {
|
||||
LOCK();
|
||||
menu_go_back();
|
||||
UNLOCK();
|
||||
} else if (strcmp(txt, "Exit") == 0) {
|
||||
LOCK();
|
||||
_mode = GUI_BUBBLE;
|
||||
@@ -609,8 +638,7 @@ static void bt_device_click_cb(lv_event_t * e) {
|
||||
if (strcmp(txt, "Back") == 0) {
|
||||
LOCK();
|
||||
bt_stop_discovery();
|
||||
_mode = GUI_MENU;
|
||||
show_menu();
|
||||
menu_go_back();
|
||||
UNLOCK();
|
||||
return;
|
||||
} else if (strcmp(txt, "Refresh") == 0) {
|
||||
@@ -803,6 +831,10 @@ static lv_obj_t* create_volume_page(void) {
|
||||
lv_obj_align(instr2, LV_ALIGN_BOTTOM_MID, 0, -10);
|
||||
#endif
|
||||
|
||||
// Add Back button
|
||||
lv_obj_t* back_btn = addMenuItem(_volume_page, "Back");
|
||||
lv_obj_add_event_cb(back_btn, btn_click_cb, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
return _volume_page;
|
||||
}
|
||||
|
||||
@@ -831,6 +863,64 @@ static void show_volume_control(void) {
|
||||
ESP_LOGI(TAG, "Volume control displayed");
|
||||
}
|
||||
|
||||
// Menu stack management functions
|
||||
static void menu_stack_push(lv_obj_t *page) {
|
||||
if (_menuStack.count < MAX_MENU_STACK_SIZE && page != NULL) {
|
||||
_menuStack.pages[_menuStack.count++] = page;
|
||||
ESP_LOGI(TAG, "Menu stack push: page=%p, count=%d", page, _menuStack.count);
|
||||
} else if (_menuStack.count >= MAX_MENU_STACK_SIZE) {
|
||||
ESP_LOGW(TAG, "Menu stack overflow, cannot push more pages");
|
||||
}
|
||||
}
|
||||
|
||||
static lv_obj_t* menu_stack_pop(void) {
|
||||
if (_menuStack.count > 0) {
|
||||
lv_obj_t *page = _menuStack.pages[--_menuStack.count];
|
||||
ESP_LOGI(TAG, "Menu stack pop: page=%p, count=%d", page, _menuStack.count);
|
||||
return page;
|
||||
}
|
||||
ESP_LOGI(TAG, "Menu stack is empty, cannot pop");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void menu_stack_clear(void) {
|
||||
_menuStack.count = 0;
|
||||
ESP_LOGI(TAG, "Menu stack cleared");
|
||||
}
|
||||
|
||||
static bool menu_stack_is_empty(void) {
|
||||
return (_menuStack.count == 0);
|
||||
}
|
||||
|
||||
static void menu_go_back(void) {
|
||||
ESP_LOGI(TAG, "Menu go back requested");
|
||||
|
||||
if (menu_stack_is_empty()) {
|
||||
ESP_LOGI(TAG, "Menu stack empty, returning to bubble mode");
|
||||
_mode = GUI_BUBBLE;
|
||||
show_bubble();
|
||||
return;
|
||||
}
|
||||
|
||||
lv_obj_t *previous_page = menu_stack_pop();
|
||||
if (previous_page != NULL) {
|
||||
ESP_LOGI(TAG, "Returning to previous menu page");
|
||||
lv_obj_t* menu = create_menu_container();
|
||||
if (menu) {
|
||||
lv_menu_set_page(menu, previous_page);
|
||||
_currentPage = previous_page;
|
||||
_mode = GUI_MENU;
|
||||
|
||||
lv_obj_remove_flag(menu, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGI(TAG, "No previous page found, returning to bubble mode");
|
||||
_mode = GUI_BUBBLE;
|
||||
show_bubble();
|
||||
}
|
||||
}
|
||||
|
||||
static void update_volume_display(int volume) {
|
||||
if (_volume_bar && _volume_label) {
|
||||
LOCK();
|
||||
@@ -1029,8 +1119,7 @@ static void gui_task(void *pvParameters)
|
||||
LOCK();
|
||||
if (_mode == GUI_MENU)
|
||||
{
|
||||
_mode = GUI_BUBBLE;
|
||||
show_bubble(); // Cleanup menu and show bubble
|
||||
menu_go_back(); // Use menu stack navigation
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -325,7 +325,8 @@ void app_main(void)
|
||||
#else
|
||||
while (1)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
system_processNvsRequests();
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
281
main/system.c
281
main/system.c
@@ -1,20 +1,34 @@
|
||||
#include "system.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs.h"
|
||||
#include "esp_timer.h"
|
||||
#include <string.h>
|
||||
|
||||
static SystemState_t _systemState;
|
||||
|
||||
static EventGroupHandle_t _systemEvent;
|
||||
static EventManager_t _eventManager;
|
||||
|
||||
static QueueHandle_t _nvsRequestQueue;
|
||||
static const char* NVS_NAMESPACE = "bt_devices";
|
||||
static const char* NVS_KEY_COUNT = "count";
|
||||
|
||||
static esp_err_t nvs_load_devices_internal(paired_device_t *devices, size_t *count);
|
||||
static esp_err_t nvs_save_devices_internal(const paired_device_t *devices, size_t count);
|
||||
|
||||
void system_init(void)
|
||||
{
|
||||
_systemState.zeroAngle = 0.0f;
|
||||
_systemState.primaryAxis = PRIMARY_AXIS;
|
||||
_systemState.pairedDeviceCount = 0;
|
||||
|
||||
_systemEvent = xEventGroupCreate();
|
||||
|
||||
_eventManager.count = 0;
|
||||
_eventManager.mutex = xSemaphoreCreateMutex();
|
||||
|
||||
system_initNvsService();
|
||||
}
|
||||
|
||||
int system_getPrimaryAxis(void)
|
||||
@@ -198,4 +212,271 @@ void system_requestVolumeUp(void) {
|
||||
void system_requestVolumeDown(void) {
|
||||
ESP_LOGI("system", "Volume Down requested");
|
||||
system_notifyAll(EM_EVENT_VOLUME_DOWN);
|
||||
}
|
||||
|
||||
void system_initNvsService(void) {
|
||||
_nvsRequestQueue = xQueueCreate(10, sizeof(nvs_request_t));
|
||||
if (_nvsRequestQueue == NULL) {
|
||||
ESP_LOGE("system", "Failed to create NVS request queue");
|
||||
}
|
||||
|
||||
memset(_systemState.pairedDevices, 0, sizeof(_systemState.pairedDevices));
|
||||
_systemState.pairedDeviceCount = 0;
|
||||
|
||||
paired_device_t devices[MAX_PAIRED_DEVICES];
|
||||
size_t count = 0;
|
||||
if (nvs_load_devices_internal(devices, &count) == ESP_OK) {
|
||||
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||
memcpy(_systemState.pairedDevices, devices, count * sizeof(paired_device_t));
|
||||
_systemState.pairedDeviceCount = count;
|
||||
xSemaphoreGive(_eventManager.mutex);
|
||||
ESP_LOGI("system", "Loaded %d paired devices from NVS", count);
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t nvs_load_devices_internal(paired_device_t *devices, size_t *count) {
|
||||
nvs_handle_t nvs_handle;
|
||||
esp_err_t ret;
|
||||
|
||||
ret = nvs_open(NVS_NAMESPACE, NVS_READONLY, &nvs_handle);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE("system", "Failed to open NVS namespace: %s", esp_err_to_name(ret));
|
||||
*count = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t device_count = 0;
|
||||
size_t required_size = sizeof(size_t);
|
||||
ret = nvs_get_blob(nvs_handle, NVS_KEY_COUNT, &device_count, &required_size);
|
||||
if (ret != ESP_OK) {
|
||||
nvs_close(nvs_handle);
|
||||
*count = 0;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
device_count = (device_count > MAX_PAIRED_DEVICES) ? MAX_PAIRED_DEVICES : device_count;
|
||||
|
||||
for (size_t i = 0; i < device_count; i++) {
|
||||
char key[16];
|
||||
snprintf(key, sizeof(key), "device_%zu", i);
|
||||
required_size = sizeof(paired_device_t);
|
||||
ret = nvs_get_blob(nvs_handle, key, &devices[i], &required_size);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW("system", "Failed to load device %zu", i);
|
||||
device_count = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nvs_close(nvs_handle);
|
||||
*count = device_count;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t nvs_save_devices_internal(const paired_device_t *devices, size_t count) {
|
||||
nvs_handle_t nvs_handle;
|
||||
esp_err_t ret;
|
||||
|
||||
ret = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE("system", "Failed to open NVS namespace for write: %s", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nvs_set_blob(nvs_handle, NVS_KEY_COUNT, &count, sizeof(size_t));
|
||||
if (ret != ESP_OK) {
|
||||
nvs_close(nvs_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
char key[16];
|
||||
snprintf(key, sizeof(key), "device_%zu", i);
|
||||
ret = nvs_set_blob(nvs_handle, key, &devices[i], sizeof(paired_device_t));
|
||||
if (ret != ESP_OK) {
|
||||
nvs_close(nvs_handle);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = nvs_commit(nvs_handle);
|
||||
nvs_close(nvs_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void system_processNvsRequests(void) {
|
||||
nvs_request_t request;
|
||||
|
||||
while (xQueueReceive(_nvsRequestQueue, &request, 0) == pdTRUE) {
|
||||
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||
switch (request.operation) {
|
||||
case NVS_OP_SAVE_DEVICE:
|
||||
request.result = nvs_save_devices_internal(_systemState.pairedDevices, _systemState.pairedDeviceCount);
|
||||
break;
|
||||
|
||||
case NVS_OP_LOAD_DEVICES:
|
||||
request.result = nvs_load_devices_internal(_systemState.pairedDevices, &_systemState.pairedDeviceCount);
|
||||
break;
|
||||
|
||||
case NVS_OP_REMOVE_DEVICE: {
|
||||
size_t removed_index = SIZE_MAX;
|
||||
for (size_t i = 0; i < _systemState.pairedDeviceCount; i++) {
|
||||
if (memcmp(_systemState.pairedDevices[i].bda, request.bda, ESP_BD_ADDR_LEN) == 0) {
|
||||
removed_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed_index != SIZE_MAX) {
|
||||
for (size_t i = removed_index; i < _systemState.pairedDeviceCount - 1; i++) {
|
||||
_systemState.pairedDevices[i] = _systemState.pairedDevices[i + 1];
|
||||
}
|
||||
_systemState.pairedDeviceCount--;
|
||||
request.result = nvs_save_devices_internal(_systemState.pairedDevices, _systemState.pairedDeviceCount);
|
||||
} else {
|
||||
request.result = ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case NVS_OP_UPDATE_TIMESTAMP: {
|
||||
for (size_t i = 0; i < _systemState.pairedDeviceCount; i++) {
|
||||
if (memcmp(_systemState.pairedDevices[i].bda, request.bda, ESP_BD_ADDR_LEN) == 0) {
|
||||
_systemState.pairedDevices[i].last_connected = (uint32_t)(esp_timer_get_time() / 1000000);
|
||||
request.result = nvs_save_devices_internal(_systemState.pairedDevices, _systemState.pairedDeviceCount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
request.result = ESP_ERR_INVALID_ARG;
|
||||
break;
|
||||
}
|
||||
xSemaphoreGive(_eventManager.mutex);
|
||||
|
||||
request.response_ready = true;
|
||||
if (request.requestor) {
|
||||
xTaskNotify(request.requestor, (uint32_t)&request, eSetValueWithOverwrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t system_savePairedDevice(const paired_device_t *device) {
|
||||
if (!device) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||
|
||||
size_t existing_index = SIZE_MAX;
|
||||
for (size_t i = 0; i < _systemState.pairedDeviceCount; i++) {
|
||||
if (memcmp(_systemState.pairedDevices[i].bda, device->bda, ESP_BD_ADDR_LEN) == 0) {
|
||||
existing_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (existing_index != SIZE_MAX) {
|
||||
_systemState.pairedDevices[existing_index] = *device;
|
||||
} else if (_systemState.pairedDeviceCount < MAX_PAIRED_DEVICES) {
|
||||
_systemState.pairedDevices[_systemState.pairedDeviceCount++] = *device;
|
||||
} else {
|
||||
xSemaphoreGive(_eventManager.mutex);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
xSemaphoreGive(_eventManager.mutex);
|
||||
|
||||
nvs_request_t request = {
|
||||
.operation = NVS_OP_SAVE_DEVICE,
|
||||
.device = *device,
|
||||
.requestor = xTaskGetCurrentTaskHandle()
|
||||
};
|
||||
|
||||
if (xQueueSend(_nvsRequestQueue, &request, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) {
|
||||
uint32_t notification;
|
||||
if (xTaskNotifyWait(0, UINT32_MAX, ¬ification, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) {
|
||||
nvs_request_t *response = (nvs_request_t*)notification;
|
||||
return response->result;
|
||||
}
|
||||
}
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
esp_err_t system_loadPairedDevices(paired_device_t *devices, size_t *count) {
|
||||
if (!devices || !count) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||
size_t copy_count = (*count < _systemState.pairedDeviceCount) ? *count : _systemState.pairedDeviceCount;
|
||||
memcpy(devices, _systemState.pairedDevices, copy_count * sizeof(paired_device_t));
|
||||
*count = copy_count;
|
||||
xSemaphoreGive(_eventManager.mutex);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t system_removePairedDevice(esp_bd_addr_t bda) {
|
||||
nvs_request_t request = {
|
||||
.operation = NVS_OP_REMOVE_DEVICE,
|
||||
.requestor = xTaskGetCurrentTaskHandle()
|
||||
};
|
||||
memcpy(request.bda, bda, ESP_BD_ADDR_LEN);
|
||||
|
||||
if (xQueueSend(_nvsRequestQueue, &request, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) {
|
||||
uint32_t notification;
|
||||
if (xTaskNotifyWait(0, UINT32_MAX, ¬ification, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) {
|
||||
nvs_request_t *response = (nvs_request_t*)notification;
|
||||
return response->result;
|
||||
}
|
||||
}
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
bool system_isDeviceKnown(esp_bd_addr_t bda) {
|
||||
bool known = false;
|
||||
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||
for (size_t i = 0; i < _systemState.pairedDeviceCount; i++) {
|
||||
if (memcmp(_systemState.pairedDevices[i].bda, bda, ESP_BD_ADDR_LEN) == 0) {
|
||||
known = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(_eventManager.mutex);
|
||||
return known;
|
||||
}
|
||||
|
||||
esp_err_t system_getKnownDeviceCount(size_t *count) {
|
||||
if (!count) return ESP_ERR_INVALID_ARG;
|
||||
|
||||
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||
*count = _systemState.pairedDeviceCount;
|
||||
xSemaphoreGive(_eventManager.mutex);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t system_updateConnectionTimestamp(esp_bd_addr_t bda) {
|
||||
nvs_request_t request = {
|
||||
.operation = NVS_OP_UPDATE_TIMESTAMP,
|
||||
.requestor = xTaskGetCurrentTaskHandle()
|
||||
};
|
||||
memcpy(request.bda, bda, ESP_BD_ADDR_LEN);
|
||||
|
||||
if (xQueueSend(_nvsRequestQueue, &request, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) {
|
||||
uint32_t notification;
|
||||
if (xTaskNotifyWait(0, UINT32_MAX, ¬ification, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) {
|
||||
nvs_request_t *response = (nvs_request_t*)notification;
|
||||
return response->result;
|
||||
}
|
||||
}
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
const paired_device_t* system_getPairedDevices(size_t *count) {
|
||||
if (!count) return NULL;
|
||||
|
||||
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||
*count = _systemState.pairedDeviceCount;
|
||||
xSemaphoreGive(_eventManager.mutex);
|
||||
|
||||
return (const paired_device_t*)_systemState.pairedDevices;
|
||||
}
|
||||
@@ -4,9 +4,22 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_bt_defs.h"
|
||||
|
||||
#define DISABLE_GUI
|
||||
|
||||
#define MAX_PAIRED_DEVICES 10
|
||||
#define DEVICE_NAME_MAX_LEN 32
|
||||
|
||||
// Forward declaration of paired_device_t
|
||||
typedef struct {
|
||||
char name[DEVICE_NAME_MAX_LEN];
|
||||
esp_bd_addr_t bda;
|
||||
uint32_t last_connected;
|
||||
bool is_connected;
|
||||
} paired_device_t;
|
||||
|
||||
enum
|
||||
{
|
||||
ANGLE_XY = 0,
|
||||
@@ -34,6 +47,10 @@ typedef struct SystemState_s
|
||||
|
||||
// BT event data
|
||||
int btDeviceIndex;
|
||||
|
||||
// NVS cached data
|
||||
paired_device_t pairedDevices[MAX_PAIRED_DEVICES];
|
||||
size_t pairedDeviceCount;
|
||||
|
||||
} SystemState_t;
|
||||
|
||||
@@ -88,5 +105,36 @@ int system_getBtDeviceIndex(void);
|
||||
void system_requestVolumeUp(void);
|
||||
void system_requestVolumeDown(void);
|
||||
|
||||
// NVS Service
|
||||
typedef enum {
|
||||
NVS_OP_SAVE_DEVICE,
|
||||
NVS_OP_LOAD_DEVICES,
|
||||
NVS_OP_REMOVE_DEVICE,
|
||||
NVS_OP_IS_DEVICE_KNOWN,
|
||||
NVS_OP_GET_DEVICE_COUNT,
|
||||
NVS_OP_UPDATE_TIMESTAMP
|
||||
} nvs_operation_type_t;
|
||||
|
||||
typedef struct {
|
||||
nvs_operation_type_t operation;
|
||||
paired_device_t device;
|
||||
esp_bd_addr_t bda;
|
||||
TaskHandle_t requestor;
|
||||
esp_err_t result;
|
||||
bool response_ready;
|
||||
} nvs_request_t;
|
||||
|
||||
void system_initNvsService(void);
|
||||
void system_processNvsRequests(void);
|
||||
esp_err_t system_savePairedDevice(const paired_device_t *device);
|
||||
esp_err_t system_loadPairedDevices(paired_device_t *devices, size_t *count);
|
||||
esp_err_t system_removePairedDevice(esp_bd_addr_t bda);
|
||||
bool system_isDeviceKnown(esp_bd_addr_t bda);
|
||||
esp_err_t system_getKnownDeviceCount(size_t *count);
|
||||
esp_err_t system_updateConnectionTimestamp(esp_bd_addr_t bda);
|
||||
const paired_device_t* system_getPairedDevices(size_t *count);
|
||||
|
||||
|
||||
#define NVS_TIMEOUT_MS 5000
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user