diff --git a/.vscode/settings.json b/.vscode/settings.json index 79d5521..621ceb7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,10 +1,11 @@ { "C_Cpp.intelliSenseEngine": "default", + "idf.projectName": "soundshot", "idf.espIdfPathWin": "C:\\Users\\Brent.Perteet\\esp\\v5.4.1\\esp-idf", "idf.openOcdConfigs": [ "board/esp32-wrover-kit-3.3v.cfg" ], - "idf.portWin": "COM14", + "idf.portWin": "COM3", "idf.toolsPathWin": "C:\\Users\\Brent.Perteet\\.espressif", "idf.flashType": "UART", "files.associations": { @@ -37,7 +38,8 @@ "lv_slider.h": "c", "lv_menu.h": "c", "stdint.h": "c", - "random": "c" + "random": "c", + "string.h": "c" }, "git.ignoreLimitWarning": true, "idf.pythonInstallPath": "C:\\Users\\Brent.Perteet\\.espressif\\tools\\idf-python\\3.11.2\\python.exe", diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 855897c..6825f82 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -2,11 +2,12 @@ idf_component_register(SRCS "battery.c" "bt_app.c" "system.c" "bubble.c" "keypad "gui.c" "lsm6dsv.c" INCLUDE_DIRS "." - REQUIRES "driver" - "esp_lcd" - "lvgl" + REQUIRES "driver" + "esp_lcd" + "lvgl" "esp_lvgl_port" "esp_timer" "nvs_flash" - "bt") + "bt" + "esp_adc") diff --git a/main/battery.c b/main/battery.c index a071d33..2e95ad0 100644 --- a/main/battery.c +++ b/main/battery.c @@ -7,6 +7,7 @@ #include "esp_adc/adc_cali_scheme.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "driver/gpio.h" static const char *TAG = "battery"; @@ -177,23 +178,89 @@ int battery_get_percentage(void) static void battery_monitoring_task(void *pvParameters) { ESP_LOGI(TAG, "Battery monitoring task started"); + bool led_toggle = false; + int loop_count = 0; + int voltage_mv = 0; + bool is_charging = false; - while (1) { - int voltage_mv = battery_read_voltage_mv(); - int percentage = battery_get_percentage(); + while (1) + { + // Read voltage every 20 iterations (5000ms) + if (loop_count % 20 == 0) { + voltage_mv = battery_read_voltage_mv(); + int percentage = battery_get_percentage(); - if (voltage_mv >= 0 && percentage >= 0) { - // Update system state with battery info - system_setBatteryVoltage(voltage_mv); - system_setBatteryPercentage(percentage); + if (voltage_mv >= 0 && percentage >= 0) { + // Update system state with battery info + system_setBatteryVoltage(voltage_mv); + system_setBatteryPercentage(percentage); - ESP_LOGI(TAG, "Battery: %d mV (%d%%)", voltage_mv, percentage); - } else { - ESP_LOGW(TAG, "Failed to read battery voltage"); + ESP_LOGI(TAG, "Battery: %d mV (%d%%)", voltage_mv, percentage); + } else { + ESP_LOGW(TAG, "Failed to read battery voltage"); + } + + // Read charge status and update system + is_charging = !gpio_get_level(PIN_NUM_CHARGE_STATUS); + system_setChargeStatus(is_charging); } - // Read battery every 30 seconds - vTaskDelay(pdMS_TO_TICKS(30000)); + // LED control based on charging status and voltage (runs every 250ms) + if (is_charging) + { + // Charging: Red until voltage > 4150mV, then Green + if (voltage_mv > 4150) { + gpio_set_level(PIN_LED_GREEN, 1); // Green ON + gpio_set_level(PIN_LED_RED, 0); // Red OFF + } else { + gpio_set_level(PIN_LED_GREEN, 0); // Green OFF + gpio_set_level(PIN_LED_RED, 1); // Red ON + } + gpio_set_level(PIN_NUM_LED_2, 1); + } + else + { + // Not charging: voltage-based indication + if (voltage_mv > 3900) + { + // Good voltage: Green steady + gpio_set_level(PIN_LED_GREEN, 1); // Green ON + gpio_set_level(PIN_LED_RED, 0); // Red OFF + } + else + if (voltage_mv > 3700) + { + // Warning voltage: Green flashing at 2Hz + gpio_set_level(PIN_LED_GREEN, led_toggle ? 0 : 1); + gpio_set_level(PIN_LED_RED, 0); // Red OFF + led_toggle = !led_toggle; + } + else + if (voltage_mv > 3600) + { + // Low voltage: Red steady + gpio_set_level(PIN_LED_GREEN, 0); // Green OFF + gpio_set_level(PIN_LED_RED, 1); // Red ON + } + else + if (voltage_mv > 3500) + { + // Warning voltage: Red flashing at 2Hz + gpio_set_level(PIN_LED_RED, led_toggle ? 0 : 1); + gpio_set_level(PIN_LED_GREEN, 0); // Green OFF + led_toggle = !led_toggle; + } + else + { + // power off + gpio_set_level(PIN_NUM_nON, 0); + } + + gpio_set_level(PIN_NUM_LED_2, 1); + } + + loop_count++; + vTaskDelay(pdMS_TO_TICKS(250)); } } diff --git a/main/battery.h b/main/battery.h index dcd4c88..7a2b374 100644 --- a/main/battery.h +++ b/main/battery.h @@ -7,7 +7,7 @@ // Battery monitoring configuration #define BATTERY_ADC_CHANNEL ADC_CHANNEL_6 // GPIO34 (ADC1_CH6) #define BATTERY_ADC_ATTEN ADC_ATTEN_DB_12 // Full range ~3.9V (0-3300mV with attenuation) -#define BATTERY_ADC_WIDTH ADC_WIDTH_BIT_12 // 12-bit resolution (0-4095) +#define BATTERY_ADC_WIDTH ADC_BITWIDTH_12 // 12-bit resolution (0-4095) // Battery voltage calculation constants // Adjust these based on your voltage divider circuit diff --git a/main/gpio.h b/main/gpio.h index 4cc617b..3ae065e 100644 --- a/main/gpio.h +++ b/main/gpio.h @@ -10,6 +10,10 @@ #define PIN_NUM_nON 26 #define PIN_NUM_CHARGE_STATUS 2 +#define PIN_LED_RED PIN_NUM_LED_0 +#define PIN_LED_GREEN PIN_NUM_LED_1 + + // Define GPIO pins #ifdef DEVKIT diff --git a/main/gui.c b/main/gui.c index 6cfe0a4..4eb286e 100644 --- a/main/gui.c +++ b/main/gui.c @@ -100,6 +100,7 @@ static lv_obj_t *list; static lv_obj_t *buttons[MAX_ITEMS]; static int selected_index = 0; static lv_obj_t *_bubble = NULL; +static lv_obj_t *_voltageLabel = NULL; static lv_obj_t * _menu = NULL; static lv_obj_t *_currentPage = NULL; @@ -242,6 +243,9 @@ static void show_menu(void) { lv_obj_remove_flag(menu, LV_OBJ_FLAG_HIDDEN); lv_obj_add_flag(_bubble, LV_OBJ_FLAG_HIDDEN); + if (_voltageLabel != NULL) { + lv_obj_add_flag(_voltageLabel, LV_OBJ_FLAG_HIDDEN); + } } static void cleanup_menu(void) { @@ -269,6 +273,9 @@ static void cleanup_menu(void) { static void show_bubble(void) { cleanup_menu(); // Free menu memory when returning to bubble lv_obj_remove_flag(_bubble, LV_OBJ_FLAG_HIDDEN); + if (_voltageLabel != NULL) { + lv_obj_remove_flag(_voltageLabel, LV_OBJ_FLAG_HIDDEN); + } } static void create_lvgl_demo(void) @@ -393,6 +400,23 @@ static void createBubble(lv_obj_t * scr) // (usually on the next tick, or immediately if LVGL is idle). _bubble = level; + + #if 0 + // Create voltage label at the top + _voltageLabel = lv_label_create(scr); + lv_label_set_text(_voltageLabel, "---- mV"); + lv_obj_align(_voltageLabel, LV_ALIGN_TOP_MID, 0, 10); + lv_obj_set_style_text_font(_voltageLabel, &lv_font_montserrat_14, 0); + // Add white background for contrast + lv_obj_set_style_bg_color(_voltageLabel, lv_color_hex(0xFFFFFF), 0); + lv_obj_set_style_bg_opa(_voltageLabel, LV_OPA_COVER, 0); + lv_obj_set_style_text_color(_voltageLabel, lv_color_hex(0x000000), 0); + lv_obj_set_style_pad_left(_voltageLabel, 8, 0); + lv_obj_set_style_pad_right(_voltageLabel, 8, 0); + lv_obj_set_style_pad_top(_voltageLabel, 4, 0); + lv_obj_set_style_pad_bottom(_voltageLabel, 4, 0); + lv_obj_set_style_radius(_voltageLabel, 4, 0); +#endif } @@ -1289,6 +1313,9 @@ static void show_bt_device_list(void) { lv_obj_remove_flag(menu, LV_OBJ_FLAG_HIDDEN); lv_obj_add_flag(_bubble, LV_OBJ_FLAG_HIDDEN); + if (_voltageLabel != NULL) { + lv_obj_add_flag(_voltageLabel, LV_OBJ_FLAG_HIDDEN); + } @@ -1420,6 +1447,9 @@ static void show_volume_control(void) { lv_obj_remove_flag(menu, LV_OBJ_FLAG_HIDDEN); lv_obj_add_flag(_bubble, LV_OBJ_FLAG_HIDDEN); + if (_voltageLabel != NULL) { + lv_obj_add_flag(_voltageLabel, LV_OBJ_FLAG_HIDDEN); + } ESP_LOGI(TAG, "Volume control displayed"); } @@ -1685,6 +1715,9 @@ static void show_calibration_menu(void) { lv_obj_remove_flag(menu, LV_OBJ_FLAG_HIDDEN); lv_obj_add_flag(_bubble, LV_OBJ_FLAG_HIDDEN); + if (_voltageLabel != NULL) { + lv_obj_add_flag(_voltageLabel, LV_OBJ_FLAG_HIDDEN); + } ESP_LOGI(TAG, "Calibration menu displayed"); } @@ -1950,6 +1983,18 @@ static void gui_task(void *pvParameters) { ImuData_t d = system_getImuData(); bubble_setValue(_bubble, -d.angle); + +#if 0 + // Update voltage display + lvgl_port_lock(0); + int voltage_mv = system_getBatteryVoltage(); + if (_voltageLabel != NULL) { + char buf[16]; + snprintf(buf, sizeof(buf), "%d mV", voltage_mv); + lv_label_set_text(_voltageLabel, buf); + } + lvgl_port_unlock(); +#endif } } diff --git a/main/main.c b/main/main.c index 058b362..0353096 100644 --- a/main/main.c +++ b/main/main.c @@ -320,14 +320,15 @@ void app_main(void) print_heap_info("POST_BATTERY"); gpio_set_level(PIN_NUM_LED_0, 1); - gpio_set_level(PIN_NUM_LED_1, 1); - gpio_set_level(PIN_NUM_LED_2, 1); + gpio_set_level(PIN_NUM_LED_1, 1); + gpio_set_level(PIN_NUM_LED_2, 1); gui_start(); print_heap_info("POST_GUI"); gpio_set_level(PIN_NUM_LED_2, 1); + battery_start_monitoring_task(); #if 0 keypad_start(); @@ -363,22 +364,7 @@ void app_main(void) #else while (1) { - // Read charge status and update system - bool is_charging = gpio_get_level(PIN_NUM_CHARGE_STATUS); - system_setChargeStatus(is_charging); - if (is_charging) - { - gpio_set_level(PIN_NUM_LED_0, 0); - gpio_set_level(PIN_NUM_LED_1, 1); - gpio_set_level(PIN_NUM_LED_2, 0); - } - else - { - gpio_set_level(PIN_NUM_LED_0, 1); - gpio_set_level(PIN_NUM_LED_1, 0); - gpio_set_level(PIN_NUM_LED_2, 0); - } system_processNvsRequests(); vTaskDelay(pdMS_TO_TICKS(10)); diff --git a/main/system.c b/main/system.c index 50a9c7e..0f68a34 100644 --- a/main/system.c +++ b/main/system.c @@ -5,6 +5,7 @@ #include "esp_timer.h" #include + static SystemState_t _systemState; static EventGroupHandle_t _systemEvent; @@ -15,6 +16,7 @@ static const char* NVS_NAMESPACE = "bt_devices"; static const char* NVS_KEY_COUNT = "count"; static const char* NVS_NAMESPACE_SETTINGS = "settings"; static const char* NVS_KEY_VOLUME = "volume"; +static const char* NVS_KEY_SWAP_LR = "swap_lr"; 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); @@ -39,6 +41,9 @@ void system_init(void) // Load saved volume from NVS system_loadVolume(); + + // Load saved swap L/R setting from NVS + system_loadSwapLR(); } int system_getPrimaryAxis(void) @@ -138,6 +143,9 @@ void system_toggleSwapLR(void) _systemState.swapLR = !_systemState.swapLR; ESP_LOGI("system", "Swap L/R toggled: %s", _systemState.swapLR ? "ON" : "OFF"); xSemaphoreGive(_eventManager.mutex); + + // Save to NVS + system_saveSwapLR(); } void system_setZeroAngle(void) @@ -354,7 +362,7 @@ esp_err_t system_loadVolume(void) { ret = nvs_open(NVS_NAMESPACE_SETTINGS, NVS_READONLY, &nvs_handle); if (ret != ESP_OK) { - ESP_LOGI("system", "No saved volume found, using default: %d", volume); + ESP_LOGI("system", "No saved volume found, using default: %ld", volume); system_setVolume(volume); return ESP_OK; // Not an error, just means no saved value } @@ -363,10 +371,10 @@ esp_err_t system_loadVolume(void) { nvs_close(nvs_handle); if (ret == ESP_OK) { - ESP_LOGI("system", "Loaded volume from NVS: %d", volume); + ESP_LOGI("system", "Loaded volume from NVS: %ld", volume); system_setVolume(volume); } else if (ret == ESP_ERR_NVS_NOT_FOUND) { - ESP_LOGI("system", "No saved volume found, using default: %d", volume); + ESP_LOGI("system", "No saved volume found, using default: %ld", volume); system_setVolume(volume); ret = ESP_OK; // Not an error } else { @@ -376,6 +384,67 @@ esp_err_t system_loadVolume(void) { return ret; } +esp_err_t system_saveSwapLR(void) { + nvs_handle_t nvs_handle; + esp_err_t ret; + + bool swapLR = system_getSwapLR(); + + ret = nvs_open(NVS_NAMESPACE_SETTINGS, NVS_READWRITE, &nvs_handle); + if (ret != ESP_OK) { + ESP_LOGE("system", "Failed to open NVS namespace for swap L/R write: %s", esp_err_to_name(ret)); + return ret; + } + + ret = nvs_set_u8(nvs_handle, NVS_KEY_SWAP_LR, swapLR ? 1 : 0); + if (ret != ESP_OK) { + ESP_LOGE("system", "Failed to write swap L/R to NVS: %s", esp_err_to_name(ret)); + nvs_close(nvs_handle); + return ret; + } + + ret = nvs_commit(nvs_handle); + nvs_close(nvs_handle); + + if (ret == ESP_OK) { + ESP_LOGI("system", "Swap L/R %s saved to NVS", swapLR ? "ON" : "OFF"); + } else { + ESP_LOGE("system", "Failed to commit swap L/R to NVS: %s", esp_err_to_name(ret)); + } + + return ret; +} + +esp_err_t system_loadSwapLR(void) { + nvs_handle_t nvs_handle; + esp_err_t ret; + uint8_t swapLR_u8 = 0; // Default value (OFF) + + ret = nvs_open(NVS_NAMESPACE_SETTINGS, NVS_READONLY, &nvs_handle); + if (ret != ESP_OK) { + ESP_LOGI("system", "No saved swap L/R found, using default: OFF"); + system_setSwapLR(false); + return ESP_OK; // Not an error, just means no saved value + } + + ret = nvs_get_u8(nvs_handle, NVS_KEY_SWAP_LR, &swapLR_u8); + nvs_close(nvs_handle); + + if (ret == ESP_OK) { + bool swapLR = (swapLR_u8 != 0); + ESP_LOGI("system", "Loaded swap L/R from NVS: %s", swapLR ? "ON" : "OFF"); + system_setSwapLR(swapLR); + } else if (ret == ESP_ERR_NVS_NOT_FOUND) { + ESP_LOGI("system", "No saved swap L/R found, using default: OFF"); + system_setSwapLR(false); + ret = ESP_OK; // Not an error + } else { + ESP_LOGE("system", "Failed to read swap L/R from NVS: %s", esp_err_to_name(ret)); + } + + return ret; +} + void system_initNvsService(void) { _nvsRequestQueue = xQueueCreate(10, sizeof(nvs_request_t)); if (_nvsRequestQueue == NULL) { diff --git a/main/system.h b/main/system.h index 12f39da..fe7afd3 100644 --- a/main/system.h +++ b/main/system.h @@ -108,6 +108,8 @@ int system_getBatteryPercentage(void); void system_setSwapLR(bool swap); bool system_getSwapLR(void); void system_toggleSwapLR(void); +esp_err_t system_saveSwapLR(void); +esp_err_t system_loadSwapLR(void); void system_setZeroAngle(void); void system_clearZeroAngle(void);