adding flasher

This commit is contained in:
Brent Perteet
2025-10-12 13:40:31 -05:00
parent a89fdc6843
commit 04d2c71d01
18 changed files with 1034 additions and 194 deletions

View File

@@ -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++) {

View File

@@ -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
{

View File

@@ -325,7 +325,8 @@ void app_main(void)
#else
while (1)
{
vTaskDelay(pdMS_TO_TICKS(1000));
system_processNvsRequests();
vTaskDelay(pdMS_TO_TICKS(10));
}
#endif
}

View File

@@ -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, &notification, 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, &notification, 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, &notification, 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;
}

View File

@@ -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