Compare commits

...

20 Commits

Author SHA1 Message Date
d427859804 saving and charge indication working 2026-01-19 22:05:35 -06:00
40bea065a7 adding save and battery voltage reading 2026-01-19 17:42:48 -06:00
Brent Perteet
3bce9e772c Add dark color scheme, backlight timeout, and L/R swap feature
- Invert UI colors: black background with white text, yellow highlights
- Add 30-second backlight timeout with auto-wake on button press
- Add Swap L/R menu option with checkbox to swap audio channels
- Update volume page styling (yellow bar, full-screen container)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 09:08:12 -06:00
Brent Perteet
31e0e3a148 add label scrolling in Bluetooth menu 2025-11-19 17:42:22 -06:00
Brent Perteet
a272a15bcf Improve calibration and volume menu UX
- Add calibration submenu with three options: Cancel (default), Calibrate, and Clear
- Cancel returns to main menu to prevent accidental calibration
- Calibrate runs system_setZeroAngle() and displays "Calibrated" confirmation
- Clear runs system_clearZeroAngle() and displays "Cleared" confirmation
- Use LVGL timer for non-blocking 1-second confirmation messages
- Center confirmation messages both horizontally and vertically
- Use larger font (montserrat_16) for better readability
- Remove "Back" button from volume control page
- Center volume control elements vertically on screen
- Improve overall menu navigation and visual consistency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-16 21:53:32 -06:00
Brent Perteet
8a1966ea90 Add charge status monitoring and LED control
- Add LED_0 pin definition and charge status GPIO pin
- Implement charge status monitoring in main loop
- Add LED visual indicators for charging state
- Configure LVGL Montserrat 10 font and set as default
- Reset GPIO pins to clear SPI configurations
- Update COM port to COM14 in VSCode settings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-16 15:55:59 -06:00
Brent Perteet
b8a3a09e9f Fix Bluetooth pairing, menu crashes, and improve UX
Major fixes and improvements to Bluetooth device management and menu navigation:

**Bluetooth Device Pairing**
- Fixed discovered devices not being saved as paired after connection
- Only save devices to NVS when successfully connected (not just discovered)
- Auto-pair discovered devices on successful A2DP connection
- Update device list to show paired status immediately after connection

**Critical Bug Fixes**
- Fixed dangling pointer crash in NVS request/response mechanism
  - Was sending pointer to stack variable, now sends result value directly
  - Prevents crash when connecting to Bluetooth devices
- Fixed use-after-free crash when clicking menu items after dynamic updates
  - Menu context now properly synchronized after adding/removing items
  - Prevents InstructionFetchError crashes in menu navigation
- Fixed memory exhaustion by reducing MAX_BT_DEVICES from 20 to 8
  - Prevents heap allocation failures when populating device list

**Menu & UX Improvements**
- "Clear Paired" button now properly disconnects active connections
- "Clear Paired" button always visible when paired devices exist
- GUI updates immediately after clearing paired devices
- Paired devices marked with asterisk prefix (* Device Name)
- Removed redundant "(paired)" suffix text
- Long device names scroll smoothly when selected (3-second animation)
- Refresh button preserved during menu updates to prevent crashes
- Menu focus state properly maintained across all dynamic updates

**Technical Details**
- bt_add_discovered_device() no longer saves to NVS
- Added currentFocusIndex() calls after all menu modifications
- Improved clear_bt_device_list() to avoid deleting active buttons
- Added bt_disconnect_current_device() for clean disconnections
- Fixed NVS notification mechanism to avoid stack variable pointers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 11:39:58 -06:00
Brent Perteet
115105c032 Fix menu navigation issues with Bluetooth and initial focus
- Initialize menu context when showing menu to properly track focused item
- Fix double-activation bug that caused immediate exit from Bluetooth menu
- Add separate refresh_bt_device_list() to avoid infinite discovery loop
- Delete old BT page before creating new one to prevent memory leaks
- Add "Clear Paired" option to Bluetooth menu
- Improve Bluetooth menu refresh behavior to show "Scanning..." message

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 19:55:32 -06:00
Brent Perteet
19e8ca30c3 everything working and tested on separate computer 2025-10-27 18:27:55 -05:00
Brent Perteet
de7041c1f5 EXE working but getting logging error 2025-10-25 11:52:11 -05:00
Brent Perteet
fe69dc6f19 flash works when not in EXE 2025-10-25 11:29:53 -05:00
Brent Perteet
bca2f6ea9c Added logo to flasher 2025-10-14 09:50:35 -05:00
Brent Perteet
5a893a034c update flasher 2025-10-13 20:51:52 -05:00
2513a9e7fb adding web flasher tool 2025-10-13 18:54:50 -05:00
Brent Perteet
04d2c71d01 adding flasher 2025-10-12 13:40:43 -05:00
Brent Perteet
a89fdc6843 Update GUI styling and font configuration
- Fix bt_app.h syntax error (remove stray "1")
- Improve menu item alignment and styling
- Enable additional LVGL fonts (Montserrat 8, Unscii 16)
- Clean up volume page layout, remove instruction labels
- Update default font to Montserrat 8

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-27 18:23:40 +00:00
Brent Perteet
439c6ef22d Enhance Bluetooth functionality and GUI integration
- Add Bluetooth device list management with discovery and pairing support
- Implement volume control with AVRC integration
- Add system event handling for GUI-to-Bluetooth communication
- Enhance menu system with device selection and volume control pages
- Improve memory management by making menu creation lazy
- Add proper event subscription between GUI and Bluetooth modules
- Update filter coefficient for improved audio clicking behavior

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-25 16:46:16 +00:00
Brent Perteet
25f875b3b2 Memory issues resolved 2025-08-20 15:46:17 +00:00
Brent Perteet
c4ca91bf84 added tweaks to filter 2025-08-08 17:31:27 -05:00
Brent Perteet
fb9fd84bf1 Fix readme 2025-07-22 14:11:25 -05:00
54 changed files with 6369 additions and 5543 deletions

View File

@@ -0,0 +1,32 @@
{
"permissions": {
"allow": [
"Bash(idf.py build:*)",
"Bash(grep:*)",
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(pip install:*)",
"Bash(build_from_spec.bat)",
"mcp__ide__getDiagnostics",
"Bash(source:*)",
"Bash(chmod:*)",
"Bash(python3:*)",
"Bash(pyinstaller:*)",
"Bash(open:*)",
"Bash(dos2unix:*)",
"Bash(./build_macos.sh:*)",
"Bash(brew install:*)",
"Bash(python:*)",
"Bash(./dist/ESP32_Flasher:*)",
"Bash(pkill:*)",
"Bash(curl -s http://127.0.0.1:5000/)",
"Bash(./build_web_macos.sh:*)",
"Bash(./dist/ESP32_Flasher.app/Contents/MacOS/ESP32_Flasher:*)",
"Bash(where:*)",
"Bash(idf.py size-components:*)",
"Bash(find:*)",
"Bash(git log:*)"
],
"deny": []
}
}

17
.gitignore vendored
View File

@@ -1,6 +1,22 @@
.pytest_cache/ .pytest_cache/
__pycache__/ __pycache__/
# macOS
.DS_Store
# Python virtual environments
venv/
env/
ENV/
.venv/
# PyInstaller build artifacts
dist/
build/
*.spec
*.pyc
*.pyo
# esp-idf built binaries # esp-idf built binaries
build/ build/
build_*_*/ build_*_*/
@@ -21,3 +37,4 @@ dependencies.lock
managed_components managed_components
components components
output

39
.vscode/c_cpp_properties.json vendored Normal file
View File

@@ -0,0 +1,39 @@
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**",
"${env:USERPROFILE}/esp/v5.4.1/esp-idf/components/**",
"${env:USERPROFILE}/.espressif/tools/xtensa-esp-elf/**",
"${workspaceFolder}/build/config",
"${workspaceFolder}/managed_components/**"
],
"defines": [
"ESP_PLATFORM"
],
"compilerPath": "${env:USERPROFILE}/.espressif/tools/xtensa-esp-elf/esp-13.2.0_20241113/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc.exe",
"cStandard": "c11",
"cppStandard": "c++20",
"intelliSenseMode": "gcc-x64"
},
{
"name": "Mac",
"includePath": [
"${workspaceFolder}/**",
"/Users/brent/esp/v5.5.1/esp-idf/components/**",
"/Users/brent/.espressif/tools/xtensa-esp-elf/**",
"${workspaceFolder}/build/config",
"${workspaceFolder}/managed_components/**"
],
"defines": [
"ESP_PLATFORM"
],
"compilerPath": "/Users/brent/.espressif/tools/xtensa-esp-elf/esp-13.2.0_20240530/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc",
"cStandard": "c11",
"cppStandard": "c++20",
"intelliSenseMode": "gcc-x64"
}
],
"version": 4
}

50
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,50 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Build ESP32 Firmware (Windows)",
"type": "process",
"request": "launch",
"command": "idf.py",
"args": ["build"],
"cwd": "${workspaceFolder}",
"windows": {
"command": "idf.py"
},
"problemMatcher": ["$gcc"]
},
{
"name": "Build ESP32 Firmware (macOS)",
"type": "process",
"request": "launch",
"command": "bash",
"args": ["-lc", "source ${IDF_PATH:-/opt/esp/idf}/export.sh && idf.py build"],
"cwd": "${workspaceFolder}",
"osx": {
"command": "bash"
},
"problemMatcher": ["$gcc"]
},
{
"name": "Build Windows Flasher",
"type": "process",
"request": "launch",
"command": "${workspaceFolder}/flash_tool/build_from_spec.bat",
"cwd": "${workspaceFolder}/flash_tool",
"windows": {
"command": "${workspaceFolder}/flash_tool/build_from_spec.bat"
}
},
{
"name": "Build macOS Flasher",
"type": "process",
"request": "launch",
"command": "${workspaceFolder}/flash_tool/build_macos.sh",
"cwd": "${workspaceFolder}/flash_tool",
"osx": {
"command": "bash",
"args": ["${workspaceFolder}/flash_tool/build_macos.sh"]
}
}
]
}

17
.vscode/settings.json vendored
View File

@@ -1,11 +1,12 @@
{ {
"C_Cpp.intelliSenseEngine": "default", "C_Cpp.intelliSenseEngine": "default",
"idf.espIdfPathWin": "C:\\Users\\brent.RPX\\esp\\v5.3.1\\esp-idf", "idf.projectName": "soundshot",
"idf.espIdfPathWin": "C:\\Users\\Brent.Perteet\\esp\\v5.4.1\\esp-idf",
"idf.openOcdConfigs": [ "idf.openOcdConfigs": [
"board/esp32-wrover-kit-3.3v.cfg" "board/esp32-wrover-kit-3.3v.cfg"
], ],
"idf.portWin": "COM4", "idf.portWin": "COM3",
"idf.toolsPathWin": "C:\\Users\\brent.RPX\\.espressif\\tools", "idf.toolsPathWin": "C:\\Users\\Brent.Perteet\\.espressif",
"idf.flashType": "UART", "idf.flashType": "UART",
"files.associations": { "files.associations": {
"esp_system.h": "c", "esp_system.h": "c",
@@ -35,7 +36,13 @@
"semphr.h": "c", "semphr.h": "c",
"lv_spinbox.h": "c", "lv_spinbox.h": "c",
"lv_slider.h": "c", "lv_slider.h": "c",
"lv_menu.h": "c" "lv_menu.h": "c",
"stdint.h": "c",
"random": "c",
"string.h": "c"
}, },
"git.ignoreLimitWarning": true "git.ignoreLimitWarning": true,
"idf.pythonInstallPath": "C:\\Users\\Brent.Perteet\\.espressif\\tools\\idf-python\\3.11.2\\python.exe",
"idf.espIdfPath": "/Users/brent/esp/v5.5.1/esp-idf",
"idf.toolsPath": "/Users/brent/.espressif"
} }

37
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,37 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "adapter",
"type": "shell",
"command": "idf.py",
"args": ["build"],
"windows": {
"command": "cmd.exe",
"args": ["/c", "${env:USERPROFILE}\\esp\\v5.4.1\\esp-idf\\export.bat", "&&", "idf.py", "build"]
},
"osx": {
"command": "bash",
"args": ["-lc", "source ${IDF_PATH:-/opt/esp/idf}/export.sh && idf.py build"]
},
"linux": {
"command": "bash",
"args": ["-lc", "source ${IDF_PATH:-/opt/esp/idf}/export.sh && idf.py build"]
},
"group": { "kind": "build", "isDefault": true },
"problemMatcher": ["${config:idf.cmakeCompilerArgs}"],
"presentation": {
"reveal": "always",
"panel": "dedicated"
}
},
{
"label": "ESP-IDF: Build (RAM) + Sync to Host",
"type": "shell",
"command": "bash -lc 'source ${IDF_PATH:-/opt/esp/idf}/export.sh && idf.py build && rsync -a --delete \"$PWD/build/\" /host_build/'",
"group": "build",
"problemMatcher": "$gcc"
}
]
}

147
CLAUDE.md Normal file
View File

@@ -0,0 +1,147 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
SoundShot is an ESP32-based embedded system that appears to be an IMU-based angle measurement device with Bluetooth connectivity and GUI interface. The project uses ESP-IDF (Espressif IoT Development Framework) and can be developed using either Docker containers or native tooling.
## Build System & Development Environment
### Docker Development (Recommended)
- **Setup**: Run `setup-env.bat` to create Python virtual environment and install dependencies
- **Container**: Uses ESP-IDF Docker containers with VS Code Dev Containers extension
- **Build**: `idf.py build` (inside container)
### Native Development
- **Build**: `idf.py build` (requires ESP-IDF setup)
- **Configuration**: Uses `settings.json` for project parameters
- **CMake**: Project uses ESP-IDF CMake build system with custom configuration generator
### Essential Commands
```bash
# Environment setup (Windows only)
setup-env.bat
# Build firmware
idf.py build
# Flash device (using custom Python tool)
flash.bat
python flash_tool/flash.py
# Monitor serial output
monitor.bat
python flash_tool/monitor.py
# Combined flash and monitor
flashmon.bat
# Clean build
idf.py fullclean
```
## Project Architecture
### Core Components
**Main Application (`main/`)**
- `main.c` - Entry point, IMU processing, task coordination
- `system.c/h` - System state management, event handling, calibration
- `gui.c/h` - LVGL-based user interface (3 modes: main, menu, bubble)
- `bt_app.c/h` - Bluetooth connectivity and communication
- `lsm6dsv.c/h` - LSM6DSV IMU sensor driver
- `keypad.c/h` - Physical button input handling
- `bubble.c/h` - Bubble level visualization
**Key Features**
- Real-time angle measurement with configurable filtering
- Bluetooth connectivity for data transmission
- LVGL-based GUI with multiple display modes
- Zero-angle calibration system
- Low-pass filtering with adaptive alpha coefficients
### Hardware Configuration
**GPIO Pins** (`gpio.h`)
- LEDs, LCD backlight, power control
- I2C for IMU communication (SCL=22, SDA=21)
- Serial communication and button inputs
**IMU Processing**
- LSM6DSV 6-axis IMU sensor
- Angle computation from accelerometer data (XZ, YZ, XY planes)
- Configurable filtering with `FILTER_COEFF` and `MAX_INDICATION_ANGLE`
- Primary axis selection via `PRIMARY_AXIS` define
## Configuration Management
### settings.json Structure
```json
{
"project_name": "soundshot",
"chip": "esp32",
"port": "COM3",
"monitor_baud": 115200,
"flash_baud": 460800,
"flash_mode": "dio",
"flash_freq": "40m",
"flash_size": "2MB"
}
```
**Configuration Flow**
1. `settings.json``prepare_config.py``project_settings.cmake`
2. CMake includes generated settings during build
3. Flash tools read `settings.json` for esptool parameters
### Build Dependencies
**ESP-IDF Components**
- `driver` - GPIO, I2C, peripherals
- `esp_lcd` - Display drivers
- `lvgl` + `esp_lvgl_port` - GUI framework
- `esp_timer` - High resolution timers
- `nvs_flash` - Non-volatile storage
- `bt` - Bluetooth stack
**Managed Components**
- LVGL 9.x with ESP32 port integration
- Located in `managed_components/`
## Development Guidelines
### Code Organization
- Hardware abstraction in dedicated modules (`lsm6dsv.c`, `keypad.c`)
- System state centralized in `system.c` with event-based communication
- GUI logic separated from business logic
- Bluetooth handled as separate subsystem
### Key Constants & Tuning Parameters
- `MAX_INDICATION_ANGLE` (5.0°) - Angle measurement limit
- `FILTER_COEFF` (0.4) - Low-pass filter strength
- `PRIMARY_AXIS` - Main measurement axis selection
- Filter alpha computed dynamically based on input magnitude
### Testing & Debugging
- Serial monitoring at 115200 baud via `monitor.bat`
- Debug prints use ESP-IDF logging (`ESP_LOGI`, `ESP_LOGW`, etc.)
- IMU data output can be enabled via conditional compilation blocks
### Flash Memory Layout
- Bootloader: 0x1000
- Partition table: 0x8000
- OTA data: 0x11000
- Application: 0x20000
## Common Development Patterns
When modifying this codebase:
1. IMU changes: Update filtering parameters in `main.c` and constants in `system.h`
2. GUI changes: Modify LVGL code in `gui.c`, add new modes to `GuiMode_t` enum
3. Bluetooth changes: Update message handlers in `bt_app.c`
4. Hardware changes: Update pin definitions in `gpio.h` and initialization in `main.c`
5. Build changes: Modify component dependencies in `main/CMakeLists.txt`
Always test flashing and monitoring tools after hardware configuration changes.

View File

@@ -1,6 +1,21 @@
# The following lines of boilerplate have to be in your project's # The following lines of boilerplate have to be in your project's CMakeLists
# CMakeLists in this exact order for cmake to work correctly # in this exact order for cmake to work correctly
configure_file(${CMAKE_SOURCE_DIR}/settings.json ${CMAKE_BINARY_DIR}/settings.json COPYONLY)
execute_process(
COMMAND ${CMAKE_COMMAND} -E echo "Parsing settings.json..."
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E env python ${CMAKE_SOURCE_DIR}/prepare_config.py
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(level-shot) include("${CMAKE_SOURCE_DIR}/project_settings.cmake")
project(${PROJECT_NAME})

View File

@@ -1,4 +1,3 @@
<<<<<<< HEAD
## 🐳 ESP-IDF Dockerized Development Environment (Windows) ## 🐳 ESP-IDF Dockerized Development Environment (Windows)
This project includes a fully containerized [ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/index.html) development environment using **Docker** and **Visual Studio Code**. This project includes a fully containerized [ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/index.html) development environment using **Docker** and **Visual Studio Code**.
@@ -210,95 +209,3 @@ Features:
* If `idf.py` is not found, make sure the container terminal sources `export.sh` * If `idf.py` is not found, make sure the container terminal sources `export.sh`
=======
| Supported Targets | ESP32 |
| ----------------- | ----- |
A2DP-SOURCE EXAMPLE
========================
Example of A2DP audio source role
This is the example of using Advanced Audio Distribution Profile (A2DP) APIs to transmit audio stream. Application can take advantage of this example to implement portable audio players or microphones to transmit audio stream to A2DP sink devices.
## How to use this example
### Hardware Required
This example is able to run on any commonly available ESP32 development board, and is supposed to connect to [A2DP sink example](../a2dp_sink) in ESP-IDF.
### Configure the project
```
idf.py menuconfig
```
* Enable Classic Bluetooth and A2DP under Component config --> Bluetooth --> Bluedroid Enable
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output.
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
For the first step, this example performs device discovery to search for a target device (A2DP sink) whose device name is "ESP_SPEAKER" and whose "Rendering" bit of its Service Class field is set in its Class of Device (COD). If a candidate target is found, the local device will initiate connection with it.
After connection with A2DP sink is established, the example performs the following running loop 1-2-3-4-1:
1. audio transmission starts and lasts for a while
2. audio transmission stops
3. disconnect with target device
4. reconnect to target device
The example implements an event loop triggered by a periodic "heart beat" timer and events from Bluetooth protocol stack callback functions.
After the local device discovers the target device and initiates connection, there will be logging message like this:
```
I (4090) BT_AV: Found a target device, address xx:xx:xx:xx:xx:xx, name ESP_SPEAKER
I (4090) BT_AV: Cancel device discovery ...
I (4100) BT_AV: Device discovery stopped.
I (4100) BT_AV: a2dp connecting to peer: ESP_SPEAKER
```
If connection is set up successfully, there will be such message:
```
I (5100) BT_AV: a2dp connected
```
Starting of audio transmission has the following notification message:
```
I (10880) BT_AV: a2dp media ready checking ...
...
I (10880) BT_AV: a2dp media ready, starting ...
...
I (11400) BT_AV: a2dp media start successfully.
```
Stop of audio transmission, and disconnection with remote device generate the following notification message:
```
I (110880) BT_AV: a2dp media stopping...
...
I (110920) BT_AV: a2dp media stopped successfully, disconnecting...
...
I (111040) BT_AV: a2dp disconnected
```
## Troubleshooting
* For current stage, the supported audio codec in ESP32 A2DP is SBC. SBC audio stream is encoded from PCM data normally formatted as 44.1kHz sampling rate, two-channel 16-bit sample data.
* The raw PCM media stream in the example is generated by a sequence of random number, so the sound played on the sink side will be piercing noise.
* As a usage limitation, ESP32 A2DP source can support at most one connection with remote A2DP sink devices. Also, A2DP source cannot be used together with A2DP sink at the same time, but can be used with other profiles such as SPP and HFP.
* Usually, the `ACL_CONN_NUM` is set to `2` but not `1` as one is used for a2dp connection and the other is used for avrcp connection.
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442

51
bt_test/bt_test.ino Normal file
View File

@@ -0,0 +1,51 @@
#include <BluetoothSerial.h>
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
BluetoothSerial SerialBT;
void setBluetoothTxPower(esp_power_level_t powerLevel) {
esp_err_t err = esp_bredr_tx_power_set(powerLevel, powerLevel);
if (err != ESP_OK) {
Serial.printf("Failed to set TX Power: %s\n", esp_err_to_name(err));
} else {
Serial.printf("TX Power set to level %d\n", powerLevel);
}
}
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Initializing Bluetooth...");
if (!btStart()) {
Serial.println("Failed to start BT controller");
return;
}
// Disable and re-enable the classic BT stack to safely set TX power
esp_bluedroid_disable();
esp_bluedroid_deinit();
// Set Classic BT TX power (e.g., ESP_PWR_LVL_P9 = highest)
//setBluetoothTxPower(ESP_PWR_LVL_P9);
setBluetoothTxPower(ESP_PWR_LVL_N12);
esp_bluedroid_init();
esp_bluedroid_enable();
if (!SerialBT.begin("ESP32-TXPowerTest")) {
Serial.println("Bluetooth Serial failed to start");
return;
}
Serial.println("Bluetooth initialized and ready!");
}
void loop() {
SerialBT.println("Hello from ESP32 with boosted TX power!");
delay(1);
}

141
docker.md Normal file
View File

@@ -0,0 +1,141 @@
Perfect! Below is the updated `README.md` section with **complete instructions** for setting up the Dockerized ESP-IDF environment on **Windows**, **including installation of the official Espressif VS Code extension**.
You can paste this into your repos `README.md`. Its ready to go and designed to guide teammates or collaborators through cloning, launching, and building the project with confidence.
---
## 🐳 ESP-IDF Dockerized Development Environment (Windows)
This project includes a fully containerized [ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/index.html) development environment using **Docker** and **Visual Studio Code**.
Follow these instructions to set up, build, and flash the firmware inside a VS Code **Dev Container** on **Windows**.
---
### ✅ Prerequisites
Ensure the following are installed on your system:
1. [**Docker Desktop for Windows**](https://www.docker.com/products/docker-desktop)
* Enable **WSL 2 backend** during installation.
2. [**Visual Studio Code**](https://code.visualstudio.com/)
3. [**Dev Containers Extension**](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
* In VS Code: `Extensions → Search "Dev Containers" → Install`
4. [**Espressif IDF Extension** for VS Code](https://marketplace.visualstudio.com/items?itemName=espressif.esp-idf-extension)
* In VS Code: `Extensions → Search "ESP-IDF" → Install`
> 💡 **Optional (recommended):** Install [WSL 2 with Ubuntu](https://learn.microsoft.com/en-us/windows/wsl/install) for improved Linux compatibility inside Docker.
---
### 🚀 Getting Started
#### 1. Clone this repository
```bash
git clone https://github.com/your-username/your-esp-idf-project.git
cd your-esp-idf-project
```
---
#### 2. Open in Visual Studio Code
From the project root:
```bash
code .
```
> Ensure you're opening the folder that contains `.devcontainer/`.
---
#### 3. Reopen in Dev Container
In VS Code:
* Press `F1` or `Ctrl+Shift+P`
* Run: **Dev Containers: Reopen in Container**
VS Code will:
* Build the Docker image (based on the provided `Dockerfile`)
* Set up the ESP-IDF environment
* Install extensions automatically
---
#### 4. Verify Environment
Once setup is complete:
* A terminal should launch inside the container
* Run:
```bash
idf.py --version
```
to confirm ESP-IDF is active and available.
---
#### 5. Build the Firmware
Inside the containers terminal:
```bash
idf.py build
```
You should see standard ESP-IDF build output and a `.bin` firmware file in the `build/` directory.
---
### 🔌 Flashing the ESP32 (Optional)
If you want to flash from inside the container:
1. Connect your ESP32 via USB.
2. Identify the COM port on Windows (e.g., `COM3`).
3. Pass the USB device into the container (this may require configuration).
4. Then run:
```bash
idf.py -p COM3 flash monitor
```
> ⚠️ **Note:** Docker Desktop for Windows doesnt always expose serial ports to containers directly. You can build firmware inside the container and flash it from your host as a fallback.
---
### 🧰 Notes
* The ESP-IDF version is pinned in the Dockerfile (e.g., `espressif/idf:v5.2.1`)
* The container automatically runs `source $IDF_PATH/export.sh` to prepare the environment.
* VS Code extensions (`.devcontainer.json`) include:
* `ms-vscode.cpptools`
* `ms-vscode.cmake-tools`
* `espressif.esp-idf-extension`
---
### 🛠 Troubleshooting
* If `idf.py` is not found, make sure the container terminal sources `export.sh`
* If USB flashing fails, flash from host or use WSL serial forwarding tools like `socat` or `usbip`
---
Would you like this `README.md` version to be packaged with:
* A **starter repo structure**
* A prebuilt `.devcontainer/` directory
* A sample `Dockerfile`, `main.c`, and `CMakeLists.txt`?
If yes, I can bundle that up for you — just say the word.

4
flash_gui.bat Normal file
View File

@@ -0,0 +1,4 @@
@echo off
echo Starting ESP32 Firmware Flash GUI...
python flash_tool/gui_flasher.py
pause

View File

@@ -0,0 +1,9 @@
{
"permissions": {
"allow": [
"Bash(python:*)"
],
"deny": [],
"ask": []
}
}

110
flash_tool/BUILD_NOTES.md Normal file
View File

@@ -0,0 +1,110 @@
# Build Notes
## Build Status
**macOS Build: SUCCESS**
- Built on: macOS 15.6 (arm64)
- Python Version: 3.9.6 (Xcode system Python with tkinter support)
- Output: `dist/ESP32_Flasher.app`
- Size: ~7.0 MB
- Tested: ✅ Application launches and runs successfully
## Prerequisites
### macOS
**Important:** Homebrew's Python 3.13 does NOT include tkinter support by default.
**Solution:** Install python-tk package:
```bash
brew install python-tk@3.13
```
However, the build system will automatically use the system Python (3.9.6 from Xcode) which has tkinter built-in. This is the recommended approach.
## Known Issues
### ~~macOS tkinter Warning~~ - RESOLVED
**Previous Issue:** Homebrew Python 3.13 doesn't include tkinter
**Solution:** Build system now uses Xcode's Python 3.9.6 which has native tkinter support
**Status:** ✅ Fixed - no warnings, app works perfectly
### Virtual Environment Required (macOS)
Due to PEP 668 (externally-managed environments), macOS requires using a virtual environment for pip installations. The build scripts automatically handle this.
## Build Commands
### Quick Build (Any Platform)
```bash
python3 build.py
```
### macOS Specific
```bash
./build_macos.sh
```
or
```bash
source venv/bin/activate
pyinstaller ESP32_Flasher_macOS.spec
```
### Windows Specific
```batch
build_from_spec.bat
```
## Distribution
### macOS
- Distribute the entire `ESP32_Flasher.app` folder (it's a bundle)
- Users may need to run: `xattr -cr ESP32_Flasher.app` if macOS blocks it
- Consider creating a DMG for easier distribution
### Windows
- Distribute the single `ESP32_Flasher.exe` file
- No installation required
- May trigger Windows SmartScreen (normal for unsigned apps)
## File Structure
```
flash_tool/
├── dist/ # Build output
│ ├── ESP32_Flasher.app # macOS bundle
│ └── ESP32_Flasher # Standalone binary
├── build/ # Build artifacts
├── venv/ # Python virtual environment (macOS)
├── gui_flasher.py # Source code
├── ESP32_Flasher_macOS.spec # macOS build config
├── ESP32_Flasher_Windows.spec # Windows build config
├── build.py # Universal build script
├── build_macos.sh # macOS build script
└── build_from_spec.bat # Windows build script
```
## Next Steps
1. **Testing**: Test the app with actual ESP32 hardware and firmware
2. **Icons**: Add custom icons (.icns for macOS, .ico for Windows)
3. **Code Signing**: Sign the executables for production distribution
4. **DMG Creation**: Package macOS app in a DMG for easier distribution
5. **Windows Installer**: Consider creating an NSIS or WiX installer
## Troubleshooting
### "App is damaged" on macOS
```bash
xattr -cr dist/ESP32_Flasher.app
```
### Port permission issues on Linux
```bash
sudo usermod -a -G dialout $USER
```
(Logout/login required)
### Build fails on macOS
Make sure virtual environment is active:
```bash
source venv/bin/activate
```

View File

@@ -0,0 +1,43 @@
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['gui_flasher.py'],
pathex=[],
binaries=[],
datas=[('requirements.txt', '.')],
hiddenimports=['serial.tools.list_ports'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='ESP32_Flasher',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True, # Set to False for windowed mode
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

View File

@@ -0,0 +1,45 @@
# -*- mode: python ; coding: utf-8 -*-
# PyInstaller spec file for Windows executable
block_cipher = None
a = Analysis(
['gui_flasher.py'],
pathex=[],
binaries=[],
datas=[('requirements.txt', '.')],
hiddenimports=['serial.tools.list_ports'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='ESP32_Flasher',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False, # Set to False for windowed mode (no console)
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=None, # Add path to .ico file if you have one
)

View File

@@ -0,0 +1,56 @@
# -*- mode: python ; coding: utf-8 -*-
# PyInstaller spec file for macOS executable
block_cipher = None
a = Analysis(
['gui_flasher.py'],
pathex=[],
binaries=[],
datas=[('requirements.txt', '.')],
hiddenimports=['serial.tools.list_ports'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='ESP32_Flasher',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False, # macOS app bundle (no console window)
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
# Create macOS app bundle
app = BUNDLE(
exe,
name='ESP32_Flasher.app',
icon=None, # Add path to .icns file if you have one
bundle_identifier='com.soundshot.esp32flasher',
info_plist={
'NSPrincipalClass': 'NSApplication',
'NSHighResolutionCapable': 'True',
},
)

View File

@@ -0,0 +1,81 @@
# -*- mode: python ; coding: utf-8 -*-
# PyInstaller spec file for Windows executable (Web-based UI)
block_cipher = None
import os
import sys
# Find esptool installation dynamically
try:
import esptool
esptool_dir = os.path.dirname(esptool.__file__)
print(f"Found esptool at: {esptool_dir}")
except ImportError:
print("Warning: esptool not found, stub files will not be included")
esptool_dir = None
# Build datas list - include all esptool data files
datas_list = [
('templates', 'templates'),
('static', 'static'),
]
# Add esptool targets directory (includes stub_flasher JSON files)
if esptool_dir and os.path.exists(os.path.join(esptool_dir, 'targets')):
targets_dir = os.path.join(esptool_dir, 'targets')
datas_list.append((targets_dir, 'esptool/targets'))
print(f"Including esptool targets from: {targets_dir}")
a = Analysis(
['web_flasher.py'],
pathex=[],
binaries=[],
datas=datas_list,
hiddenimports=[
'serial.tools.list_ports',
'flask',
'jinja2',
'werkzeug',
'flask_socketio',
'socketio',
'engineio.async_drivers.threading',
'esptool',
'esptool.cmds',
'esptool.loader',
'esptool.util',
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='ESP32_Flasher',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False, # No console window
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=None, # Add path to .ico file if you have one
)

View File

@@ -0,0 +1,69 @@
# -*- mode: python ; coding: utf-8 -*-
# PyInstaller spec file for macOS executable (Web-based UI)
block_cipher = None
a = Analysis(
['web_flasher.py'],
pathex=[],
binaries=[],
datas=[
('templates', 'templates'),
('static', 'static'),
],
hiddenimports=[
'serial.tools.list_ports',
'flask',
'jinja2',
'werkzeug',
'flask_socketio',
'socketio',
'engineio.async_drivers.threading',
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='ESP32_Flasher',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False, # macOS app bundle (no console window)
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
# Create macOS app bundle
app = BUNDLE(
exe,
name='ESP32_Flasher.app',
icon=None, # Add path to .icns file if you have one
bundle_identifier='com.soundshot.esp32flasher',
info_plist={
'NSPrincipalClass': 'NSApplication',
'NSHighResolutionCapable': 'True',
'CFBundleShortVersionString': '1.0.0',
'CFBundleDisplayName': 'ESP32 Flasher',
},
)

148
flash_tool/README.md Normal file
View File

@@ -0,0 +1,148 @@
# ESP32 Firmware Flasher GUI
A cross-platform GUI tool for flashing ESP32 firmware packages.
## Features
- Simple, user-friendly graphical interface
- Cross-platform support (Windows, macOS, Linux)
- Automatic serial port detection
- Firmware package validation (.zip files)
- Real-time flashing progress output
- Configurable flash parameters
## Building Executables
### Universal Build (Recommended)
The easiest way to build for your current platform:
```bash
python build.py
```
This script will:
1. Detect your platform automatically
2. Install required dependencies
3. Build the appropriate executable
### Platform-Specific Builds
#### macOS
```bash
./build_macos.sh
```
This creates an application bundle at `dist/ESP32_Flasher.app`
To run:
```bash
open dist/ESP32_Flasher.app
```
#### Windows
```batch
build_from_spec.bat
```
This creates an executable at `dist\ESP32_Flasher.exe`
#### Linux
```bash
python build.py
```
Creates an executable at `dist/ESP32_Flasher`
## Running Without Building
You can run the GUI directly with Python:
```bash
python gui_flasher.py
```
### Requirements
```bash
pip install -r requirements.txt
```
## Firmware Package Format
The flasher expects a `.zip` file containing these files:
- `bootloader.bin` - ESP32 bootloader
- `partition-table.bin` - Partition table
- `ota_data_initial.bin` - OTA data
- `soundshot.bin` - Main application firmware
## Usage
1. Launch the ESP32_Flasher application
2. Select your ESP32's serial port (or click Refresh)
3. Browse and select your firmware `.zip` package
4. (Optional) Adjust flash settings if needed
5. Click "Flash Firmware"
6. Wait for the process to complete
## Flash Settings
Default settings work for most ESP32 boards:
- **Chip**: esp32
- **Baud Rate**: 460800 (faster) or 115200 (more reliable)
- **Flash Mode**: dio
- **Flash Freq**: 40m
- **Flash Size**: 2MB (adjust based on your board)
## Troubleshooting
### Port Not Detected
- Ensure ESP32 is connected via USB
- Install CH340/CP2102 drivers if needed (Windows/macOS)
- On Linux, add user to `dialout` group: `sudo usermod -a -G dialout $USER`
### Flash Failed
- Try lower baud rate (115200)
- Press and hold BOOT button during flash
- Check USB cable quality
- Verify firmware package integrity
### macOS: "App is damaged"
Run this command to allow the app:
```bash
xattr -cr dist/ESP32_Flasher.app
```
## Development
### Project Structure
```
flash_tool/
├── gui_flasher.py # Main GUI application
├── ESP32_Flasher_macOS.spec # PyInstaller spec for macOS
├── ESP32_Flasher_Windows.spec # PyInstaller spec for Windows
├── build.py # Universal build script
├── build_macos.sh # macOS build script
├── build_from_spec.bat # Windows build script
├── requirements.txt # Python dependencies
└── README.md # This file
```
### Dependencies
- **tkinter**: GUI framework (included with Python)
- **pyserial**: Serial port communication
- **esptool**: ESP32 flashing utility
- **pyinstaller**: Executable builder
## License
[Your license here]
## Support
For issues and questions, please contact [your contact info].

BIN
flash_tool/SoundShot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

171
flash_tool/build.py Executable file
View File

@@ -0,0 +1,171 @@
#!/usr/bin/env python3
"""
Universal build script for ESP32 Flasher GUI
Automatically detects platform and builds the appropriate executable
"""
import sys
import subprocess
import platform
import os
def get_platform():
"""Detect the current platform"""
system = platform.system()
if system == "Darwin":
return "macos"
elif system == "Windows":
return "windows"
elif system == "Linux":
return "linux"
else:
return "unknown"
def setup_venv():
"""Create and setup virtual environment if on macOS"""
if platform.system() == "Darwin":
if not os.path.exists("venv"):
print("Creating virtual environment (required on macOS)...")
try:
subprocess.run([sys.executable, "-m", "venv", "venv"], check=True)
print("✓ Virtual environment created")
except subprocess.CalledProcessError as e:
print(f"✗ Failed to create virtual environment: {e}")
return False
# Use venv Python for the rest of the script
venv_python = os.path.join("venv", "bin", "python3")
if os.path.exists(venv_python):
return venv_python
return sys.executable
def install_dependencies(python_exe=None):
"""Install required Python packages"""
if python_exe is None:
python_exe = sys.executable
print("Installing dependencies...")
packages = ["pyinstaller", "esptool", "pyserial"]
try:
subprocess.run([python_exe, "-m", "pip", "install"] + packages, check=True)
print("✓ Dependencies installed successfully")
return True
except subprocess.CalledProcessError as e:
print(f"✗ Failed to install dependencies: {e}")
return False
def build_macos():
"""Build macOS application bundle"""
print("\n=== Building for macOS ===")
spec_file = "ESP32_Flasher_macOS.spec"
if not os.path.exists(spec_file):
print(f"✗ Error: {spec_file} not found")
return False
try:
subprocess.run(["pyinstaller", spec_file], check=True)
if os.path.exists("dist/ESP32_Flasher.app"):
print("\n✓ Build complete!")
print(f"\nApplication created at: dist/ESP32_Flasher.app")
print("\nTo run the application:")
print(" open dist/ESP32_Flasher.app")
return True
else:
print("\n✗ Build failed - application not found in dist folder")
return False
except subprocess.CalledProcessError as e:
print(f"\n✗ Build failed: {e}")
return False
def build_windows():
"""Build Windows executable"""
print("\n=== Building for Windows ===")
spec_file = "ESP32_Flasher_Windows.spec"
if not os.path.exists(spec_file):
print(f"✗ Error: {spec_file} not found")
return False
try:
subprocess.run(["pyinstaller", spec_file], check=True)
if os.path.exists("dist/ESP32_Flasher.exe"):
print("\n✓ Build complete!")
print(f"\nExecutable created at: dist\\ESP32_Flasher.exe")
print("\nYou can now distribute ESP32_Flasher.exe to users.")
return True
else:
print("\n✗ Build failed - executable not found in dist folder")
return False
except subprocess.CalledProcessError as e:
print(f"\n✗ Build failed: {e}")
return False
def build_linux():
"""Build Linux executable"""
print("\n=== Building for Linux ===")
print("Note: Linux users typically prefer to run Python scripts directly.")
print("Creating standalone executable anyway...")
# Use macOS spec as template for Linux (both use ELF format)
spec_file = "ESP32_Flasher_macOS.spec"
if not os.path.exists(spec_file):
print(f"✗ Error: {spec_file} not found")
return False
try:
subprocess.run(["pyinstaller", spec_file], check=True)
if os.path.exists("dist/ESP32_Flasher"):
print("\n✓ Build complete!")
print(f"\nExecutable created at: dist/ESP32_Flasher")
print("\nTo run:")
print(" ./dist/ESP32_Flasher")
return True
else:
print("\n✗ Build failed - executable not found in dist folder")
return False
except subprocess.CalledProcessError as e:
print(f"\n✗ Build failed: {e}")
return False
def main():
"""Main build function"""
print("=== ESP32 Flasher - Universal Build Script ===\n")
# Detect platform
current_platform = get_platform()
print(f"Detected platform: {current_platform}")
if current_platform == "unknown":
print("✗ Unsupported platform")
return 1
# Setup virtual environment if needed (macOS)
python_exe = setup_venv()
# Install dependencies
if not install_dependencies(python_exe):
return 1
# Build for detected platform
success = False
if current_platform == "macos":
success = build_macos()
elif current_platform == "windows":
success = build_windows()
elif current_platform == "linux":
success = build_linux()
return 0 if success else 1
if __name__ == "__main__":
sys.exit(main())

7
flash_tool/build_exe.bat Normal file
View File

@@ -0,0 +1,7 @@
@echo off
echo Building ESP32 Flasher Executable...
cd /d "%~dp0"
python build_executable.py
echo.
echo Build complete! Check the 'dist' folder for ESP32_Flasher.exe
pause

View File

@@ -0,0 +1,49 @@
#!/usr/bin/env python3
"""
Build script to create standalone executable for ESP32 Flash GUI
"""
import subprocess
import sys
import os
from pathlib import Path
def install_requirements():
"""Install required packages"""
print("Installing requirements...")
subprocess.check_call([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"])
def build_executable():
"""Build standalone executable using PyInstaller"""
print("Building standalone executable...")
# PyInstaller command
cmd = [
sys.executable, "-m", "PyInstaller",
"--onefile", # Single executable file
"--windowed", # No console window (remove if you want console)
"--name", "ESP32_Flasher",
"--icon", "icon.ico" if Path("icon.ico").exists() else None,
"--add-data", "requirements.txt;.", # Include requirements file
"gui_flasher.py"
]
# Remove None values
cmd = [arg for arg in cmd if arg is not None]
subprocess.check_call(cmd)
print("\nExecutable built successfully!")
print("Find it in the 'dist' folder as 'ESP32_Flasher.exe'")
def main():
os.chdir(Path(__file__).parent)
try:
install_requirements()
build_executable()
except subprocess.CalledProcessError as e:
print(f"Error: {e}")
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,24 @@
@echo off
echo === ESP32 Flasher - Windows Build Script ===
echo.
echo Installing dependencies...
pip install pyinstaller esptool pyserial
echo.
echo Building Windows executable...
pyinstaller ESP32_Flasher_Windows.spec
echo.
if exist "dist\ESP32_Flasher.exe" (
echo Build complete!
echo.
echo Executable created at: dist\ESP32_Flasher.exe
echo.
echo You can now distribute ESP32_Flasher.exe to users.
) else (
echo Build failed - executable not found in dist folder
exit /b 1
)
pause

45
flash_tool/build_macos.sh Executable file
View File

@@ -0,0 +1,45 @@
#!/bin/bash
# Build script for macOS executable
echo "=== ESP32 Flasher - macOS Build Script ==="
echo ""
# Check if running on macOS
if [[ "$OSTYPE" != "darwin"* ]]; then
echo "❌ Error: This script is for macOS only."
echo " Use build_from_spec.bat on Windows."
exit 1
fi
# Create virtual environment if it doesn't exist
if [ ! -d "venv" ]; then
echo "Creating virtual environment..."
python3 -m venv venv
fi
echo "Activating virtual environment..."
source venv/bin/activate
echo "Installing dependencies..."
pip install pyinstaller esptool pyserial
echo ""
echo "Building macOS application bundle..."
pyinstaller ESP32_Flasher_macOS.spec
echo ""
if [ -d "dist/ESP32_Flasher.app" ]; then
echo "✓ Build complete!"
echo ""
echo "Application created at: dist/ESP32_Flasher.app"
echo ""
echo "To run the application:"
echo " open dist/ESP32_Flasher.app"
echo ""
echo "To distribute, you can:"
echo " 1. Zip the .app bundle"
echo " 2. Create a DMG installer (requires additional tools)"
else
echo "❌ Build failed - application not found in dist folder"
exit 1
fi

43
flash_tool/build_web_macos.sh Executable file
View File

@@ -0,0 +1,43 @@
#!/bin/bash
# Build script for macOS executable (Web-based UI)
echo "=== ESP32 Flasher (Web UI) - macOS Build Script ==="
echo ""
# Check if running on macOS
if [[ "$OSTYPE" != "darwin"* ]]; then
echo "❌ Error: This script is for macOS only."
echo " Use build_web_windows.bat on Windows."
exit 1
fi
# Create virtual environment if it doesn't exist
if [ ! -d "venv" ]; then
echo "Creating virtual environment..."
python3 -m venv venv
fi
echo "Activating virtual environment..."
source venv/bin/activate
echo "Installing dependencies..."
pip install -r requirements.txt
echo ""
echo "Building macOS application bundle..."
pyinstaller ESP32_WebFlasher_macOS.spec
echo ""
if [ -d "dist/ESP32_Flasher.app" ]; then
echo "✓ Build complete!"
echo ""
echo "Application created at: dist/ESP32_Flasher.app"
echo ""
echo "To run the application:"
echo " open dist/ESP32_Flasher.app"
echo ""
echo "The app will open in your default web browser!"
else
echo "❌ Build failed - application not found in dist folder"
exit 1
fi

View File

@@ -0,0 +1,32 @@
@echo off
echo === ESP32 Flasher (Web UI) - Windows Build Script ===
echo.
REM Check if running on Windows
if not "%OS%"=="Windows_NT" (
echo Error: This script is for Windows only.
echo Use build_web_macos.sh on macOS.
exit /b 1
)
echo Installing dependencies...
pip install -r requirements.txt
echo.
echo Building Windows executable...
pyinstaller ESP32_WebFlasher_Windows.spec
echo.
if exist "dist\ESP32_Flasher.exe" (
echo Build complete!
echo.
echo Executable created at: dist\ESP32_Flasher.exe
echo.
echo The app will open in your default web browser!
echo You can now distribute ESP32_Flasher.exe to users.
) else (
echo Build failed - executable not found in dist folder
exit /b 1
)
pause

View File

@@ -0,0 +1,14 @@
@echo off
echo Installing auto-py-to-exe...
pip install auto-py-to-exe esptool pyserial
echo.
echo Starting auto-py-to-exe GUI...
echo.
echo Configure the following settings:
echo - Script Location: gui_flasher.py
echo - Onefile: One File
echo - Console Window: Console Based (or Window Based if you prefer no console)
echo - Additional Files: Add requirements.txt
echo.
auto-py-to-exe

View File

@@ -27,8 +27,10 @@ def main():
# Define binaries and offsets # Define binaries and offsets
bootloader = root / "build" / "bootloader" / "bootloader.bin" bootloader = root / "build" / "bootloader" / "bootloader.bin"
firmware = root / "build" / f"{project}.bin" firmware = root / "build" / f"{project}.bin"
ota_intitial = root / "build" / "ota_data_initial.bin"
partition = root / "build" / "partition_table" / "partition-table.bin" partition = root / "build" / "partition_table" / "partition-table.bin"
# Verify binaries exist # Verify binaries exist
for f in [bootloader, firmware, partition]: for f in [bootloader, firmware, partition]:
if not f.exists(): if not f.exists():
@@ -47,8 +49,9 @@ def main():
"--flash-mode", flash_mode, # ✅ hyphenated flags "--flash-mode", flash_mode, # ✅ hyphenated flags
"--flash-freq", flash_freq, "--flash-freq", flash_freq,
"--flash-size", flash_size, "--flash-size", flash_size,
"0x0", str(bootloader), "0x1000", str(bootloader),
"0x10000", str(firmware), "0x20000", str(firmware),
"0x11000", str(ota_intitial),
"0x8000", str(partition) "0x8000", str(partition)
] ]

337
flash_tool/gui_flasher.py Normal file
View File

@@ -0,0 +1,337 @@
#!/usr/bin/env python3
"""
ESP32 Firmware Flash GUI Tool
Simple GUI interface for flashing firmware packages to ESP32 devices
"""
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
import subprocess
import sys
import threading
import zipfile
import tempfile
import os
from pathlib import Path
import serial.tools.list_ports
class ESP32FlasherGUI:
def __init__(self, root):
self.root = root
self.root.title("ESP32 Firmware Flasher")
self.root.geometry("600x500")
# Configure colors for dark mode compatibility
self.setup_colors()
# Variables
self.port_var = tk.StringVar()
self.firmware_path_var = tk.StringVar()
self.temp_dir = None
self.setup_ui()
self.refresh_ports()
def setup_colors(self):
"""Configure colors that work in both light and dark mode"""
# Try to detect dark mode on macOS
try:
import subprocess
result = subprocess.run(
['defaults', 'read', '-g', 'AppleInterfaceStyle'],
capture_output=True,
text=True
)
is_dark_mode = (result.returncode == 0 and 'Dark' in result.stdout)
except:
is_dark_mode = False
if is_dark_mode:
# Dark mode colors
self.bg_color = '#2b2b2b'
self.fg_color = '#ffffff'
self.text_bg = '#1e1e1e'
self.text_fg = '#d4d4d4'
self.button_bg = '#3c3c3c'
else:
# Light mode colors
self.bg_color = '#f0f0f0'
self.fg_color = '#000000'
self.text_bg = '#ffffff'
self.text_fg = '#000000'
self.button_bg = '#e0e0e0'
# Configure root window
self.root.configure(bg=self.bg_color)
def setup_ui(self):
# Main frame
main_frame = tk.Frame(self.root, bg=self.bg_color, padx=10, pady=10)
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# Configure grid weights
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
main_frame.columnconfigure(1, weight=1)
# Port selection
tk.Label(main_frame, text="Serial Port:", bg=self.bg_color, fg=self.fg_color).grid(
row=0, column=0, sticky=tk.W, pady=5)
port_frame = tk.Frame(main_frame, bg=self.bg_color)
port_frame.grid(row=0, column=1, sticky=(tk.W, tk.E), pady=5)
port_frame.columnconfigure(0, weight=1)
self.port_combo = ttk.Combobox(port_frame, textvariable=self.port_var, state="readonly")
self.port_combo.grid(row=0, column=0, sticky=(tk.W, tk.E), padx=(0, 5))
tk.Button(port_frame, text="Refresh", command=self.refresh_ports,
bg=self.button_bg, fg=self.fg_color, relief=tk.RAISED).grid(row=0, column=1)
# Firmware package selection
tk.Label(main_frame, text="Firmware Package:", bg=self.bg_color, fg=self.fg_color).grid(
row=1, column=0, sticky=tk.W, pady=5)
firmware_frame = tk.Frame(main_frame, bg=self.bg_color)
firmware_frame.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=5)
firmware_frame.columnconfigure(0, weight=1)
self.firmware_entry = tk.Entry(firmware_frame, textvariable=self.firmware_path_var,
state="readonly", bg=self.text_bg, fg=self.text_fg,
relief=tk.SUNKEN, borderwidth=2)
self.firmware_entry.grid(row=0, column=0, sticky=(tk.W, tk.E), padx=(0, 5))
tk.Button(firmware_frame, text="Browse", command=self.browse_firmware,
bg=self.button_bg, fg=self.fg_color, relief=tk.RAISED).grid(row=0, column=1)
# Flash settings frame
settings_frame = tk.LabelFrame(main_frame, text="Flash Settings",
bg=self.bg_color, fg=self.fg_color,
relief=tk.GROOVE, borderwidth=2, padx=5, pady=5)
settings_frame.grid(row=2, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=10)
settings_frame.columnconfigure(1, weight=1)
# Flash settings
tk.Label(settings_frame, text="Chip:", bg=self.bg_color, fg=self.fg_color).grid(
row=0, column=0, sticky=tk.W, pady=2, padx=(0, 10))
self.chip_var = tk.StringVar(value="esp32")
tk.Entry(settings_frame, textvariable=self.chip_var, width=15,
bg=self.text_bg, fg=self.text_fg, relief=tk.SUNKEN).grid(row=0, column=1, sticky=tk.W, pady=2)
tk.Label(settings_frame, text="Baud Rate:", bg=self.bg_color, fg=self.fg_color).grid(
row=1, column=0, sticky=tk.W, pady=2, padx=(0, 10))
self.baud_var = tk.StringVar(value="460800")
tk.Entry(settings_frame, textvariable=self.baud_var, width=15,
bg=self.text_bg, fg=self.text_fg, relief=tk.SUNKEN).grid(row=1, column=1, sticky=tk.W, pady=2)
tk.Label(settings_frame, text="Flash Mode:", bg=self.bg_color, fg=self.fg_color).grid(
row=2, column=0, sticky=tk.W, pady=2, padx=(0, 10))
self.flash_mode_var = tk.StringVar(value="dio")
tk.Entry(settings_frame, textvariable=self.flash_mode_var, width=15,
bg=self.text_bg, fg=self.text_fg, relief=tk.SUNKEN).grid(row=2, column=1, sticky=tk.W, pady=2)
tk.Label(settings_frame, text="Flash Freq:", bg=self.bg_color, fg=self.fg_color).grid(
row=3, column=0, sticky=tk.W, pady=2, padx=(0, 10))
self.flash_freq_var = tk.StringVar(value="40m")
tk.Entry(settings_frame, textvariable=self.flash_freq_var, width=15,
bg=self.text_bg, fg=self.text_fg, relief=tk.SUNKEN).grid(row=3, column=1, sticky=tk.W, pady=2)
tk.Label(settings_frame, text="Flash Size:", bg=self.bg_color, fg=self.fg_color).grid(
row=4, column=0, sticky=tk.W, pady=2, padx=(0, 10))
self.flash_size_var = tk.StringVar(value="2MB")
tk.Entry(settings_frame, textvariable=self.flash_size_var, width=15,
bg=self.text_bg, fg=self.text_fg, relief=tk.SUNKEN).grid(row=4, column=1, sticky=tk.W, pady=2)
# Flash button
self.flash_button = tk.Button(main_frame, text="Flash Firmware", command=self.flash_firmware,
bg=self.button_bg, fg=self.fg_color,
relief=tk.RAISED, padx=20, pady=5,
font=('TkDefaultFont', 10, 'bold'))
self.flash_button.grid(row=3, column=0, columnspan=2, pady=10)
# Progress bar
self.progress = ttk.Progressbar(main_frame, mode='indeterminate')
self.progress.grid(row=4, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)
# Log output
tk.Label(main_frame, text="Output:", bg=self.bg_color, fg=self.fg_color).grid(
row=5, column=0, sticky=tk.W, pady=(10, 0))
self.log_text = scrolledtext.ScrolledText(
main_frame,
height=15,
width=70,
bg=self.text_bg,
fg=self.text_fg,
insertbackground=self.text_fg, # Cursor color
relief=tk.SUNKEN,
borderwidth=2
)
self.log_text.grid(row=6, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)
main_frame.rowconfigure(6, weight=1)
def refresh_ports(self):
"""Refresh the list of available serial ports"""
ports = [port.device for port in serial.tools.list_ports.comports()]
self.port_combo['values'] = ports
if ports and not self.port_var.get():
self.port_var.set(ports[0])
def browse_firmware(self):
"""Browse for firmware package (.zip file)"""
filename = filedialog.askopenfilename(
title="Select Firmware Package",
filetypes=[("ZIP files", "*.zip"), ("All files", "*.*")]
)
if filename:
self.firmware_path_var.set(filename)
self.validate_firmware_package(filename)
def validate_firmware_package(self, zip_path):
"""Validate that the ZIP contains required firmware files"""
required_files = [
"bootloader.bin",
"soundshot.bin",
"ota_data_initial.bin",
"partition-table.bin"
]
try:
with zipfile.ZipFile(zip_path, 'r') as zip_file:
zip_contents = zip_file.namelist()
missing_files = []
for required_file in required_files:
if required_file not in zip_contents:
missing_files.append(required_file)
if missing_files:
messagebox.showwarning(
"Invalid Package",
f"Missing required files:\n{', '.join(missing_files)}"
)
return False
else:
self.log_message(f"✓ Valid firmware package: {Path(zip_path).name}")
return True
except zipfile.BadZipFile:
messagebox.showerror("Error", "Invalid ZIP file")
return False
def log_message(self, message):
"""Add message to log output"""
self.log_text.insert(tk.END, message + "\n")
self.log_text.see(tk.END)
self.root.update()
def extract_firmware_package(self, zip_path):
"""Extract firmware package to temporary directory"""
if self.temp_dir:
# Clean up previous temp dir
import shutil
shutil.rmtree(self.temp_dir, ignore_errors=True)
self.temp_dir = tempfile.mkdtemp(prefix="esp32_flash_")
with zipfile.ZipFile(zip_path, 'r') as zip_file:
zip_file.extractall(self.temp_dir)
return self.temp_dir
def flash_firmware(self):
"""Flash the firmware to ESP32"""
# Validate inputs
if not self.port_var.get():
messagebox.showerror("Error", "Please select a serial port")
return
if not self.firmware_path_var.get():
messagebox.showerror("Error", "Please select a firmware package")
return
# Disable flash button and start progress
self.flash_button.config(state="disabled")
self.progress.start()
self.log_text.delete(1.0, tk.END)
# Run flash in separate thread to prevent UI freezing
thread = threading.Thread(target=self._flash_worker)
thread.daemon = True
thread.start()
def _flash_worker(self):
"""Worker thread for flashing firmware"""
try:
# Extract firmware package
self.log_message("Extracting firmware package...")
temp_dir = self.extract_firmware_package(self.firmware_path_var.get())
# Define file paths
bootloader = os.path.join(temp_dir, "bootloader.bin")
firmware = os.path.join(temp_dir, "soundshot.bin")
ota_initial = os.path.join(temp_dir, "ota_data_initial.bin")
partition = os.path.join(temp_dir, "partition-table.bin")
# Build esptool command
cmd = [
sys.executable, "-m", "esptool",
"--chip", self.chip_var.get(),
"--port", self.port_var.get(),
"--baud", self.baud_var.get(),
"--before", "default_reset",
"--after", "hard_reset",
"write-flash",
"--flash-mode", self.flash_mode_var.get(),
"--flash-freq", self.flash_freq_var.get(),
"--flash-size", self.flash_size_var.get(),
"0x1000", bootloader,
"0x20000", firmware,
"0x11000", ota_initial,
"0x8000", partition
]
self.log_message(f"Running: {' '.join(cmd)}\n")
# Run esptool
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1,
universal_newlines=True
)
# Stream output
for line in process.stdout:
self.root.after(0, self.log_message, line.rstrip())
process.wait()
if process.returncode == 0:
self.root.after(0, self.log_message, "\n✓ Flash completed successfully!")
self.root.after(0, messagebox.showinfo, "Success", "Firmware flashed successfully!")
else:
self.root.after(0, self.log_message, f"\n✗ Flash failed with return code {process.returncode}")
self.root.after(0, messagebox.showerror, "Error", "Flash operation failed!")
except Exception as e:
self.root.after(0, self.log_message, f"\n✗ Error: {str(e)}")
self.root.after(0, messagebox.showerror, "Error", f"Flash operation failed: {str(e)}")
finally:
# Re-enable UI
self.root.after(0, self.progress.stop)
self.root.after(0, lambda: self.flash_button.config(state="normal"))
# Clean up temp directory
if self.temp_dir:
import shutil
shutil.rmtree(self.temp_dir, ignore_errors=True)
self.temp_dir = None
def main():
root = tk.Tk()
app = ESP32FlasherGUI(root)
root.mainloop()
if __name__ == "__main__":
main()

View File

@@ -3,11 +3,7 @@ import serial
import sys import sys
import time import time
from pathlib import Path from pathlib import Path
# import colorama
# colorama.just_fix_windows_console()
print("\x1b[0;32mThis should be green\x1b[0m")
print("\x1b[0;31mThis should be red\x1b[0m")
def main(): def main():
# Load config # Load config
@@ -27,6 +23,10 @@ def main():
try: try:
with serial.Serial(port, baud, timeout=0.5) as ser: with serial.Serial(port, baud, timeout=0.5) as ser:
# 🔧 Clear DTR and RTS lines (common for ESP32 reset handling)
ser.dtr = False
ser.rts = False
print("[Serial Monitor] Press Ctrl+C to exit.\n") print("[Serial Monitor] Press Ctrl+C to exit.\n")
while True: while True:
if ser.in_waiting: if ser.in_waiting:

View File

@@ -0,0 +1,6 @@
esptool>=4.0
pyserial>=3.5
pyinstaller>=5.0
flask>=2.3.0
flask-socketio>=5.3.0
python-socketio>=5.11.0

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

View File

@@ -0,0 +1,570 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SoundShot Firmware Flasher</title>
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: linear-gradient(135deg, #d94125 0%, #a33318 100%);
min-height: 100vh;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
}
.container {
background: white;
border-radius: 12px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
max-width: 700px;
width: 100%;
padding: 40px;
}
.header {
text-align: center;
margin-bottom: 30px;
background: linear-gradient(135deg, #2c2c2c 0%, #1a1a1a 100%);
padding: 40px 20px 30px 20px;
margin: -40px -40px 30px -40px;
border-radius: 12px 12px 0 0;
}
.logo {
max-width: 450px;
width: 100%;
height: auto;
margin-bottom: 10px;
}
h1 {
color: #c04026;
margin-bottom: 10px;
font-size: 28px;
}
.subtitle {
color: #d0d0d0;
font-size: 14px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
color: #333;
font-weight: 500;
font-size: 14px;
}
input[type="text"],
select {
width: 100%;
padding: 12px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 14px;
transition: border-color 0.3s;
}
input[type="text"]:focus,
select:focus {
outline: none;
border-color: #c04026;
}
.file-input-wrapper {
position: relative;
overflow: hidden;
display: inline-block;
width: 100%;
}
.file-input-wrapper input[type="file"] {
position: absolute;
left: -9999px;
}
.file-input-label {
display: block;
padding: 12px;
border: 2px dashed #e0e0e0;
border-radius: 8px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
color: #666;
}
.file-input-label:hover {
border-color: #c04026;
background: #fef6f4;
}
.file-selected {
border-color: #c04026;
border-style: solid;
background: #fef6f4;
color: #c04026;
}
.btn {
width: 100%;
padding: 14px;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
}
.btn-primary {
background: linear-gradient(135deg, #d94125 0%, #a33318 100%);
color: white;
}
.btn-primary:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(217, 65, 37, 0.3);
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.output-section {
margin-top: 30px;
}
.output-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.output-toggle {
background: #f0f0f0;
border: none;
border-radius: 6px;
padding: 8px 16px;
cursor: pointer;
font-size: 13px;
color: #333;
transition: background 0.3s;
}
.output-toggle:hover {
background: #e0e0e0;
}
.output-box {
background: #1e1e1e;
color: #d4d4d4;
padding: 20px;
border-radius: 8px;
font-family: 'Courier New', monospace;
font-size: 13px;
max-height: 400px;
overflow-y: auto;
line-height: 1.6;
white-space: pre-wrap;
word-wrap: break-word;
display: none;
}
.output-box.expanded {
display: block;
}
.output-box:empty::before {
content: 'Output will appear here...';
color: #666;
}
.progress-bar {
width: 100%;
height: 8px;
background: #e0e0e0;
border-radius: 4px;
overflow: hidden;
margin: 20px 0;
display: none;
}
.progress-bar.active {
display: block;
}
.progress-bar-fill {
height: 100%;
background: linear-gradient(90deg, #d94125, #a33318);
width: 0%;
transition: width 0.3s ease-out;
}
.progress-bar-fill.indeterminate {
animation: progress 2s ease-in-out infinite;
}
@keyframes progress {
0% { width: 0%; }
50% { width: 100%; }
100% { width: 0%; }
}
.progress-text {
text-align: center;
font-size: 13px;
color: #c04026;
font-weight: 600;
margin-top: 5px;
display: none;
}
.progress-text.active {
display: block;
}
.status-message {
padding: 12px;
border-radius: 8px;
margin: 15px 0;
font-weight: 500;
display: none;
}
.status-message.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
display: block;
}
.status-message.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
display: block;
}
.refresh-btn {
padding: 8px 16px;
background: #f0f0f0;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
color: #333;
margin-left: 10px;
transition: background 0.3s;
}
.refresh-btn:hover {
background: #e0e0e0;
}
.port-section {
display: flex;
align-items: flex-end;
gap: 10px;
}
.port-section .form-group {
flex: 1;
margin-bottom: 0;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<img src="/static/SoundShot.png" alt="SoundShot" class="logo">
<p class="subtitle">Firmware Flasher</p>
</div>
<form id="flashForm" onsubmit="return false;">
<div class="port-section">
<div class="form-group">
<label for="port">Serial Port</label>
<select id="port" name="port" required>
<option value="">Select a port...</option>
</select>
</div>
<button type="button" class="refresh-btn" onclick="refreshPorts()">🔄 Refresh</button>
</div>
<div class="form-group">
<label for="firmware">Firmware Package (.zip)</label>
<div class="file-input-wrapper">
<input type="file" id="firmware" name="firmware" accept=".zip" required>
<label for="firmware" class="file-input-label" id="fileLabel">
📦 Click to select firmware package
</label>
</div>
</div>
<!-- Hidden fields with default values -->
<input type="hidden" id="chip" name="chip" value="esp32">
<input type="hidden" id="baud" name="baud" value="460800">
<input type="hidden" id="flash_mode" name="flash_mode" value="dio">
<input type="hidden" id="flash_freq" name="flash_freq" value="40m">
<input type="hidden" id="flash_size" name="flash_size" value="2MB">
<button type="submit" class="btn btn-primary" id="flashBtn">
⚡ Flash Firmware
</button>
<div class="progress-bar" id="progressBar">
<div class="progress-bar-fill" id="progressBarFill"></div>
</div>
<div class="progress-text" id="progressText">0%</div>
<div class="status-message" id="statusMessage"></div>
</form>
<div class="output-section">
<div class="output-header">
<label>Output Log</label>
<button type="button" class="output-toggle" id="outputToggle" onclick="toggleOutput()">▼ Show Details</button>
</div>
<div class="output-box" id="output"></div>
</div>
</div>
<script>
let statusCheckInterval = null;
let socket = null;
let heartbeatInterval = null;
// Toggle output visibility
function toggleOutput() {
const output = document.getElementById('output');
const toggle = document.getElementById('outputToggle');
if (output.classList.contains('expanded')) {
output.classList.remove('expanded');
toggle.textContent = '▼ Show Details';
} else {
output.classList.add('expanded');
toggle.textContent = '▲ Hide Details';
}
}
// Initialize Socket.IO connection
function initWebSocket() {
socket = io();
socket.on('connect', () => {
console.log('WebSocket connected');
// Start sending heartbeats every 2 seconds
heartbeatInterval = setInterval(() => {
socket.emit('heartbeat');
}, 2000);
});
socket.on('disconnect', () => {
console.log('WebSocket disconnected');
if (heartbeatInterval) {
clearInterval(heartbeatInterval);
heartbeatInterval = null;
}
});
socket.on('heartbeat_ack', (data) => {
// Heartbeat acknowledged
});
}
// Load ports on page load
document.addEventListener('DOMContentLoaded', () => {
initWebSocket();
refreshPorts();
});
// Clean up on page unload
window.addEventListener('beforeunload', () => {
if (socket) {
socket.disconnect();
}
});
// Handle file selection
document.getElementById('firmware').addEventListener('change', function(e) {
const fileLabel = document.getElementById('fileLabel');
if (e.target.files.length > 0) {
fileLabel.textContent = '✓ ' + e.target.files[0].name;
fileLabel.classList.add('file-selected');
} else {
fileLabel.textContent = '📦 Click to select firmware package';
fileLabel.classList.remove('file-selected');
}
});
async function refreshPorts() {
const portSelect = document.getElementById('port');
portSelect.innerHTML = '<option value="">Loading ports...</option>';
try {
const response = await fetch('/api/ports');
const data = await response.json();
if (data.success) {
portSelect.innerHTML = '<option value="">Select a port...</option>';
data.ports.forEach(port => {
const option = document.createElement('option');
option.value = port.device;
option.textContent = `${port.device} - ${port.description}`;
portSelect.appendChild(option);
});
} else {
portSelect.innerHTML = '<option value="">Error loading ports</option>';
}
} catch (error) {
portSelect.innerHTML = '<option value="">Error loading ports</option>';
console.error('Error:', error);
}
}
document.getElementById('flashForm').addEventListener('submit', async (e) => {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
const flashBtn = document.getElementById('flashBtn');
const progressBar = document.getElementById('progressBar');
const progressBarFill = document.getElementById('progressBarFill');
const progressText = document.getElementById('progressText');
const output = document.getElementById('output');
const outputToggle = document.getElementById('outputToggle');
const statusMessage = document.getElementById('statusMessage');
// Disable form
flashBtn.disabled = true;
flashBtn.textContent = '⚡ Flashing...';
progressBar.classList.add('active');
progressBarFill.classList.add('indeterminate');
progressBarFill.style.width = '0%';
progressText.classList.add('active');
progressText.textContent = '0%';
output.textContent = '';
output.classList.remove('expanded');
outputToggle.textContent = '▼ Show Details';
statusMessage.style.display = 'none';
statusMessage.className = 'status-message';
// Create FormData
const formData = new FormData(e.target);
try {
const response = await fetch('/api/flash', {
method: 'POST',
body: formData
});
const data = await response.json();
if (data.success) {
// Start checking status
statusCheckInterval = setInterval(checkStatus, 500);
} else {
showError(data.error);
resetForm();
}
} catch (error) {
showError('Failed to start flash: ' + error.message);
resetForm();
}
});
async function checkStatus() {
try {
const response = await fetch('/api/status');
const data = await response.json();
// Update output
const output = document.getElementById('output');
output.textContent = data.output.join('\n');
output.scrollTop = output.scrollHeight;
// Update progress bar
const progressBarFill = document.getElementById('progressBarFill');
const progressText = document.getElementById('progressText');
if (data.progress !== undefined && data.progress > 0) {
// Switch from indeterminate to determinate
progressBarFill.classList.remove('indeterminate');
progressBarFill.style.width = data.progress + '%';
progressText.textContent = data.progress.toFixed(1) + '%';
}
// Check if complete
if (!data.running && statusCheckInterval) {
clearInterval(statusCheckInterval);
statusCheckInterval = null;
const statusMessage = document.getElementById('statusMessage');
if (data.success === true) {
progressBarFill.style.width = '100%';
progressText.textContent = '100%';
statusMessage.textContent = '✓ Flash completed successfully!';
statusMessage.className = 'status-message success';
statusMessage.style.display = 'block';
} else if (data.success === false) {
statusMessage.textContent = '✗ Flash operation failed. Check the output log for details.';
statusMessage.className = 'status-message error';
statusMessage.style.display = 'block';
}
resetForm();
}
} catch (error) {
console.error('Error checking status:', error);
clearInterval(statusCheckInterval);
statusCheckInterval = null;
resetForm();
}
}
function showError(message) {
const statusMessage = document.getElementById('statusMessage');
statusMessage.textContent = '✗ ' + message;
statusMessage.className = 'status-message error';
statusMessage.style.display = 'block';
}
function resetForm() {
const flashBtn = document.getElementById('flashBtn');
const progressBar = document.getElementById('progressBar');
const progressBarFill = document.getElementById('progressBarFill');
const progressText = document.getElementById('progressText');
flashBtn.disabled = false;
flashBtn.textContent = '⚡ Flash Firmware';
// Delay hiding progress to let user see completion
setTimeout(() => {
progressBar.classList.remove('active');
progressText.classList.remove('active');
progressBarFill.classList.remove('indeterminate');
progressBarFill.style.width = '0%';
}, 2000);
}
</script>
</body>
</html>

343
flash_tool/web_flasher.py Normal file
View File

@@ -0,0 +1,343 @@
#!/usr/bin/env python3
"""
ESP32 Firmware Flash Web Server
Web-based GUI interface for flashing firmware packages to ESP32 devices
"""
from flask import Flask, render_template, request, jsonify, send_from_directory
from flask_socketio import SocketIO, emit
import subprocess
import sys
import threading
import zipfile
import tempfile
import os
import shutil
from pathlib import Path
import serial.tools.list_ports
import webbrowser
import socket
import time
import signal
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024 # 100MB max file size
app.config['SECRET_KEY'] = 'esp32-flasher-secret-key'
socketio = SocketIO(app, cors_allowed_origins="*")
# Global state
flash_status = {
'running': False,
'output': [],
'success': None,
'progress': 0
}
# Client connection tracking
client_connected = False
last_heartbeat = time.time()
shutdown_timer = None
def get_free_port():
"""Find a free port to run the server on"""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(('', 0))
s.listen(1)
port = s.getsockname()[1]
return port
@app.route('/')
def index():
"""Serve the main page"""
return render_template('index.html')
@app.route('/static/<path:filename>')
def serve_static(filename):
"""Serve static files"""
static_dir = os.path.join(os.path.dirname(__file__), 'static')
return send_from_directory(static_dir, filename)
@app.route('/api/ports')
def get_ports():
"""Get list of available serial ports"""
try:
ports = [{'device': port.device, 'description': port.description}
for port in serial.tools.list_ports.comports()]
return jsonify({'success': True, 'ports': ports})
except Exception as e:
return jsonify({'success': False, 'error': str(e)})
@app.route('/api/flash', methods=['POST'])
def flash_firmware():
"""Flash firmware to ESP32"""
global flash_status
if flash_status['running']:
return jsonify({'success': False, 'error': 'Flash operation already in progress'})
# Get form data
port = request.form.get('port')
chip = request.form.get('chip', 'esp32')
baud = request.form.get('baud', '460800')
flash_mode = request.form.get('flash_mode', 'dio')
flash_freq = request.form.get('flash_freq', '40m')
flash_size = request.form.get('flash_size', '2MB')
# Get uploaded file
if 'firmware' not in request.files:
return jsonify({'success': False, 'error': 'No firmware file uploaded'})
firmware_file = request.files['firmware']
if firmware_file.filename == '':
return jsonify({'success': False, 'error': 'No firmware file selected'})
# Save and extract firmware
try:
# Create temp directory
temp_dir = tempfile.mkdtemp(prefix="esp32_flash_")
zip_path = os.path.join(temp_dir, 'firmware.zip')
firmware_file.save(zip_path)
# Extract firmware
with zipfile.ZipFile(zip_path, 'r') as zip_file:
zip_file.extractall(temp_dir)
# Start flash in background thread
flash_status = {'running': True, 'output': [], 'success': None, 'progress': 0}
thread = threading.Thread(
target=flash_worker,
args=(temp_dir, port, chip, baud, flash_mode, flash_freq, flash_size)
)
thread.daemon = True
thread.start()
return jsonify({'success': True, 'message': 'Flash started'})
except Exception as e:
return jsonify({'success': False, 'error': str(e)})
@app.route('/api/status')
def get_status():
"""Get current flash status"""
return jsonify(flash_status)
@socketio.on('connect')
def handle_connect():
"""Handle client connection"""
global client_connected, last_heartbeat, shutdown_timer
client_connected = True
last_heartbeat = time.time()
# Cancel any pending shutdown
if shutdown_timer:
shutdown_timer.cancel()
shutdown_timer = None
print('Client connected')
@socketio.on('disconnect')
def handle_disconnect():
"""Handle client disconnection"""
global client_connected, shutdown_timer
client_connected = False
print('Client disconnected - scheduling shutdown in 1 second...')
# Schedule shutdown after 5 seconds
shutdown_timer = threading.Timer(1.0, shutdown_server)
shutdown_timer.daemon = True
shutdown_timer.start()
@socketio.on('heartbeat')
def handle_heartbeat():
"""Handle heartbeat from client"""
global last_heartbeat
last_heartbeat = time.time()
emit('heartbeat_ack', {'timestamp': last_heartbeat})
def shutdown_server():
"""Gracefully shutdown the server"""
print('\nNo clients connected. Shutting down server...')
# Give a moment for any pending operations
time.sleep(1)
# Shutdown Flask
try:
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
# Alternative shutdown method
os.kill(os.getpid(), signal.SIGTERM)
else:
func()
except:
# Force exit as last resort
os._exit(0)
def flash_worker(temp_dir, port, chip, baud, flash_mode, flash_freq, flash_size):
"""Background worker for flashing firmware"""
global flash_status
import re
import io
from contextlib import redirect_stdout, redirect_stderr
try:
# Define file paths
bootloader = os.path.join(temp_dir, "bootloader.bin")
firmware = os.path.join(temp_dir, "soundshot.bin")
ota_initial = os.path.join(temp_dir, "ota_data_initial.bin")
partition = os.path.join(temp_dir, "partition-table.bin")
# Verify files exist
required_files = [bootloader, firmware, ota_initial, partition]
for file_path in required_files:
if not os.path.exists(file_path):
flash_status['output'].append(f"ERROR: Missing file {os.path.basename(file_path)}")
flash_status['success'] = False
flash_status['running'] = False
return
# Build esptool command arguments
esptool_args = [
"--chip", chip,
"--port", port,
"--baud", baud,
"--before", "default_reset",
"--after", "hard_reset",
"write-flash",
"--flash-mode", flash_mode,
"--flash-freq", flash_freq,
"--flash-size", flash_size,
"0x1000", bootloader,
"0x20000", firmware,
"0x11000", ota_initial,
"0x8000", partition
]
flash_status['output'].append(f"Running esptool with args: {' '.join(esptool_args)}")
flash_status['output'].append("")
# Import and run esptool directly (works in both script and EXE)
import esptool
# Fix esptool data path for PyInstaller
if getattr(sys, 'frozen', False):
# Running as compiled executable
bundle_dir = sys._MEIPASS
esptool_targets = os.path.join(bundle_dir, 'esptool', 'targets')
if os.path.exists(esptool_targets):
# Override esptool's resource path
esptool.RESOURCES_DIR = bundle_dir
# Capture stdout/stderr
output_buffer = io.StringIO()
# Backup original sys.argv and replace with our arguments
original_argv = sys.argv
sys.argv = ['esptool.py'] + esptool_args
# Run esptool and capture output
return_code = 0
# Regex to parse progress lines
# Example: "Writing at 0x0011325c... (85 %)"
# or "Writing at 0x0011325c [========================> ] 85.3% 622592/730050 bytes..."
progress_pattern = re.compile(r'(\d+(?:\.\d+)?)\s*%')
# Save original stdout/stderr
original_stdout = sys.stdout
original_stderr = sys.stderr
try:
# Custom output class to capture and stream esptool output
class OutputCapture:
def __init__(self):
self.buffer = []
def write(self, text):
if text and text.strip():
lines = text.rstrip().split('\n')
for line in lines:
flash_status['output'].append(line)
self.buffer.append(line)
# Try to extract progress percentage
match = progress_pattern.search(line)
if match:
try:
percent = float(match.group(1))
flash_status['progress'] = percent
except ValueError:
pass
return len(text)
def flush(self):
pass
capture = OutputCapture()
# Redirect stdout/stderr to our capture object
with redirect_stdout(capture), redirect_stderr(capture):
esptool.main()
except SystemExit as e:
return_code = e.code if e.code is not None else 0
finally:
# Restore original sys.argv and stdout/stderr
sys.argv = original_argv
sys.stdout = original_stdout
sys.stderr = original_stderr
if return_code == 0:
flash_status['output'].append("")
flash_status['output'].append("✓ Flash completed successfully!")
flash_status['success'] = True
flash_status['progress'] = 100
else:
flash_status['output'].append("")
flash_status['output'].append(f"✗ Flash failed with return code {return_code}")
flash_status['success'] = False
except Exception as e:
flash_status['output'].append(f"✗ Error: {str(e)}")
flash_status['success'] = False
finally:
flash_status['running'] = False
# Clean up temp directory
try:
shutil.rmtree(temp_dir, ignore_errors=True)
except:
pass
def open_browser(port):
"""Open browser to the application"""
url = f'http://127.0.0.1:{port}'
webbrowser.open(url)
def main():
"""Run the web server"""
import logging
# Disable Flask request logging to avoid colorama issues with stdout redirection
log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR)
port = get_free_port()
print(f"Starting ESP32 Flasher on port {port}...")
print(f"Open your browser to: http://127.0.0.1:{port}")
print(f"Server will automatically shut down when browser is closed.\n")
# Open browser after short delay
timer = threading.Timer(1.5, open_browser, args=[port])
timer.daemon = True
timer.start()
# Run Flask server with SocketIO
try:
socketio.run(app, host='127.0.0.1', port=port, debug=False, allow_unsafe_werkzeug=True, log_output=False)
except KeyboardInterrupt:
print('\nShutting down...')
except SystemExit:
print('Server stopped.')
if __name__ == "__main__":
main()

View File

@@ -1,6 +1,4 @@
<<<<<<< HEAD idf_component_register(SRCS "battery.c" "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
idf_component_register(SRCS "system.c.LOCAL.c" "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
"gui.c" "gui.c"
"lsm6dsv.c" "lsm6dsv.c"
INCLUDE_DIRS "." INCLUDE_DIRS "."
@@ -10,19 +8,6 @@ idf_component_register(SRCS "system.c.LOCAL.c" "bt_app.c" "system.c" "bubble.c"
"esp_lvgl_port" "esp_lvgl_port"
"esp_timer" "esp_timer"
"nvs_flash" "nvs_flash"
"bt") "bt"
======= "esp_adc")
idf_component_register(SRCS "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
"gui.c"
"lsm6dsv.c"
INCLUDE_DIRS "."
REQUIRES "driver"
"esp_lcd"
"lvgl"
"esp_lvgl_port"
"esp_timer"
"nvs_flash"
"bt")
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442

271
main/battery.c Normal file
View File

@@ -0,0 +1,271 @@
#include "battery.h"
#include "system.h"
#include "gpio.h"
#include "esp_log.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
static const char *TAG = "battery";
static adc_oneshot_unit_handle_t adc1_handle = NULL;
static adc_cali_handle_t adc1_cali_handle = NULL;
static bool adc_calibration_enabled = false;
// ADC Calibration initialization
static bool adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle)
{
adc_cali_handle_t handle = NULL;
esp_err_t ret = ESP_FAIL;
bool calibrated = false;
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
if (!calibrated) {
ESP_LOGI(TAG, "Calibration scheme: Curve Fitting");
adc_cali_curve_fitting_config_t cali_config = {
.unit_id = unit,
.chan = channel,
.atten = atten,
.bitwidth = BATTERY_ADC_WIDTH,
};
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
#endif
#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
if (!calibrated) {
ESP_LOGI(TAG, "Calibration scheme: Line Fitting");
adc_cali_line_fitting_config_t cali_config = {
.unit_id = unit,
.atten = atten,
.bitwidth = BATTERY_ADC_WIDTH,
};
ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
#endif
*out_handle = handle;
if (ret == ESP_OK) {
ESP_LOGI(TAG, "ADC calibration successful");
} else {
ESP_LOGW(TAG, "ADC calibration failed: %s", esp_err_to_name(ret));
}
return calibrated;
}
esp_err_t battery_init(void)
{
esp_err_t ret;
// Configure ADC1 oneshot mode
adc_oneshot_unit_init_cfg_t init_config = {
.unit_id = ADC_UNIT_1,
};
ret = adc_oneshot_new_unit(&init_config, &adc1_handle);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize ADC unit: %s", esp_err_to_name(ret));
return ret;
}
// Configure ADC channel
adc_oneshot_chan_cfg_t config = {
.bitwidth = BATTERY_ADC_WIDTH,
.atten = BATTERY_ADC_ATTEN,
};
ret = adc_oneshot_config_channel(adc1_handle, BATTERY_ADC_CHANNEL, &config);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to configure ADC channel: %s", esp_err_to_name(ret));
return ret;
}
// Initialize calibration
adc_calibration_enabled = adc_calibration_init(ADC_UNIT_1, BATTERY_ADC_CHANNEL,
BATTERY_ADC_ATTEN, &adc1_cali_handle);
ESP_LOGI(TAG, "Battery monitoring initialized on GPIO34 (ADC1_CH6)");
return ESP_OK;
}
int battery_read_raw(void)
{
int adc_raw = 0;
esp_err_t ret = adc_oneshot_read(adc1_handle, BATTERY_ADC_CHANNEL, &adc_raw);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to read ADC: %s", esp_err_to_name(ret));
return -1;
}
return adc_raw;
}
int battery_read_voltage_mv(void)
{
int voltage_mv = 0;
int adc_sum = 0;
int valid_samples = 0;
// Take multiple samples and average
for (int i = 0; i < BATTERY_SAMPLES; i++) {
int adc_raw = battery_read_raw();
if (adc_raw >= 0) {
adc_sum += adc_raw;
valid_samples++;
}
vTaskDelay(pdMS_TO_TICKS(1)); // Small delay between samples
}
if (valid_samples == 0) {
ESP_LOGE(TAG, "No valid ADC samples");
return -1;
}
int adc_avg = adc_sum / valid_samples;
// Convert to voltage using calibration if available
if (adc_calibration_enabled) {
esp_err_t ret = adc_cali_raw_to_voltage(adc1_cali_handle, adc_avg, &voltage_mv);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "Calibration conversion failed, using raw calculation");
adc_calibration_enabled = false; // Disable for future reads
}
}
// Fallback to manual calculation if calibration not available
if (!adc_calibration_enabled) {
// Simple linear conversion for 12-bit ADC with 12dB attenuation
// Approximate range: 0-3300mV for 0-4095 raw values
voltage_mv = (adc_avg * 3300) / 4095;
}
// Apply voltage divider ratio to get actual battery voltage
voltage_mv = (int)(voltage_mv * BATTERY_VOLTAGE_DIVIDER_RATIO);
return voltage_mv;
}
int battery_get_percentage(void)
{
int voltage_mv = battery_read_voltage_mv();
if (voltage_mv < 0) {
return -1;
}
// Clamp to min/max range
if (voltage_mv >= BATTERY_VOLTAGE_MAX) {
return 100;
}
if (voltage_mv <= BATTERY_VOLTAGE_MIN) {
return 0;
}
// Linear interpolation between min and max
int percentage = ((voltage_mv - BATTERY_VOLTAGE_MIN) * 100) /
(BATTERY_VOLTAGE_MAX - BATTERY_VOLTAGE_MIN);
return percentage;
}
// Battery monitoring task
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)
{
// 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);
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);
}
// 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));
}
}
void battery_start_monitoring_task(void)
{
xTaskCreate(battery_monitoring_task, "battery_task", 3072, NULL, 5, NULL);
ESP_LOGI(TAG, "Battery monitoring task created");
}

56
main/battery.h Normal file
View File

@@ -0,0 +1,56 @@
#ifndef BATTERY_H
#define BATTERY_H
#include <stdint.h>
#include "esp_err.h"
// 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_BITWIDTH_12 // 12-bit resolution (0-4095)
// Battery voltage calculation constants
// Adjust these based on your voltage divider circuit
#define BATTERY_VOLTAGE_DIVIDER_RATIO 2.0f // Example: R1=R2, adjust for your circuit
#define BATTERY_SAMPLES 16 // Number of samples to average
// Battery percentage thresholds (in millivolts at battery)
#define BATTERY_VOLTAGE_MAX 4200 // Fully charged Li-Ion
#define BATTERY_VOLTAGE_MIN 3000 // Empty Li-Ion (cutoff)
/**
* @brief Initialize battery monitoring ADC
*
* @return esp_err_t ESP_OK on success
*/
esp_err_t battery_init(void);
/**
* @brief Read raw ADC value from battery pin
*
* @return int Raw ADC value (0-4095)
*/
int battery_read_raw(void);
/**
* @brief Read battery voltage in millivolts (averaged)
*
* @return int Battery voltage in mV
*/
int battery_read_voltage_mv(void);
/**
* @brief Get battery percentage (0-100)
*
* @return int Battery percentage
*/
int battery_get_percentage(void);
/**
* @brief Start battery monitoring task
*
* This task periodically reads battery voltage and updates system state
*/
void battery_start_monitoring_task(void);
#endif // BATTERY_H

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include "esp_bt_defs.h"
/* log tag */ /* log tag */
#define BT_APP_CORE_TAG "BT_APP_CORE" #define BT_APP_CORE_TAG "BT_APP_CORE"
@@ -67,4 +68,47 @@ void bt_app_task_shut_down(void);
void bt_app_init(void); void bt_app_init(void);
/* Bluetooth device management for GUI */
#define MAX_BT_DEVICES 8 // Reduced from 20 to save memory
#define MAX_BT_NAME_LEN 32
typedef struct {
esp_bd_addr_t bda;
char name[MAX_BT_NAME_LEN];
bool is_paired;
int rssi;
} bt_device_info_t;
typedef struct {
bt_device_info_t devices[MAX_BT_DEVICES];
int count;
bool discovery_active;
} bt_device_list_t;
/* Get current device list for GUI display */
bt_device_list_t* bt_get_device_list(void);
/* Start device discovery */
bool bt_start_discovery(void);
/* Stop device discovery */
bool bt_stop_discovery(void);
/* Connect to specific device by index in device list */
bool bt_connect_device(int device_index);
/* Clear discovered devices (keep paired devices) */
void bt_clear_discovered_devices(void);
/* Clear all devices from the device list (paired and discovered) */
void bt_clear_all_devices(void);
/* Disconnect from currently connected device */
void bt_disconnect_current_device(void);
/* Volume control functions */
void bt_volume_up(void);
void bt_volume_down(void);
int bt_get_current_volume(void);
#endif /* __BT_APP_CORE_H__ */ #endif /* __BT_APP_CORE_H__ */

View File

@@ -1,13 +1,18 @@
<<<<<<< HEAD
#ifndef GPIO_H #ifndef GPIO_H
#define GPIO_H #define GPIO_H
// Define keypad buttons // Define keypad buttons
#define PIN_NUM_BUTTON_0 36 #define PIN_NUM_BUTTON_0 36
#define PIN_NUM_BUTTON_1 39 #define PIN_NUM_BUTTON_1 39
#define PIN_NUM_LED_1 32 #define PIN_NUM_LED_0 32
#define PIN_NUM_LED_2 33 #define PIN_NUM_LED_1 33
#define PIN_NUM_LED_2 25
#define PIN_NUM_nON 26 #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 // Define GPIO pins
@@ -27,34 +32,4 @@
#define PIN_NUM_BK_LIGHT 5 // Backlight control pin, -1 if not used #define PIN_NUM_BK_LIGHT 5 // Backlight control pin, -1 if not used
#endif #endif
=======
#ifndef GPIO_H
#define GPIO_H
// Define keypad buttons
#define PIN_NUM_BUTTON_0 36
#define PIN_NUM_BUTTON_1 39
#define PIN_NUM_LED_1 32
#define PIN_NUM_LED_2 33
#define PIN_NUM_nON 26
// Define GPIO pins
#ifdef DEVKIT
#define PIN_NUM_MOSI 23 // SDA pin for LCD
#define PIN_NUM_CLK 18 // SCL pin for LCD
#define PIN_NUM_CS 2 // CS pin
#define PIN_NUM_DC 12 // Data/Command pin (RS)
#define PIN_NUM_RST 13 // Reset pin
#define PIN_NUM_BK_LIGHT -1 // Backlight control pin, -1 if not used
#else
#define PIN_NUM_MOSI 23 // SDA pin for LCD
#define PIN_NUM_CLK 18 // SCL pin for LCD
#define PIN_NUM_CS 12 // CS pin
#define PIN_NUM_DC 15 // Data/Command pin (RS)
#define PIN_NUM_RST 13 // Reset pin
#define PIN_NUM_BK_LIGHT 5 // Backlight control pin, -1 if not used
#endif
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
#endif #endif

1997
main/gui.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,3 @@
<<<<<<< HEAD
#ifndef _KEYPAD_H #ifndef _KEYPAD_H
#define _KEYPAD_H #define _KEYPAD_H
@@ -21,28 +20,4 @@ typedef enum
void keypad_start(void); void keypad_start(void);
QueueHandle_t keypad_getQueue(void); QueueHandle_t keypad_getQueue(void);
=======
#ifndef _KEYPAD_H
#define _KEYPAD_H
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
typedef enum
{
KEY0 = (1 << 0),
KEY1 = (1 << 1),
} keycode_t;
#define KEY_SHORT_PRESS 0
#define KEY_LONG_PRESS 4
#define KEY_UP KEY0
#define KEY_DOWN KEY1
void keypad_start(void);
QueueHandle_t keypad_getQueue(void);
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
#endif #endif

View File

@@ -53,7 +53,7 @@
#if LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN #if LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN
/*Size of the memory available for `lv_malloc()` in bytes (>= 2kB)*/ /*Size of the memory available for `lv_malloc()` in bytes (>= 2kB)*/
#define LV_MEM_SIZE (64 * 1024U) /*[bytes]*/ #define LV_MEM_SIZE (32 * 1024U) /*[bytes]*/
/*Size of the memory expand for `lv_malloc()` in bytes*/ /*Size of the memory expand for `lv_malloc()` in bytes*/
#define LV_MEM_POOL_EXPAND_SIZE 0 #define LV_MEM_POOL_EXPAND_SIZE 0
@@ -481,7 +481,7 @@
/*Montserrat fonts with ASCII range and some symbols using bpp = 4 /*Montserrat fonts with ASCII range and some symbols using bpp = 4
*https://fonts.google.com/specimen/Montserrat*/ *https://fonts.google.com/specimen/Montserrat*/
#define LV_FONT_MONTSERRAT_8 0 #define LV_FONT_MONTSERRAT_8 1
#define LV_FONT_MONTSERRAT_10 0 #define LV_FONT_MONTSERRAT_10 0
#define LV_FONT_MONTSERRAT_12 0 #define LV_FONT_MONTSERRAT_12 0
#define LV_FONT_MONTSERRAT_14 1 #define LV_FONT_MONTSERRAT_14 1
@@ -511,7 +511,7 @@
/*Pixel perfect monospace fonts*/ /*Pixel perfect monospace fonts*/
#define LV_FONT_UNSCII_8 0 #define LV_FONT_UNSCII_8 0
#define LV_FONT_UNSCII_16 0 #define LV_FONT_UNSCII_16 1
/*Optionally declare custom fonts here. /*Optionally declare custom fonts here.
*You can use these fonts as default font too and they will be available globally. *You can use these fonts as default font too and they will be available globally.
@@ -519,7 +519,7 @@
#define LV_FONT_CUSTOM_DECLARE #define LV_FONT_CUSTOM_DECLARE
/*Always set a default font*/ /*Always set a default font*/
#define LV_FONT_DEFAULT &lv_font_montserrat_14 #define LV_FONT_DEFAULT &lv_font_unscii_16
/*Enable handling large font and/or fonts with a lot of characters. /*Enable handling large font and/or fonts with a lot of characters.
*The limit depends on the font size, font face and bpp. *The limit depends on the font size, font face and bpp.

View File

@@ -1,4 +1,3 @@
<<<<<<< HEAD
/* /*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
* *
@@ -14,6 +13,7 @@
#include "esp_system.h" #include "esp_system.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/timers.h" #include "freertos/timers.h"
@@ -28,18 +28,54 @@
#include "gpio.h" #include "gpio.h"
#include "keypad.h" #include "keypad.h"
#include "system.h" #include "system.h"
#include "battery.h"
static const char *TAG = "main";
/********************************* /*********************************
* STATIC FUNCTION DECLARATIONS * STATIC FUNCTION DECLARATIONS
********************************/ ********************************/
static void print_heap_info(const char* tag) {
size_t free_heap = esp_get_free_heap_size();
size_t min_free_heap = esp_get_minimum_free_heap_size();
size_t largest_block = heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT);
ESP_LOGI(TAG, "[%s] Free heap: %zu bytes, Min free: %zu bytes, Largest block: %zu bytes",
tag, free_heap, min_free_heap, largest_block);
}
typedef struct { typedef struct {
float alpha; // smoothing factor, 0<alpha<1 float alpha; // smoothing factor, 0<alpha<1
float prev_output; // y[n-1] float prev_output; // y[n-1]
} LowPassFilter; } LowPassFilter;
#define ALPHA_MIN 0.2f
#define ALPHA_MAX 0.4f
// Clamp function to bound value between min and max
double clamp(double value, double min, double max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
// Compute alpha using linear ramp
float compute_alpha_linear(double x, float alpha_min, float alpha_max, float threshold) {
float abs_x = fabs(x);
float t = clamp(abs_x / threshold, 0.0, 1.0); // Normalize |x| to [0,1]
return alpha_min + (alpha_max - alpha_min) * t;
}
// Compute sigmoid-based dynamic alpha
float compute_alpha_sigmoid(float x, float alpha_min, float alpha_max, float k, float midpoint) {
float abs_x = fabs(x);
float exponent = -k * (abs_x - midpoint);
float sigmoid = 1.0 / (1.0 + exp(exponent));
return alpha_min + (alpha_max - alpha_min) * sigmoid;
}
// Initialize the filter. alpha = smoothing factor. // Initialize the filter. alpha = smoothing factor.
// e.g. alpha = dt/(RC+dt) if you derive from cutoff freq & sample time. // e.g. alpha = dt/(RC+dt) if you derive from cutoff freq & sample time.
// init_output can be 0 or your first sample to avoid startup glitch. // init_output can be 0 or your first sample to avoid startup glitch.
@@ -51,7 +87,11 @@ static inline void LPF_Init(LowPassFilter *f, float alpha, float init_output) {
// Run one input sample through the filter. // Run one input sample through the filter.
// Returns y[n] = alpha * x[n] + (1-alpha) * y[n-1]. // Returns y[n] = alpha * x[n] + (1-alpha) * y[n-1].
static inline float LPF_Update(LowPassFilter *f, float input) { static inline float LPF_Update(LowPassFilter *f, float input) {
float out = f->alpha * input + (1.0f - f->alpha) * f->prev_output;
//float alpha = compute_alpha_sigmoid(input, ALPHA_MIN, ALPHA_MAX, 1.0f, 0.0f);
float alpha = compute_alpha_linear(input, ALPHA_MIN, ALPHA_MAX, 2.0f);
float out = alpha * input + (1.0f - alpha) * f->prev_output;
//float out = f->alpha * input + (1.0f - f->alpha) * f->prev_output;
f->prev_output = out; f->prev_output = out;
return out; return out;
} }
@@ -60,26 +100,52 @@ static inline float LPF_Update(LowPassFilter *f, float input) {
/********************************* /*********************************
* STATIC VARIABLE DEFINITIONS * STATIC VARIABLE DEFINITIONS
********************************/ ********************************/
static const char *TAG = "main";
/********************************* /*********************************
* STATIC FUNCTION DEFINITIONS * STATIC FUNCTION DEFINITIONS
********************************/ ********************************/
// Helper function to set LED with verification
static void set_led_level(gpio_num_t pin, uint32_t level)
{
esp_err_t err = gpio_set_level(pin, level);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to set GPIO %d to %lu: %s", pin, level, esp_err_to_name(err));
}
}
static void init_gpio(void) static void init_gpio(void)
{ {
gpio_config_t io_conf; gpio_config_t io_conf;
// Reset GPIO peripheral to clear any SPI/peripheral configurations
gpio_reset_pin(PIN_NUM_LED_0);
gpio_reset_pin(PIN_NUM_LED_1);
gpio_reset_pin(PIN_NUM_LED_2);
// Configure output GPIO // Configure output GPIO
io_conf.pin_bit_mask = (1ULL << PIN_NUM_LED_1) | (1ULL << PIN_NUM_LED_2); io_conf.pin_bit_mask = (1ULL << PIN_NUM_LED_0) | (1ULL << PIN_NUM_LED_1) | (1ULL << PIN_NUM_LED_2);
io_conf.mode = GPIO_MODE_OUTPUT; io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.intr_type = GPIO_INTR_DISABLE; io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE; io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_config(&io_conf); gpio_config(&io_conf);
// Set initial state
gpio_set_level(PIN_NUM_LED_0, 0);
gpio_set_level(PIN_NUM_LED_1, 0);
gpio_set_level(PIN_NUM_LED_2, 0);
ESP_LOGI(TAG, "LED pins configured: %d, %d, %d", PIN_NUM_LED_0, PIN_NUM_LED_1, PIN_NUM_LED_2);
// Configure charge status input GPIO
io_conf.pin_bit_mask = (1ULL << PIN_NUM_CHARGE_STATUS);
io_conf.mode = GPIO_MODE_INPUT;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_config(&io_conf);
#if 1 #if 1
@@ -219,6 +285,7 @@ static void imu_task(void *pvParameters) {
void app_main(void) void app_main(void)
{ {
print_heap_info("STARTUP");
/* initialize NVS — it is used to store PHY calibration data */ /* initialize NVS — it is used to store PHY calibration data */
esp_err_t ret = nvs_flash_init(); esp_err_t ret = nvs_flash_init();
@@ -227,30 +294,41 @@ void app_main(void)
ret = nvs_flash_init(); ret = nvs_flash_init();
} }
ESP_ERROR_CHECK(ret); ESP_ERROR_CHECK(ret);
print_heap_info("POST_NVS");
init_gpio(); init_gpio();
print_heap_info("POST_GPIO");
system_init(); system_init();
print_heap_info("POST_SYSTEM");
// Initialize IMU // Initialize IMU
ESP_ERROR_CHECK(lsm6dsv_init(22, 21)); // SCL = IO14, SDA = IO15 ESP_ERROR_CHECK(lsm6dsv_init(22, 21)); // SCL = IO14, SDA = IO15`
print_heap_info("POST_IMU");
// Create IMU task // Create IMU task
TaskHandle_t h = xTaskCreate(imu_task, "imu_task", 4096, NULL, 5, NULL); TaskHandle_t h = NULL;
xTaskCreate(imu_task, "imu_task", 2048, NULL, 5, &h);
print_heap_info("POST_IMU_TASK");
bt_app_init(); bt_app_init();
print_heap_info("POST_BLUETOOTH");
// Initialize battery monitoring
ESP_ERROR_CHECK(battery_init());
battery_start_monitoring_task();
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);
gui_start(); gui_start();
print_heap_info("POST_GUI");
gpio_set_level(PIN_NUM_LED_2, 1); gpio_set_level(PIN_NUM_LED_2, 1);
battery_start_monitoring_task();
#if 0 #if 0
keypad_start(); keypad_start();
@@ -286,300 +364,10 @@ void app_main(void)
#else #else
while (1) while (1)
{ {
vTaskDelay(pdMS_TO_TICKS(1000));
system_processNvsRequests();
vTaskDelay(pdMS_TO_TICKS(10));
} }
#endif #endif
} }
=======
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <inttypes.h>
#include "math.h"
#include "esp_system.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "driver/gpio.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "bt_app.h"
#include "lsm6dsv.h"
#include "gui.h"
#include "gpio.h"
#include "keypad.h"
#include "system.h"
/*********************************
* STATIC FUNCTION DECLARATIONS
********************************/
typedef struct {
float alpha; // smoothing factor, 0<alpha<1
float prev_output; // y[n-1]
} LowPassFilter;
// Initialize the filter. alpha = smoothing factor.
// e.g. alpha = dt/(RC+dt) if you derive from cutoff freq & sample time.
// init_output can be 0 or your first sample to avoid startup glitch.
static inline void LPF_Init(LowPassFilter *f, float alpha, float init_output) {
f->alpha = alpha;
f->prev_output = init_output;
}
// Run one input sample through the filter.
// Returns y[n] = alpha * x[n] + (1-alpha) * y[n-1].
static inline float LPF_Update(LowPassFilter *f, float input) {
float out = f->alpha * input + (1.0f - f->alpha) * f->prev_output;
f->prev_output = out;
return out;
}
/*********************************
* STATIC VARIABLE DEFINITIONS
********************************/
static const char *TAG = "main";
/*********************************
* STATIC FUNCTION DEFINITIONS
********************************/
static void init_gpio(void)
{
gpio_config_t io_conf;
// Configure output GPIO
io_conf.pin_bit_mask = (1ULL << PIN_NUM_LED_1) | (1ULL << PIN_NUM_LED_2);
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_config(&io_conf);
#if 1
// Configure output power signal
gpio_set_level(PIN_NUM_nON, 1);
io_conf.pin_bit_mask = (1ULL << PIN_NUM_nON);
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_config(&io_conf);
#endif
// Configure LCD Backlight GPIO
io_conf.pin_bit_mask = (1ULL << PIN_NUM_BK_LIGHT);
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_config(&io_conf);
}
// IMU task to read sensor data
static void imu_task(void *pvParameters) {
lsm6dsv_data_t imu_data;
char data_str[128];
float roll, pitch, yaw;
lsm6dsv_fifo_t fifo;
ImuData_t imu;
LowPassFilter lpf;
LPF_Init(&lpf, FILTER_COEFF, 0);
while (1) {
// uint8_t samples = lsm6dsv_fifo_ready();
//ESP_LOGI(TAG, "Samples: %d", samples);
// while (samples)
// {
// lsm6dsv_fifo_read(&fifo);
// // snprintf(data_str, sizeof(data_str),
// // "tag: %d, count: %d, (%d, %d, %d)",
// // fifo.tag, fifo.count, x, y, z);
// // ESP_LOGI(TAG, "%s", data_str);
// samples--;
// }
// lsm6dsv_getAttitude(&fifo, &roll, &pitch, &yaw);
// snprintf(data_str, sizeof(data_str),
// "r: %0.3f, p: %0.3f, y: %0.3f",
// roll, pitch, yaw);
// ESP_LOGI(TAG, "%s", data_str);
float xz;
float yz;
float xy;
#if 1
if (lsm6dsv_read_data(&imu_data) == ESP_OK)
{
// snprintf(data_str, sizeof(data_str),
// "Acc: %.2f, %.2f, %.2f; "
// "Gyro: %.2f, %.2f, %.2f (%d)\n",
// imu_data.acc_x, imu_data.acc_y, imu_data.acc_z,
// imu_data.gyro_x, imu_data.gyro_y, imu_data.gyro_z, lsm6dsv_fifo_ready());
#if 1
imu.raw[ANGLE_XZ] = atan2f((float)imu_data.acc_z, (float)imu_data.acc_x) * 180 / M_PI;
imu.raw[ANGLE_YZ] = atan2f((float)imu_data.acc_z, (float)imu_data.acc_y) * 180 / M_PI;
imu.raw[ANGLE_XY] = atan2f((float)imu_data.acc_x, (float)imu_data.acc_y) * 180 / M_PI;
float angle;
angle = system_getAngle();
if (angle > MAX_INDICATION_ANGLE)
{
angle = MAX_INDICATION_ANGLE;
}
else
if (angle < -MAX_INDICATION_ANGLE)
{
angle = -MAX_INDICATION_ANGLE;
}
// low pass filter the angle measurement
imu.angle = LPF_Update(&lpf, angle);
//imu.filtered[ANGLE_XY] = LPF_Update(&lpf, imu.raw[ANGLE_XY]);
system_setImuData(imu);
// snprintf(data_str, sizeof(data_str),
// "(%.2f, %.2f, %.2f)", xy, yz, xy);
#endif
#if 0
snprintf(data_str, sizeof(data_str),
"(%.1f, %.1f, %.1f) (%.2f, %.2f, %.2f)",
imu.raw[ANGLE_XZ], imu.raw[ANGLE_YZ], imu.raw[ANGLE_XY],
(float)imu_data.acc_x, (float)imu_data.acc_y, (float)imu_data.acc_z);
ESP_LOGI(TAG, "%s", data_str);
#endif
// Update label text in LVGL task
//lv_label_set_text(imu_label, data_str);
}
#endif
vTaskDelay(pdMS_TO_TICKS(100)); // Update every 100ms
}
}
/*********************************
* MAIN ENTRY POINT
********************************/
void app_main(void)
{
/* initialize NVS — it is used to store PHY calibration data */
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
init_gpio();
system_init();
// Initialize IMU
ESP_ERROR_CHECK(lsm6dsv_init(22, 21)); // SCL = IO14, SDA = IO15
// Create IMU task
TaskHandle_t h = xTaskCreate(imu_task, "imu_task", 4096, NULL, 5, NULL);
bt_app_init();
gui_start();
gpio_set_level(PIN_NUM_LED_2, 1);
#if 0
keypad_start();
QueueHandle_t q = keypad_getQueue();
uint32_t ev = 0;
//gpio_set_level(PIN_NUM_LED_1, 1);
gpio_set_level(PIN_NUM_LED_2, 1);
// Main loop - LVGL task will run automatically
while (1) {
if (xQueueReceive(q, &ev, pdMS_TO_TICKS(10)) == pdTRUE)
{
switch (ev)
{
case (KEY_UP << KEY_LONG_PRESS):
{
system_setZeroAngle();
break;
}
case (KEY_DOWN << KEY_LONG_PRESS):
{
system_clearZeroAngle();
break;
}
}
}
}
#else
while (1)
{
vTaskDelay(pdMS_TO_TICKS(1000));
}
#endif
}
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442

View File

@@ -1,21 +1,49 @@
<<<<<<< HEAD
#include "system.h" #include "system.h"
#include "esp_log.h" #include "esp_log.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "esp_timer.h"
#include <string.h>
static SystemState_t _systemState; static SystemState_t _systemState;
static EventGroupHandle_t _systemEvent; static EventGroupHandle_t _systemEvent;
static EventManager_t _eventManager; static EventManager_t _eventManager;
static QueueHandle_t _nvsRequestQueue;
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);
void system_init(void) void system_init(void)
{ {
_systemState.zeroAngle = 0.0f; _systemState.zeroAngle = 0.0f;
_systemState.primaryAxis = PRIMARY_AXIS; _systemState.primaryAxis = PRIMARY_AXIS;
_systemState.pairedDeviceCount = 0;
_systemState.isCharging = false;
_systemState.swapLR = false;
_systemState.volume = 50; // Default volume
_systemState.batteryVoltage_mv = 0;
_systemState.batteryPercentage = 0;
EventGroupHandle_t evt = xEventGroupCreate(); _systemEvent = xEventGroupCreate();
_eventManager.count = 0; _eventManager.count = 0;
_eventManager.mutex = xSemaphoreCreateMutex(); _eventManager.mutex = xSemaphoreCreateMutex();
system_initNvsService();
// Load saved volume from NVS
system_loadVolume();
// Load saved swap L/R setting from NVS
system_loadSwapLR();
} }
int system_getPrimaryAxis(void) int system_getPrimaryAxis(void)
@@ -44,6 +72,82 @@ float system_getAngle(void)
return angle; return angle;
} }
void system_setChargeStatus(bool charging)
{
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
_systemState.isCharging = charging;
xSemaphoreGive(_eventManager.mutex);
}
bool system_getChargeStatus(void)
{
bool charging;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
charging = _systemState.isCharging;
xSemaphoreGive(_eventManager.mutex);
return charging;
}
void system_setBatteryVoltage(int voltage_mv)
{
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
_systemState.batteryVoltage_mv = voltage_mv;
xSemaphoreGive(_eventManager.mutex);
}
int system_getBatteryVoltage(void)
{
int voltage;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
voltage = _systemState.batteryVoltage_mv;
xSemaphoreGive(_eventManager.mutex);
return voltage;
}
void system_setBatteryPercentage(int percentage)
{
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
_systemState.batteryPercentage = percentage;
xSemaphoreGive(_eventManager.mutex);
}
int system_getBatteryPercentage(void)
{
int percentage;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
percentage = _systemState.batteryPercentage;
xSemaphoreGive(_eventManager.mutex);
return percentage;
}
void system_setSwapLR(bool swap)
{
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
_systemState.swapLR = swap;
xSemaphoreGive(_eventManager.mutex);
ESP_LOGI("system", "Swap L/R: %s", swap ? "ON" : "OFF");
}
bool system_getSwapLR(void)
{
bool swap;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
swap = _systemState.swapLR;
xSemaphoreGive(_eventManager.mutex);
return swap;
}
void system_toggleSwapLR(void)
{
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
_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) void system_setZeroAngle(void)
{ {
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY); xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
@@ -167,174 +271,459 @@ void system_notifyAll(uint32_t eventBits) {
} }
xSemaphoreGive(em->mutex); xSemaphoreGive(em->mutex);
} }
=======
#include "system.h"
#include "esp_log.h"
static SystemState_t _systemState;
static EventGroupHandle_t _systemEvent;
static EventManager_t _eventManager;
void system_init(void)
{
_systemState.zeroAngle = 0.0f;
_systemState.primaryAxis = PRIMARY_AXIS;
EventGroupHandle_t evt = xEventGroupCreate();
_eventManager.count = 0;
_eventManager.mutex = xSemaphoreCreateMutex();
} }
int system_getPrimaryAxis(void) void system_requestBtRefresh(void) {
{ ESP_LOGI("system", "BT Refresh requested");
int axis; system_notifyAll(EM_EVENT_BT_REFRESH);
}
void system_requestBtConnect(int device_index) {
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY); xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
axis = _systemState.primaryAxis; _systemState.btDeviceIndex = device_index;
xSemaphoreGive(_eventManager.mutex); xSemaphoreGive(_eventManager.mutex);
return axis; ESP_LOGI("system", "BT Connect requested for device %d", device_index);
system_notifyAll(EM_EVENT_BT_CONNECT);
} }
float system_getAngle(void) int system_getBtDeviceIndex(void) {
{ int index;
float angle; xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
index = _systemState.btDeviceIndex;
xSemaphoreGive(_eventManager.mutex);
return index;
}
void system_requestVolumeUp(void) {
ESP_LOGI("system", "Volume Up requested");
system_notifyAll(EM_EVENT_VOLUME_UP);
}
void system_requestVolumeDown(void) {
ESP_LOGI("system", "Volume Down requested");
system_notifyAll(EM_EVENT_VOLUME_DOWN);
}
void system_setVolume(int volume) {
if (volume < 0) volume = 0;
if (volume > 100) volume = 100;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY); xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
_systemState.volume = volume;
xSemaphoreGive(_eventManager.mutex);
ESP_LOGI("system", "Volume set to %d", volume);
angle = _systemState.imu.raw[_systemState.primaryAxis] - _systemState.zeroAngle;
xSemaphoreGive(_eventManager.mutex);
return angle;
} }
void system_setZeroAngle(void) int system_getVolume(void) {
{ int volume;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY); xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
volume = _systemState.volume;
xSemaphoreGive(_eventManager.mutex);
_systemState.zeroAngle = _systemState.imu.raw[_systemState.primaryAxis]; return volume;
ESP_LOGI("system", "Zero: %.1f", _systemState.zeroAngle);
xSemaphoreGive(_eventManager.mutex);
} }
void system_clearZeroAngle(void) esp_err_t system_saveVolume(void) {
{ nvs_handle_t nvs_handle;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY); esp_err_t ret;
_systemState.zeroAngle = 0.0f; int volume = system_getVolume();
ESP_LOGI("system", "Zero: %.1f", _systemState.zeroAngle); ret = nvs_open(NVS_NAMESPACE_SETTINGS, NVS_READWRITE, &nvs_handle);
if (ret != ESP_OK) {
xSemaphoreGive(_eventManager.mutex); ESP_LOGE("system", "Failed to open NVS namespace for volume write: %s", esp_err_to_name(ret));
} return ret;
float system_getZeroAngle(void)
{
float angle;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
angle = _systemState.zeroAngle;
xSemaphoreGive(_eventManager.mutex);
return angle;
}
void system_setImuData(ImuData_t imu)
{
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
_systemState.imu = imu;
xSemaphoreGive(_eventManager.mutex);
//ESP_LOGI("g", "New IMU Data: %.2f", xy);
system_notifyAll(EM_EVENT_NEW_DATA);
}
ImuData_t system_getImuData(void)
{
ImuData_t imu;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
imu = _systemState.imu;
xSemaphoreGive(_eventManager.mutex);
return imu;
}
void system_waitForEvent(void)
{
}
SystemState_t *system_getState(void)
{
return &_systemState;
}
BaseType_t system_subscribe(TaskHandle_t task) {
EventManager_t *em = &_eventManager;
ESP_LOGI("g", "Subscribe: %p", task);
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdFALSE) {
return pdFAIL;
} }
if (em->count < EM_MAX_SUBSCRIBERS) {
// avoid duplicates? ret = nvs_set_i32(nvs_handle, NVS_KEY_VOLUME, volume);
ESP_LOGI("g", "PASS"); if (ret != ESP_OK) {
em->subscribers[em->count++] = task; ESP_LOGE("system", "Failed to write volume to NVS: %s", esp_err_to_name(ret));
xSemaphoreGive(em->mutex); nvs_close(nvs_handle);
return pdPASS; return ret;
} }
xSemaphoreGive(em->mutex);
return pdFAIL; // full ret = nvs_commit(nvs_handle);
nvs_close(nvs_handle);
if (ret == ESP_OK) {
ESP_LOGI("system", "Volume %d saved to NVS", volume);
} else {
ESP_LOGE("system", "Failed to commit volume to NVS: %s", esp_err_to_name(ret));
}
return ret;
} }
BaseType_t system_unsubscribe(TaskHandle_t task) { esp_err_t system_loadVolume(void) {
nvs_handle_t nvs_handle;
esp_err_t ret;
int32_t volume = 50; // Default value
EventManager_t *em = &_eventManager; ret = nvs_open(NVS_NAMESPACE_SETTINGS, NVS_READONLY, &nvs_handle);
if (ret != ESP_OK) {
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
}
BaseType_t removed = pdFAIL; ret = nvs_get_i32(nvs_handle, NVS_KEY_VOLUME, &volume);
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdTRUE) { nvs_close(nvs_handle);
for (size_t i = 0; i < em->count; ++i) {
if (em->subscribers[i] == task) { if (ret == ESP_OK) {
// shift down ESP_LOGI("system", "Loaded volume from NVS: %ld", volume);
for (size_t j = i; j + 1 < em->count; ++j) system_setVolume(volume);
em->subscribers[j] = em->subscribers[j+1]; } else if (ret == ESP_ERR_NVS_NOT_FOUND) {
em->count--; ESP_LOGI("system", "No saved volume found, using default: %ld", volume);
removed = pdPASS; system_setVolume(volume);
ret = ESP_OK; // Not an error
} else {
ESP_LOGE("system", "Failed to read volume from NVS: %s", esp_err_to_name(ret));
}
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) {
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; 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);
// Send the result directly as the notification value (not a pointer)
if (request.requestor) {
xTaskNotify(request.requestor, (uint32_t)request.result, eSetValueWithOverwrite);
} }
xSemaphoreGive(em->mutex);
} }
return removed;
} }
void system_notifyAll(uint32_t eventBits) { esp_err_t system_savePairedDevice(const paired_device_t *device) {
EventManager_t *em = &_eventManager; if (!device) return ESP_ERR_INVALID_ARG;
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdTRUE) {
for (size_t i = 0; i < em->count; ++i) { xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
// set the bits in each task's notification value
//ESP_LOGI("g", "Notify: %p", em->subscribers[i]); size_t existing_index = SIZE_MAX;
xTaskNotify(em->subscribers[i], for (size_t i = 0; i < _systemState.pairedDeviceCount; i++) {
eventBits, if (memcmp(_systemState.pairedDevices[i].bda, device->bda, ESP_BD_ADDR_LEN) == 0) {
eSetBits); existing_index = i;
break;
} }
xSemaphoreGive(em->mutex);
} }
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
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) {
// notification contains the result directly (not a pointer)
return (esp_err_t)notification;
}
}
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) {
// notification contains the result directly (not a pointer)
return (esp_err_t)notification;
}
}
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) {
// notification contains the result directly (not a pointer)
return (esp_err_t)notification;
}
}
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;
}
esp_err_t system_clearAllPairedDevices(void) {
// Directly clear in-memory state and save to NVS
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
_systemState.pairedDeviceCount = 0;
esp_err_t ret = nvs_save_devices_internal(_systemState.pairedDevices, 0);
xSemaphoreGive(_eventManager.mutex);
if (ret == ESP_OK) {
ESP_LOGI("system", "Cleared all paired devices from NVS");
} else {
ESP_LOGE("system", "Failed to clear paired devices: %s", esp_err_to_name(ret));
}
return ret;
} }

View File

@@ -1,13 +1,25 @@
<<<<<<< HEAD
#ifndef SYSTEM_H #ifndef SYSTEM_H
#define SYSTEM_H #define SYSTEM_H
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "freertos/queue.h"
#include "esp_bt_defs.h"
#define DISABLE_GUI #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 enum
{ {
ANGLE_XY = 0, ANGLE_XY = 0,
@@ -33,16 +45,42 @@ typedef struct SystemState_s
float zeroAngle; float zeroAngle;
int primaryAxis; int primaryAxis;
// BT event data
int btDeviceIndex;
// NVS cached data
paired_device_t pairedDevices[MAX_PAIRED_DEVICES];
size_t pairedDeviceCount;
// Charge status
bool isCharging;
// Swap L/R audio channels
bool swapLR;
// Volume setting (0-100)
int volume;
// Battery monitoring
int batteryVoltage_mv;
int batteryPercentage;
} SystemState_t; } SystemState_t;
#define MAX_INDICATION_ANGLE 5.0f #define MAX_INDICATION_ANGLE 7.5f
#define FILTER_COEFF 0.2f // 0 to 1 Smaller number is heavier filter #define FILTER_COEFF 0.4f // 0 to 1 Smaller number is heavier filter
#define PRIMARY_AXIS ANGLE_YZ #define PRIMARY_AXIS ANGLE_YZ
#define RIFLE_AXIS Y
#define EM_MAX_SUBSCRIBERS 8 // tweak as needed #define EM_MAX_SUBSCRIBERS 8 // tweak as needed
#define EM_EVENT_NEW_DATA (1UL<<0) #define EM_EVENT_NEW_DATA (1UL<<0)
#define EM_EVENT_ERROR (1UL<<1) #define EM_EVENT_ERROR (1UL<<1)
#define EM_EVENT_BT_REFRESH (1UL<<2)
#define EM_EVENT_BT_CONNECT (1UL<<3)
#define EM_EVENT_VOLUME_UP (1UL<<4)
#define EM_EVENT_VOLUME_DOWN (1UL<<5)
#define EM_EVENT_BT_DISCOVERY_COMPLETE (1UL<<6)
// …add more event bit-masks here… // …add more event bit-masks here…
typedef struct { typedef struct {
@@ -59,6 +97,20 @@ ImuData_t system_getImuData(void);
int system_getPrimaryAxis(void); int system_getPrimaryAxis(void);
float system_getAngle(void); float system_getAngle(void);
void system_setChargeStatus(bool charging);
bool system_getChargeStatus(void);
void system_setBatteryVoltage(int voltage_mv);
int system_getBatteryVoltage(void);
void system_setBatteryPercentage(int percentage);
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_setZeroAngle(void);
void system_clearZeroAngle(void); void system_clearZeroAngle(void);
float system_getZeroAngle(void); float system_getZeroAngle(void);
@@ -72,81 +124,50 @@ BaseType_t system_unsubscribe(TaskHandle_t task);
// Notify all subscribers of one or more event bits // Notify all subscribers of one or more event bits
void system_notifyAll(uint32_t eventBits); void system_notifyAll(uint32_t eventBits);
// BT-specific event functions
void system_requestBtRefresh(void);
void system_requestBtConnect(int device_index);
int system_getBtDeviceIndex(void);
======= // Volume control functions
#ifndef SYSTEM_H void system_requestVolumeUp(void);
#define SYSTEM_H void system_requestVolumeDown(void);
void system_setVolume(int volume);
int system_getVolume(void);
esp_err_t system_saveVolume(void);
esp_err_t system_loadVolume(void);
#include "freertos/FreeRTOS.h" // NVS Service
#include "freertos/task.h" typedef enum {
#include "freertos/semphr.h" NVS_OP_SAVE_DEVICE,
NVS_OP_LOAD_DEVICES,
#define DISABLE_GUI NVS_OP_REMOVE_DEVICE,
NVS_OP_IS_DEVICE_KNOWN,
enum NVS_OP_GET_DEVICE_COUNT,
{ NVS_OP_UPDATE_TIMESTAMP
ANGLE_XY = 0, } nvs_operation_type_t;
ANGLE_XZ,
ANGLE_YZ,
};
typedef struct
{
float raw[3];
float filtered[3];
float angle;
} ImuData_t;
typedef struct SystemState_s
{
ImuData_t imu;
EventGroupHandle_t event;
float zeroAngle;
int primaryAxis;
} SystemState_t;
#define MAX_INDICATION_ANGLE 5.0f
#define FILTER_COEFF 0.2f // 0 to 1 Smaller number is heavier filter
#define PRIMARY_AXIS ANGLE_YZ
#define EM_MAX_SUBSCRIBERS 8 // tweak as needed
#define EM_EVENT_NEW_DATA (1UL<<0)
#define EM_EVENT_ERROR (1UL<<1)
// …add more event bit-masks here…
typedef struct { typedef struct {
TaskHandle_t subscribers[EM_MAX_SUBSCRIBERS]; nvs_operation_type_t operation;
size_t count; paired_device_t device;
SemaphoreHandle_t mutex; esp_bd_addr_t bda;
} EventManager_t; TaskHandle_t requestor;
esp_err_t result;
bool response_ready;
} nvs_request_t;
void system_init(void); void system_initNvsService(void);
void system_setImuData(ImuData_t imu); void system_processNvsRequests(void);
esp_err_t system_savePairedDevice(const paired_device_t *device);
ImuData_t system_getImuData(void); esp_err_t system_loadPairedDevices(paired_device_t *devices, size_t *count);
esp_err_t system_removePairedDevice(esp_bd_addr_t bda);
int system_getPrimaryAxis(void); bool system_isDeviceKnown(esp_bd_addr_t bda);
float system_getAngle(void); esp_err_t system_getKnownDeviceCount(size_t *count);
esp_err_t system_updateConnectionTimestamp(esp_bd_addr_t bda);
void system_setZeroAngle(void); const paired_device_t* system_getPairedDevices(size_t *count);
void system_clearZeroAngle(void); esp_err_t system_clearAllPairedDevices(void);
float system_getZeroAngle(void);
// Subscribe (register) current task to receive events
BaseType_t system_subscribe(TaskHandle_t task);
// Unsubscribe if you ever need
BaseType_t system_unsubscribe(TaskHandle_t task);
// Notify all subscribers of one or more event bits
void system_notifyAll(uint32_t eventBits);
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442 #define NVS_TIMEOUT_MS 5000
#endif #endif

View File

@@ -7,4 +7,4 @@ with open("project_settings.cmake", "w") as out:
out.write(f'set(PROJECT_NAME "{cfg["project_name"]}")\n') out.write(f'set(PROJECT_NAME "{cfg["project_name"]}")\n')
out.write(f'set(CHIP "{cfg["chip"]}")\n') out.write(f'set(CHIP "{cfg["chip"]}")\n')
out.write(f'set(PORT "{cfg["port"]}")\n') out.write(f'set(PORT "{cfg["port"]}")\n')
out.write(f'set(BAUD "{cfg["baud"]}")\n') out.write(f'set(BAUD "{cfg["flash_baud"]}")\n')

4
project_settings.cmake Normal file
View File

@@ -0,0 +1,4 @@
set(PROJECT_NAME "soundshot")
set(CHIP "esp32")
set(PORT "COM14")
set(BAUD "460800")

210
sdkconfig
View File

@@ -1,6 +1,6 @@
# #
# Automatically generated file. DO NOT EDIT. # Automatically generated file. DO NOT EDIT.
# Espressif IoT Development Framework (ESP-IDF) 5.3.1 Project Configuration # Espressif IoT Development Framework (ESP-IDF) 5.4.1 Project Configuration
# #
CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined" CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined"
CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined" CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined"
@@ -91,12 +91,14 @@ CONFIG_SOC_GPIO_OUT_RANGE_MAX=33
CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0xEF0FEA CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0xEF0FEA
CONFIG_SOC_GPIO_CLOCKOUT_BY_IO_MUX=y CONFIG_SOC_GPIO_CLOCKOUT_BY_IO_MUX=y
CONFIG_SOC_GPIO_CLOCKOUT_CHANNEL_NUM=3 CONFIG_SOC_GPIO_CLOCKOUT_CHANNEL_NUM=3
CONFIG_SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP=y
CONFIG_SOC_I2C_NUM=2 CONFIG_SOC_I2C_NUM=2
CONFIG_SOC_HP_I2C_NUM=2 CONFIG_SOC_HP_I2C_NUM=2
CONFIG_SOC_I2C_FIFO_LEN=32 CONFIG_SOC_I2C_FIFO_LEN=32
CONFIG_SOC_I2C_CMD_REG_NUM=16 CONFIG_SOC_I2C_CMD_REG_NUM=16
CONFIG_SOC_I2C_SUPPORT_SLAVE=y CONFIG_SOC_I2C_SUPPORT_SLAVE=y
CONFIG_SOC_I2C_SUPPORT_APB=y CONFIG_SOC_I2C_SUPPORT_APB=y
CONFIG_SOC_I2C_SUPPORT_10BIT_ADDR=y
CONFIG_SOC_I2C_STOP_INDEPENDENT=y CONFIG_SOC_I2C_STOP_INDEPENDENT=y
CONFIG_SOC_I2S_NUM=2 CONFIG_SOC_I2S_NUM=2
CONFIG_SOC_I2S_HW_VERSION_1=y CONFIG_SOC_I2S_HW_VERSION_1=y
@@ -111,6 +113,7 @@ CONFIG_SOC_I2S_SUPPORTS_ADC_DAC=y
CONFIG_SOC_I2S_SUPPORTS_ADC=y CONFIG_SOC_I2S_SUPPORTS_ADC=y
CONFIG_SOC_I2S_SUPPORTS_DAC=y CONFIG_SOC_I2S_SUPPORTS_DAC=y
CONFIG_SOC_I2S_SUPPORTS_LCD_CAMERA=y CONFIG_SOC_I2S_SUPPORTS_LCD_CAMERA=y
CONFIG_SOC_I2S_MAX_DATA_WIDTH=24
CONFIG_SOC_I2S_TRANS_SIZE_ALIGN_WORD=y CONFIG_SOC_I2S_TRANS_SIZE_ALIGN_WORD=y
CONFIG_SOC_I2S_LCD_I80_VARIANT=y CONFIG_SOC_I2S_LCD_I80_VARIANT=y
CONFIG_SOC_LCD_I80_SUPPORTED=y CONFIG_SOC_LCD_I80_SUPPORTED=y
@@ -120,6 +123,7 @@ CONFIG_SOC_LEDC_HAS_TIMER_SPECIFIC_MUX=y
CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y
CONFIG_SOC_LEDC_SUPPORT_REF_TICK=y CONFIG_SOC_LEDC_SUPPORT_REF_TICK=y
CONFIG_SOC_LEDC_SUPPORT_HS_MODE=y CONFIG_SOC_LEDC_SUPPORT_HS_MODE=y
CONFIG_SOC_LEDC_TIMER_NUM=4
CONFIG_SOC_LEDC_CHANNEL_NUM=8 CONFIG_SOC_LEDC_CHANNEL_NUM=8
CONFIG_SOC_LEDC_TIMER_BIT_WIDTH=20 CONFIG_SOC_LEDC_TIMER_BIT_WIDTH=20
CONFIG_SOC_MCPWM_GROUPS=2 CONFIG_SOC_MCPWM_GROUPS=2
@@ -172,6 +176,8 @@ CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=2
CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64 CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64
CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4 CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4
CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y
CONFIG_SOC_LP_TIMER_BIT_WIDTH_LO=32
CONFIG_SOC_LP_TIMER_BIT_WIDTH_HI=16
CONFIG_SOC_TOUCH_SENSOR_VERSION=1 CONFIG_SOC_TOUCH_SENSOR_VERSION=1
CONFIG_SOC_TOUCH_SENSOR_NUM=10 CONFIG_SOC_TOUCH_SENSOR_NUM=10
CONFIG_SOC_TOUCH_SAMPLE_CFG_NUM=1 CONFIG_SOC_TOUCH_SAMPLE_CFG_NUM=1
@@ -214,6 +220,7 @@ CONFIG_SOC_PM_SUPPORT_RC_FAST_PD=y
CONFIG_SOC_PM_SUPPORT_VDDSDIO_PD=y CONFIG_SOC_PM_SUPPORT_VDDSDIO_PD=y
CONFIG_SOC_PM_SUPPORT_MODEM_PD=y CONFIG_SOC_PM_SUPPORT_MODEM_PD=y
CONFIG_SOC_CONFIGURABLE_VDDSDIO_SUPPORTED=y CONFIG_SOC_CONFIGURABLE_VDDSDIO_SUPPORTED=y
CONFIG_SOC_PM_MODEM_PD_BY_SW=y
CONFIG_SOC_CLK_APLL_SUPPORTED=y CONFIG_SOC_CLK_APLL_SUPPORTED=y
CONFIG_SOC_CLK_RC_FAST_D256_SUPPORTED=y CONFIG_SOC_CLK_RC_FAST_D256_SUPPORTED=y
CONFIG_SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256=y CONFIG_SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256=y
@@ -236,10 +243,11 @@ CONFIG_SOC_PHY_COMBO_MODULE=y
CONFIG_SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK=y CONFIG_SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK=y
CONFIG_IDF_CMAKE=y CONFIG_IDF_CMAKE=y
CONFIG_IDF_TOOLCHAIN="gcc" CONFIG_IDF_TOOLCHAIN="gcc"
CONFIG_IDF_TOOLCHAIN_GCC=y
CONFIG_IDF_TARGET_ARCH_XTENSA=y CONFIG_IDF_TARGET_ARCH_XTENSA=y
CONFIG_IDF_TARGET_ARCH="xtensa" CONFIG_IDF_TARGET_ARCH="xtensa"
CONFIG_IDF_TARGET="esp32" CONFIG_IDF_TARGET="esp32"
CONFIG_IDF_INIT_VERSION="5.3.1" CONFIG_IDF_INIT_VERSION="5.4.1"
CONFIG_IDF_TARGET_ESP32=y CONFIG_IDF_TARGET_ESP32=y
CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000
@@ -273,6 +281,10 @@ CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set
# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set
# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set
#
# Log
#
# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set # CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set # CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set # CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
@@ -281,6 +293,14 @@ CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set # CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set
CONFIG_BOOTLOADER_LOG_LEVEL=3 CONFIG_BOOTLOADER_LOG_LEVEL=3
#
# Format
#
# CONFIG_BOOTLOADER_LOG_COLORS is not set
CONFIG_BOOTLOADER_LOG_TIMESTAMP_SOURCE_CPU_TICKS=y
# end of Format
# end of Log
# #
# Serial Flash Configurations # Serial Flash Configurations
# #
@@ -336,6 +356,7 @@ CONFIG_ESP_ROM_HAS_SW_FLOAT=y
CONFIG_ESP_ROM_USB_OTG_NUM=-1 CONFIG_ESP_ROM_USB_OTG_NUM=-1
CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=-1 CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=-1
CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB=y CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB=y
CONFIG_ESP_ROM_HAS_OUTPUT_PUTC_FUNC=y
# #
# Serial flasher config # Serial flasher config
@@ -377,6 +398,7 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
# CONFIG_PARTITION_TABLE_SINGLE_APP is not set # CONFIG_PARTITION_TABLE_SINGLE_APP is not set
# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set # CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set
# CONFIG_PARTITION_TABLE_TWO_OTA is not set # CONFIG_PARTITION_TABLE_TWO_OTA is not set
# CONFIG_PARTITION_TABLE_TWO_OTA_LARGE is not set
CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
@@ -400,6 +422,7 @@ CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
# CONFIG_COMPILER_ASSERT_NDEBUG_EVALUATE is not set
CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2
# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set # CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set
@@ -410,14 +433,18 @@ CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set # CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set
# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set # CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set
# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set # CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set
# CONFIG_COMPILER_NO_MERGE_CONSTANTS is not set
# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set # CONFIG_COMPILER_WARN_WRITE_STRINGS is not set
# CONFIG_COMPILER_DISABLE_DEFAULT_ERRORS is not set
# CONFIG_COMPILER_DISABLE_GCC12_WARNINGS is not set # CONFIG_COMPILER_DISABLE_GCC12_WARNINGS is not set
# CONFIG_COMPILER_DISABLE_GCC13_WARNINGS is not set # CONFIG_COMPILER_DISABLE_GCC13_WARNINGS is not set
# CONFIG_COMPILER_DISABLE_GCC14_WARNINGS is not set
# CONFIG_COMPILER_DUMP_RTL_FILES is not set # CONFIG_COMPILER_DUMP_RTL_FILES is not set
CONFIG_COMPILER_RT_LIB_GCCLIB=y CONFIG_COMPILER_RT_LIB_GCCLIB=y
CONFIG_COMPILER_RT_LIB_NAME="gcc" CONFIG_COMPILER_RT_LIB_NAME="gcc"
# CONFIG_COMPILER_ORPHAN_SECTIONS_WARNING is not set # CONFIG_COMPILER_ORPHAN_SECTIONS_WARNING is not set
CONFIG_COMPILER_ORPHAN_SECTIONS_PLACE=y CONFIG_COMPILER_ORPHAN_SECTIONS_PLACE=y
# CONFIG_COMPILER_STATIC_ANALYZER is not set
# end of Compiler options # end of Compiler options
# #
@@ -449,7 +476,7 @@ CONFIG_BT_CONTROLLER_ENABLED=y
# #
# Bluedroid Options # Bluedroid Options
# #
CONFIG_BT_BTC_TASK_STACK_SIZE=3072 CONFIG_BT_BTC_TASK_STACK_SIZE=8192
CONFIG_BT_BLUEDROID_PINNED_TO_CORE_0=y CONFIG_BT_BLUEDROID_PINNED_TO_CORE_0=y
# CONFIG_BT_BLUEDROID_PINNED_TO_CORE_1 is not set # CONFIG_BT_BLUEDROID_PINNED_TO_CORE_1 is not set
CONFIG_BT_BLUEDROID_PINNED_TO_CORE=0 CONFIG_BT_BLUEDROID_PINNED_TO_CORE=0
@@ -461,10 +488,20 @@ CONFIG_BT_ENC_KEY_SIZE_CTRL_VSC=y
# CONFIG_BT_ENC_KEY_SIZE_CTRL_NONE is not set # CONFIG_BT_ENC_KEY_SIZE_CTRL_NONE is not set
# CONFIG_BT_CLASSIC_BQB_ENABLED is not set # CONFIG_BT_CLASSIC_BQB_ENABLED is not set
CONFIG_BT_A2DP_ENABLE=y CONFIG_BT_A2DP_ENABLE=y
CONFIG_BT_AVRCP_ENABLED=y
#
# AVRCP Features
#
CONFIG_BT_AVRCP_CT_COVER_ART_ENABLED=y
# end of AVRCP Features
# CONFIG_BT_SPP_ENABLED is not set # CONFIG_BT_SPP_ENABLED is not set
# CONFIG_BT_L2CAP_ENABLED is not set # CONFIG_BT_L2CAP_ENABLED is not set
# CONFIG_BT_SDP_COMMON_ENABLED is not set
# CONFIG_BT_HFP_ENABLE is not set # CONFIG_BT_HFP_ENABLE is not set
# CONFIG_BT_HID_ENABLED is not set # CONFIG_BT_HID_ENABLED is not set
CONFIG_BT_GOEPC_ENABLED=y
CONFIG_BT_BLE_ENABLED=y CONFIG_BT_BLE_ENABLED=y
CONFIG_BT_GATTS_ENABLE=y CONFIG_BT_GATTS_ENABLE=y
# CONFIG_BT_GATTS_PPCP_CHAR_GAP is not set # CONFIG_BT_GATTS_PPCP_CHAR_GAP is not set
@@ -485,6 +522,7 @@ CONFIG_BT_GATTC_CONNECT_RETRY_COUNT=3
CONFIG_BT_BLE_SMP_ENABLE=y CONFIG_BT_BLE_SMP_ENABLE=y
# CONFIG_BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE is not set # CONFIG_BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE is not set
# CONFIG_BT_BLE_SMP_ID_RESET_ENABLE is not set # CONFIG_BT_BLE_SMP_ID_RESET_ENABLE is not set
CONFIG_BT_BLE_SMP_BOND_NVS_FLASH=y
# CONFIG_BT_STACK_NO_LOG is not set # CONFIG_BT_STACK_NO_LOG is not set
# #
@@ -672,8 +710,8 @@ CONFIG_BT_BLE_ESTAB_LINK_CONN_TOUT=30
CONFIG_BT_MAX_DEVICE_NAME_LEN=32 CONFIG_BT_MAX_DEVICE_NAME_LEN=32
# CONFIG_BT_BLE_RPA_SUPPORTED is not set # CONFIG_BT_BLE_RPA_SUPPORTED is not set
CONFIG_BT_BLE_RPA_TIMEOUT=900 CONFIG_BT_BLE_RPA_TIMEOUT=900
# CONFIG_BT_BLE_42_FEATURES_SUPPORTED is not set
# CONFIG_BT_BLE_HIGH_DUTY_ADV_INTERVAL is not set # CONFIG_BT_BLE_HIGH_DUTY_ADV_INTERVAL is not set
# CONFIG_BT_ABORT_WHEN_ALLOCATION_FAILS is not set
# end of Bluedroid Options # end of Bluedroid Options
# #
@@ -682,6 +720,7 @@ CONFIG_BT_BLE_RPA_TIMEOUT=900
# CONFIG_BTDM_CTRL_MODE_BLE_ONLY is not set # CONFIG_BTDM_CTRL_MODE_BLE_ONLY is not set
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y
# CONFIG_BTDM_CTRL_MODE_BTDM is not set # CONFIG_BTDM_CTRL_MODE_BTDM is not set
CONFIG_BTDM_CTRL_BR_EDR_MIN_ENC_KEY_SZ_DFT=7
CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN=2 CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN=2
CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN=0 CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN=0
# CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI is not set # CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI is not set
@@ -692,11 +731,16 @@ CONFIG_BTDM_CTRL_PCM_ROLE_MASTER=y
# CONFIG_BTDM_CTRL_PCM_ROLE_SLAVE is not set # CONFIG_BTDM_CTRL_PCM_ROLE_SLAVE is not set
CONFIG_BTDM_CTRL_PCM_POLAR_FALLING_EDGE=y CONFIG_BTDM_CTRL_PCM_POLAR_FALLING_EDGE=y
# CONFIG_BTDM_CTRL_PCM_POLAR_RISING_EDGE is not set # CONFIG_BTDM_CTRL_PCM_POLAR_RISING_EDGE is not set
CONFIG_BTDM_CTRL_PCM_FSYNCSHP_STEREO_MODE=y
# CONFIG_BTDM_CTRL_PCM_FSYNCSHP_MONO_MODE_LF is not set
# CONFIG_BTDM_CTRL_PCM_FSYNCSHP_MONO_MODE_FF is not set
CONFIG_BTDM_CTRL_PCM_ROLE_EFF=0 CONFIG_BTDM_CTRL_PCM_ROLE_EFF=0
CONFIG_BTDM_CTRL_PCM_POLAR_EFF=0 CONFIG_BTDM_CTRL_PCM_POLAR_EFF=0
CONFIG_BTDM_CTRL_PCM_FSYNCSHP_EFF=0
CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT=y CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT=y
CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF=y CONFIG_BTDM_CTRL_LEGACY_AUTH_VENDOR_EVT_EFF=y
CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0 CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0
CONFIG_BTDM_CTRL_BR_EDR_MIN_ENC_KEY_SZ_DFT_EFF=7
CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=2 CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=2
CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0 CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0
CONFIG_BTDM_CTRL_PINNED_TO_CORE_0=y CONFIG_BTDM_CTRL_PINNED_TO_CORE_0=y
@@ -716,6 +760,14 @@ CONFIG_BTDM_CTRL_LPCLK_SEL_MAIN_XTAL=y
CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF=1 CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF=1
# CONFIG_BTDM_CTRL_SCAN_BACKOFF_UPPERLIMITMAX is not set # CONFIG_BTDM_CTRL_SCAN_BACKOFF_UPPERLIMITMAX is not set
# CONFIG_BTDM_CTRL_CHECK_CONNECT_IND_ACCESS_ADDRESS is not set
#
# BLE disconnects when Instant Passed (0x28) occurs
#
# end of BLE disconnects when Instant Passed (0x28) occurs
# CONFIG_BTDM_CTRL_CONTROLLER_DEBUG_MODE_1 is not set
CONFIG_BTDM_RESERVE_DRAM=0xdb5c CONFIG_BTDM_RESERVE_DRAM=0xdb5c
CONFIG_BTDM_CTRL_HLI=y CONFIG_BTDM_CTRL_HLI=y
# end of Controller Options # end of Controller Options
@@ -724,6 +776,7 @@ CONFIG_BTDM_CTRL_HLI=y
# Common Options # Common Options
# #
CONFIG_BT_ALARM_MAX_NUM=50 CONFIG_BT_ALARM_MAX_NUM=50
# CONFIG_BT_BLE_LOG_SPI_OUT_ENABLED is not set
# end of Common Options # end of Common Options
# CONFIG_BT_HCI_LOG_DEBUG_EN is not set # CONFIG_BT_HCI_LOG_DEBUG_EN is not set
@@ -757,6 +810,7 @@ CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM=y
# #
CONFIG_ADC_DISABLE_DAC=y CONFIG_ADC_DISABLE_DAC=y
# CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set # CONFIG_ADC_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_ADC_SKIP_LEGACY_CONFLICT_CHECK is not set
# #
# Legacy ADC Calibration Configuration # Legacy ADC Calibration Configuration
@@ -772,42 +826,49 @@ CONFIG_ADC_CAL_LUT_ENABLE=y
# Legacy DAC Driver Configurations # Legacy DAC Driver Configurations
# #
# CONFIG_DAC_SUPPRESS_DEPRECATE_WARN is not set # CONFIG_DAC_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_DAC_SKIP_LEGACY_CONFLICT_CHECK is not set
# end of Legacy DAC Driver Configurations # end of Legacy DAC Driver Configurations
# #
# Legacy MCPWM Driver Configurations # Legacy MCPWM Driver Configurations
# #
# CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set # CONFIG_MCPWM_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_MCPWM_SKIP_LEGACY_CONFLICT_CHECK is not set
# end of Legacy MCPWM Driver Configurations # end of Legacy MCPWM Driver Configurations
# #
# Legacy Timer Group Driver Configurations # Legacy Timer Group Driver Configurations
# #
# CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set # CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_GPTIMER_SKIP_LEGACY_CONFLICT_CHECK is not set
# end of Legacy Timer Group Driver Configurations # end of Legacy Timer Group Driver Configurations
# #
# Legacy RMT Driver Configurations # Legacy RMT Driver Configurations
# #
# CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set # CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_RMT_SKIP_LEGACY_CONFLICT_CHECK is not set
# end of Legacy RMT Driver Configurations # end of Legacy RMT Driver Configurations
# #
# Legacy I2S Driver Configurations # Legacy I2S Driver Configurations
# #
# CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set # CONFIG_I2S_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_I2S_SKIP_LEGACY_CONFLICT_CHECK is not set
# end of Legacy I2S Driver Configurations # end of Legacy I2S Driver Configurations
# #
# Legacy PCNT Driver Configurations # Legacy PCNT Driver Configurations
# #
# CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set # CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_PCNT_SKIP_LEGACY_CONFLICT_CHECK is not set
# end of Legacy PCNT Driver Configurations # end of Legacy PCNT Driver Configurations
# #
# Legacy SDM Driver Configurations # Legacy SDM Driver Configurations
# #
# CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set # CONFIG_SDM_SUPPRESS_DEPRECATE_WARN is not set
# CONFIG_SDM_SKIP_LEGACY_CONFLICT_CHECK is not set
# end of Legacy SDM Driver Configurations # end of Legacy SDM Driver Configurations
# end of Driver Configurations # end of Driver Configurations
@@ -859,6 +920,7 @@ CONFIG_ADC_DISABLE_DAC_OUTPUT=y
CONFIG_ESP_COEX_ENABLED=y CONFIG_ESP_COEX_ENABLED=y
CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y
# CONFIG_ESP_COEX_POWER_MANAGEMENT is not set # CONFIG_ESP_COEX_POWER_MANAGEMENT is not set
# CONFIG_ESP_COEX_GPIO_DEBUG is not set
# end of Wireless Coexistence # end of Wireless Coexistence
# #
@@ -897,6 +959,7 @@ CONFIG_GPTIMER_ISR_HANDLER_IN_IRAM=y
# #
# CONFIG_I2C_ISR_IRAM_SAFE is not set # CONFIG_I2C_ISR_IRAM_SAFE is not set
# CONFIG_I2C_ENABLE_DEBUG_LOG is not set # CONFIG_I2C_ENABLE_DEBUG_LOG is not set
# CONFIG_I2C_ENABLE_SLAVE_DRIVER_VERSION_2 is not set
# end of ESP-Driver:I2C Configurations # end of ESP-Driver:I2C Configurations
# #
@@ -1004,6 +1067,13 @@ CONFIG_ESP_GDBSTUB_SUPPORT_TASKS=y
CONFIG_ESP_GDBSTUB_MAX_TASKS=32 CONFIG_ESP_GDBSTUB_MAX_TASKS=32
# end of GDB Stub # end of GDB Stub
#
# ESP HID
#
CONFIG_ESPHID_TASK_SIZE_BT=2048
CONFIG_ESPHID_TASK_SIZE_BLE=4096
# end of ESP HID
# #
# ESP HTTP client # ESP HTTP client
# #
@@ -1011,6 +1081,7 @@ CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set # CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set
# CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set # CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH is not set
# CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT is not set # CONFIG_ESP_HTTP_CLIENT_ENABLE_CUSTOM_TRANSPORT is not set
CONFIG_ESP_HTTP_CLIENT_EVENT_POST_TIMEOUT=2000
# end of ESP HTTP client # end of ESP HTTP client
# #
@@ -1023,6 +1094,7 @@ CONFIG_HTTPD_PURGE_BUF_LEN=32
# CONFIG_HTTPD_LOG_PURGE_DATA is not set # CONFIG_HTTPD_LOG_PURGE_DATA is not set
# CONFIG_HTTPD_WS_SUPPORT is not set # CONFIG_HTTPD_WS_SUPPORT is not set
# CONFIG_HTTPD_QUEUE_WORK_BLOCKING is not set # CONFIG_HTTPD_QUEUE_WORK_BLOCKING is not set
CONFIG_HTTPD_SERVER_EVENT_POST_TIMEOUT=2000
# end of HTTP Server # end of HTTP Server
# #
@@ -1030,12 +1102,14 @@ CONFIG_HTTPD_PURGE_BUF_LEN=32
# #
# CONFIG_ESP_HTTPS_OTA_DECRYPT_CB is not set # CONFIG_ESP_HTTPS_OTA_DECRYPT_CB is not set
# CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP is not set # CONFIG_ESP_HTTPS_OTA_ALLOW_HTTP is not set
CONFIG_ESP_HTTPS_OTA_EVENT_POST_TIMEOUT=2000
# end of ESP HTTPS OTA # end of ESP HTTPS OTA
# #
# ESP HTTPS server # ESP HTTPS server
# #
# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set # CONFIG_ESP_HTTPS_SERVER_ENABLE is not set
CONFIG_ESP_HTTPS_SERVER_EVENT_POST_TIMEOUT=2000
# end of ESP HTTPS server # end of ESP HTTPS server
# #
@@ -1060,6 +1134,12 @@ CONFIG_ESP_REV_MIN_FULL=0
# #
CONFIG_ESP32_REV_MAX_FULL=399 CONFIG_ESP32_REV_MAX_FULL=399
CONFIG_ESP_REV_MAX_FULL=399 CONFIG_ESP_REV_MAX_FULL=399
CONFIG_ESP_EFUSE_BLOCK_REV_MIN_FULL=0
CONFIG_ESP_EFUSE_BLOCK_REV_MAX_FULL=99
#
# Maximum Supported ESP32 eFuse Block Revision (eFuse Block Rev v0.99)
#
# end of Chip revision # end of Chip revision
# #
@@ -1112,6 +1192,7 @@ CONFIG_PERIPH_CTRL_FUNC_IN_IRAM=y
# Main XTAL Config # Main XTAL Config
# #
# CONFIG_XTAL_FREQ_26 is not set # CONFIG_XTAL_FREQ_26 is not set
# CONFIG_XTAL_FREQ_32 is not set
CONFIG_XTAL_FREQ_40=y CONFIG_XTAL_FREQ_40=y
# CONFIG_XTAL_FREQ_AUTO is not set # CONFIG_XTAL_FREQ_AUTO is not set
CONFIG_XTAL_FREQ=40 CONFIG_XTAL_FREQ=40
@@ -1121,31 +1202,29 @@ CONFIG_ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM=y
# end of Hardware Settings # end of Hardware Settings
# #
# LCD and Touch Panel # ESP-Driver:LCD Controller Configurations
# #
#
# LCD Touch Drivers are maintained in the IDF Component Registry
#
#
# LCD Peripheral Configuration
#
CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE=32
# CONFIG_LCD_ENABLE_DEBUG_LOG is not set # CONFIG_LCD_ENABLE_DEBUG_LOG is not set
# end of LCD Peripheral Configuration # end of ESP-Driver:LCD Controller Configurations
# end of LCD and Touch Panel
#
# ESP-MM: Memory Management Configurations
#
# end of ESP-MM: Memory Management Configurations
# #
# ESP NETIF Adapter # ESP NETIF Adapter
# #
CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120 CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120
# CONFIG_ESP_NETIF_PROVIDE_CUSTOM_IMPLEMENTATION is not set
CONFIG_ESP_NETIF_TCPIP_LWIP=y CONFIG_ESP_NETIF_TCPIP_LWIP=y
# CONFIG_ESP_NETIF_LOOPBACK is not set # CONFIG_ESP_NETIF_LOOPBACK is not set
CONFIG_ESP_NETIF_USES_TCPIP_WITH_BSD_API=y CONFIG_ESP_NETIF_USES_TCPIP_WITH_BSD_API=y
CONFIG_ESP_NETIF_REPORT_DATA_TRAFFIC=y
# CONFIG_ESP_NETIF_RECEIVE_REPORT_ERRORS is not set # CONFIG_ESP_NETIF_RECEIVE_REPORT_ERRORS is not set
# CONFIG_ESP_NETIF_L2_TAP is not set # CONFIG_ESP_NETIF_L2_TAP is not set
# CONFIG_ESP_NETIF_BRIDGE_EN is not set # CONFIG_ESP_NETIF_BRIDGE_EN is not set
# CONFIG_ESP_NETIF_SET_DNS_PER_DEFAULT_NETIF is not set
# end of ESP NETIF Adapter # end of ESP NETIF Adapter
# #
@@ -1162,17 +1241,20 @@ CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20 CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20
CONFIG_ESP_PHY_MAX_TX_POWER=20 CONFIG_ESP_PHY_MAX_TX_POWER=20
# CONFIG_ESP_PHY_REDUCE_TX_POWER is not set # CONFIG_ESP_PHY_REDUCE_TX_POWER is not set
# CONFIG_ESP_PHY_ENABLE_CERT_TEST is not set
CONFIG_ESP_PHY_RF_CAL_PARTIAL=y CONFIG_ESP_PHY_RF_CAL_PARTIAL=y
# CONFIG_ESP_PHY_RF_CAL_NONE is not set # CONFIG_ESP_PHY_RF_CAL_NONE is not set
# CONFIG_ESP_PHY_RF_CAL_FULL is not set # CONFIG_ESP_PHY_RF_CAL_FULL is not set
CONFIG_ESP_PHY_CALIBRATION_MODE=0 CONFIG_ESP_PHY_CALIBRATION_MODE=0
# CONFIG_ESP_PHY_PLL_TRACK_DEBUG is not set # CONFIG_ESP_PHY_PLL_TRACK_DEBUG is not set
# CONFIG_ESP_PHY_RECORD_USED_TIME is not set
# end of PHY # end of PHY
# #
# Power Management # Power Management
# #
# CONFIG_PM_ENABLE is not set # CONFIG_PM_ENABLE is not set
CONFIG_PM_SLP_IRAM_OPT=y
# end of Power Management # end of Power Management
# #
@@ -1187,6 +1269,11 @@ CONFIG_ESP_PHY_CALIBRATION_MODE=0
# CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set # CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH is not set
# end of ESP Ringbuf # end of ESP Ringbuf
#
# ESP Security Specific
#
# end of ESP Security Specific
# #
# ESP System Settings # ESP System Settings
# #
@@ -1404,6 +1491,9 @@ CONFIG_FATFS_FS_LOCK=0
CONFIG_FATFS_TIMEOUT_MS=10000 CONFIG_FATFS_TIMEOUT_MS=10000
CONFIG_FATFS_PER_FILE_CACHE=y CONFIG_FATFS_PER_FILE_CACHE=y
# CONFIG_FATFS_USE_FASTSEEK is not set # CONFIG_FATFS_USE_FASTSEEK is not set
CONFIG_FATFS_USE_STRFUNC_NONE=y
# CONFIG_FATFS_USE_STRFUNC_WITHOUT_CRLF_CONV is not set
# CONFIG_FATFS_USE_STRFUNC_WITH_CRLF_CONV is not set
CONFIG_FATFS_VFS_FSTAT_BLKSIZE=0 CONFIG_FATFS_VFS_FSTAT_BLKSIZE=0
# CONFIG_FATFS_IMMEDIATE_FSYNC is not set # CONFIG_FATFS_IMMEDIATE_FSYNC is not set
# CONFIG_FATFS_USE_LABEL is not set # CONFIG_FATFS_USE_LABEL is not set
@@ -1429,6 +1519,7 @@ CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
# CONFIG_FREERTOS_USE_TICK_HOOK is not set # CONFIG_FREERTOS_USE_TICK_HOOK is not set
CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
# CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set # CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY is not set
CONFIG_FREERTOS_USE_TIMERS=y
CONFIG_FREERTOS_TIMER_SERVICE_TASK_NAME="Tmr Svc" CONFIG_FREERTOS_TIMER_SERVICE_TASK_NAME="Tmr Svc"
# CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU0 is not set # CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU0 is not set
# CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU1 is not set # CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU1 is not set
@@ -1464,6 +1555,11 @@ CONFIG_FREERTOS_SYSTICK_USES_CCOUNT=y
# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set # CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set
# end of Port # end of Port
#
# Extra
#
# end of Extra
CONFIG_FREERTOS_PORT=y CONFIG_FREERTOS_PORT=y
CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
@@ -1501,7 +1597,11 @@ CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS=y
# end of Heap memory debugging # end of Heap memory debugging
# #
# Log output # Log
#
#
# Log Level
# #
# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set # CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set # CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
@@ -1514,11 +1614,29 @@ CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y
# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set # CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set
# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set # CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set
CONFIG_LOG_MAXIMUM_LEVEL=3 CONFIG_LOG_MAXIMUM_LEVEL=3
#
# Level Settings
#
# CONFIG_LOG_MASTER_LEVEL is not set # CONFIG_LOG_MASTER_LEVEL is not set
CONFIG_LOG_DYNAMIC_LEVEL_CONTROL=y
# CONFIG_LOG_TAG_LEVEL_IMPL_NONE is not set
# CONFIG_LOG_TAG_LEVEL_IMPL_LINKED_LIST is not set
CONFIG_LOG_TAG_LEVEL_IMPL_CACHE_AND_LINKED_LIST=y
# CONFIG_LOG_TAG_LEVEL_CACHE_ARRAY is not set
CONFIG_LOG_TAG_LEVEL_CACHE_BINARY_MIN_HEAP=y
CONFIG_LOG_TAG_LEVEL_IMPL_CACHE_SIZE=31
# end of Level Settings
# end of Log Level
#
# Format
#
CONFIG_LOG_COLORS=y CONFIG_LOG_COLORS=y
CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y
# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set # CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set
# end of Log output # end of Format
# end of Log
# #
# LWIP # LWIP
@@ -1557,6 +1675,8 @@ CONFIG_LWIP_ESP_MLDV6_REPORT=y
CONFIG_LWIP_MLDV6_TMR_INTERVAL=40 CONFIG_LWIP_MLDV6_TMR_INTERVAL=40
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y
# CONFIG_LWIP_DHCP_DOES_ACD_CHECK is not set
# CONFIG_LWIP_DHCP_DOES_NOT_CHECK_OFFERED_IP is not set
# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set # CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set
CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y
# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set # CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set
@@ -1571,6 +1691,7 @@ CONFIG_LWIP_DHCPS=y
CONFIG_LWIP_DHCPS_LEASE_UNIT=60 CONFIG_LWIP_DHCPS_LEASE_UNIT=60
CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8
CONFIG_LWIP_DHCPS_STATIC_ENTRIES=y CONFIG_LWIP_DHCPS_STATIC_ENTRIES=y
CONFIG_LWIP_DHCPS_ADD_DNS=y
# end of DHCP server # end of DHCP server
# CONFIG_LWIP_AUTOIP is not set # CONFIG_LWIP_AUTOIP is not set
@@ -1629,9 +1750,12 @@ CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set # CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set
# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set # CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set
CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF
# CONFIG_LWIP_PPP_SUPPORT is not set
CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3 CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3
CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5 CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5
CONFIG_LWIP_IPV6_ND6_NUM_PREFIXES=5
CONFIG_LWIP_IPV6_ND6_NUM_ROUTERS=3
CONFIG_LWIP_IPV6_ND6_NUM_DESTINATIONS=10
# CONFIG_LWIP_PPP_SUPPORT is not set
# CONFIG_LWIP_SLIP_SUPPORT is not set # CONFIG_LWIP_SLIP_SUPPORT is not set
# #
@@ -1661,8 +1785,10 @@ CONFIG_LWIP_SNTP_MAXIMUM_STARTUP_DELAY=5000
# #
# DNS # DNS
# #
CONFIG_LWIP_DNS_MAX_HOST_IP=1
CONFIG_LWIP_DNS_MAX_SERVERS=3 CONFIG_LWIP_DNS_MAX_SERVERS=3
# CONFIG_LWIP_FALLBACK_DNS_SERVER_SUPPORT is not set # CONFIG_LWIP_FALLBACK_DNS_SERVER_SUPPORT is not set
# CONFIG_LWIP_DNS_SETSERVER_WITH_NETIF is not set
# end of DNS # end of DNS
CONFIG_LWIP_BRIDGEIF_MAX_PORTS=7 CONFIG_LWIP_BRIDGEIF_MAX_PORTS=7
@@ -1686,6 +1812,8 @@ CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_NONE=y
CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y
# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set # CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set
# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set # CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set
CONFIG_LWIP_HOOK_DNS_EXT_RESOLVE_NONE=y
# CONFIG_LWIP_HOOK_DNS_EXT_RESOLVE_CUSTOM is not set
CONFIG_LWIP_HOOK_IP6_INPUT_NONE=y CONFIG_LWIP_HOOK_IP6_INPUT_NONE=y
# CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT is not set # CONFIG_LWIP_HOOK_IP6_INPUT_DEFAULT is not set
# CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM is not set # CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM is not set
@@ -1744,6 +1872,7 @@ CONFIG_MBEDTLS_HAVE_TIME=y
# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set # CONFIG_MBEDTLS_HAVE_TIME_DATE is not set
CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y
CONFIG_MBEDTLS_SHA512_C=y CONFIG_MBEDTLS_SHA512_C=y
CONFIG_MBEDTLS_SHA3_C=y
CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y
# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set # CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set
# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set # CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set
@@ -1797,6 +1926,8 @@ CONFIG_MBEDTLS_X509_CSR_PARSE_C=y
# end of Certificates # end of Certificates
CONFIG_MBEDTLS_ECP_C=y CONFIG_MBEDTLS_ECP_C=y
CONFIG_MBEDTLS_PK_PARSE_EC_EXTENDED=y
CONFIG_MBEDTLS_PK_PARSE_EC_COMPRESSED=y
# CONFIG_MBEDTLS_DHM_C is not set # CONFIG_MBEDTLS_DHM_C is not set
CONFIG_MBEDTLS_ECDH_C=y CONFIG_MBEDTLS_ECDH_C=y
CONFIG_MBEDTLS_ECDSA_C=y CONFIG_MBEDTLS_ECDSA_C=y
@@ -1820,6 +1951,7 @@ CONFIG_MBEDTLS_ECP_FIXED_POINT_OPTIM=y
# CONFIG_MBEDTLS_HKDF_C is not set # CONFIG_MBEDTLS_HKDF_C is not set
# CONFIG_MBEDTLS_THREADING_C is not set # CONFIG_MBEDTLS_THREADING_C is not set
CONFIG_MBEDTLS_ERROR_STRINGS=y CONFIG_MBEDTLS_ERROR_STRINGS=y
CONFIG_MBEDTLS_FS_IO=y
# end of mbedTLS # end of mbedTLS
# #
@@ -1867,25 +1999,10 @@ CONFIG_NEWLIB_TIME_SYSCALL_USE_RTC_HRT=y
# CONFIG_OPENTHREAD_ENABLED is not set # CONFIG_OPENTHREAD_ENABLED is not set
# #
# Thread Operational Dataset # OpenThread Spinel
# #
CONFIG_OPENTHREAD_NETWORK_NAME="OpenThread-ESP"
CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX="fd00:db8:a0:0::/64"
CONFIG_OPENTHREAD_NETWORK_CHANNEL=15
CONFIG_OPENTHREAD_NETWORK_PANID=0x1234
CONFIG_OPENTHREAD_NETWORK_EXTPANID="dead00beef00cafe"
CONFIG_OPENTHREAD_NETWORK_MASTERKEY="00112233445566778899aabbccddeeff"
CONFIG_OPENTHREAD_NETWORK_PSKC="104810e2315100afd6bc9215a6bfac53"
# end of Thread Operational Dataset
CONFIG_OPENTHREAD_XTAL_ACCURACY=130
# CONFIG_OPENTHREAD_SPINEL_ONLY is not set # CONFIG_OPENTHREAD_SPINEL_ONLY is not set
# CONFIG_OPENTHREAD_RX_ON_WHEN_IDLE is not set # end of OpenThread Spinel
#
# Thread Address Query Config
#
# end of Thread Address Query Config
# end of OpenThread # end of OpenThread
# #
@@ -1894,6 +2011,7 @@ CONFIG_OPENTHREAD_XTAL_ACCURACY=130
CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0=y CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0=y
CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1=y CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1=y
CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2=y CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2=y
CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_PATCH_VERSION=y
# end of Protocomm # end of Protocomm
# #
@@ -1936,6 +2054,7 @@ CONFIG_SPI_FLASH_BROWNOUT_RESET=y
# Features here require specific hardware (READ DOCS FIRST!) # Features here require specific hardware (READ DOCS FIRST!)
# #
CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US=50 CONFIG_SPI_FLASH_SUSPEND_TSUS_VAL_US=50
# CONFIG_SPI_FLASH_FORCE_ENABLE_XMC_C_SUSPEND is not set
# end of Optional and Experimental Features (READ DOCS FIRST) # end of Optional and Experimental Features (READ DOCS FIRST)
# end of Main Flash configuration # end of Main Flash configuration
@@ -2065,6 +2184,8 @@ CONFIG_VFS_MAX_COUNT=8
# #
CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1 CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1
# end of Host File System I/O (Semihosting) # end of Host File System I/O (Semihosting)
CONFIG_VFS_INITIALIZE_DEV_NULL=y
# end of Virtual file system # end of Virtual file system
# #
@@ -2082,6 +2203,7 @@ CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30 CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
# CONFIG_WIFI_PROV_BLE_BONDING is not set # CONFIG_WIFI_PROV_BLE_BONDING is not set
# CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set # CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION is not set
# CONFIG_WIFI_PROV_BLE_NOTIFY is not set
# CONFIG_WIFI_PROV_KEEP_BLE_ON_AFTER_PROV is not set # CONFIG_WIFI_PROV_KEEP_BLE_ON_AFTER_PROV is not set
CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y
# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set # CONFIG_WIFI_PROV_STA_FAST_SCAN is not set
@@ -2246,13 +2368,13 @@ CONFIG_LV_ATTRIBUTE_MEM_ALIGN_SIZE=1
# #
# Enable built-in fonts # Enable built-in fonts
# #
# CONFIG_LV_FONT_MONTSERRAT_8 is not set CONFIG_LV_FONT_MONTSERRAT_8=y
# CONFIG_LV_FONT_MONTSERRAT_10 is not set CONFIG_LV_FONT_MONTSERRAT_10=y
# CONFIG_LV_FONT_MONTSERRAT_12 is not set CONFIG_LV_FONT_MONTSERRAT_12=y
CONFIG_LV_FONT_MONTSERRAT_14=y CONFIG_LV_FONT_MONTSERRAT_14=y
# CONFIG_LV_FONT_MONTSERRAT_16 is not set # CONFIG_LV_FONT_MONTSERRAT_16 is not set
# CONFIG_LV_FONT_MONTSERRAT_18 is not set # CONFIG_LV_FONT_MONTSERRAT_18 is not set
CONFIG_LV_FONT_MONTSERRAT_20=y # CONFIG_LV_FONT_MONTSERRAT_20 is not set
# CONFIG_LV_FONT_MONTSERRAT_22 is not set # CONFIG_LV_FONT_MONTSERRAT_22 is not set
# CONFIG_LV_FONT_MONTSERRAT_24 is not set # CONFIG_LV_FONT_MONTSERRAT_24 is not set
# CONFIG_LV_FONT_MONTSERRAT_26 is not set # CONFIG_LV_FONT_MONTSERRAT_26 is not set
@@ -2272,7 +2394,7 @@ CONFIG_LV_FONT_MONTSERRAT_20=y
# CONFIG_LV_FONT_SIMSUN_14_CJK is not set # CONFIG_LV_FONT_SIMSUN_14_CJK is not set
# CONFIG_LV_FONT_SIMSUN_16_CJK is not set # CONFIG_LV_FONT_SIMSUN_16_CJK is not set
CONFIG_LV_FONT_UNSCII_8=y CONFIG_LV_FONT_UNSCII_8=y
# CONFIG_LV_FONT_UNSCII_16 is not set CONFIG_LV_FONT_UNSCII_16=y
# end of Enable built-in fonts # end of Enable built-in fonts
# CONFIG_LV_FONT_DEFAULT_MONTSERRAT_8 is not set # CONFIG_LV_FONT_DEFAULT_MONTSERRAT_8 is not set
@@ -2455,7 +2577,7 @@ CONFIG_LVGL_VERSION_PATCH=2
# #
# Examples # Examples
# #
CONFIG_LV_BUILD_EXAMPLES=y # CONFIG_LV_BUILD_EXAMPLES is not set
# end of Examples # end of Examples
# #
@@ -2515,7 +2637,7 @@ CONFIG_ESP32_APPTRACE_DEST_NONE=y
CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
CONFIG_BLUEDROID_ENABLED=y CONFIG_BLUEDROID_ENABLED=y
# CONFIG_NIMBLE_ENABLED is not set # CONFIG_NIMBLE_ENABLED is not set
CONFIG_BTC_TASK_STACK_SIZE=3072 CONFIG_BTC_TASK_STACK_SIZE=8192
CONFIG_BLUEDROID_PINNED_TO_CORE_0=y CONFIG_BLUEDROID_PINNED_TO_CORE_0=y
# CONFIG_BLUEDROID_PINNED_TO_CORE_1 is not set # CONFIG_BLUEDROID_PINNED_TO_CORE_1 is not set
CONFIG_BLUEDROID_PINNED_TO_CORE=0 CONFIG_BLUEDROID_PINNED_TO_CORE=0
@@ -2811,8 +2933,6 @@ CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32
CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP32_WIFI_TX_BA_WIN=6 CONFIG_ESP32_WIFI_TX_BA_WIN=6
CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP32_WIFI_RX_BA_WIN=6
CONFIG_ESP32_WIFI_RX_BA_WIN=6 CONFIG_ESP32_WIFI_RX_BA_WIN=6
CONFIG_ESP32_WIFI_NVS_ENABLED=y CONFIG_ESP32_WIFI_NVS_ENABLED=y
CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y

View File

@@ -1,4 +1,3 @@
<<<<<<< HEAD
# Override some defaults so BT stack is enabled and # Override some defaults so BT stack is enabled and
# Classic BT is enabled # Classic BT is enabled
CONFIG_BT_ENABLED=y CONFIG_BT_ENABLED=y
@@ -8,14 +7,3 @@ CONFIG_BTDM_CTRL_MODE_BTDM=n
CONFIG_BT_BLUEDROID_ENABLED=y CONFIG_BT_BLUEDROID_ENABLED=y
CONFIG_BT_CLASSIC_ENABLED=y CONFIG_BT_CLASSIC_ENABLED=y
CONFIG_BT_A2DP_ENABLE=y CONFIG_BT_A2DP_ENABLE=y
=======
# Override some defaults so BT stack is enabled and
# Classic BT is enabled
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=n
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y
CONFIG_BTDM_CTRL_MODE_BTDM=n
CONFIG_BT_BLUEDROID_ENABLED=y
CONFIG_BT_CLASSIC_ENABLED=y
CONFIG_BT_A2DP_ENABLE=y
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,11 @@
{ {
"project_name": "soundshot", "project_name": "soundshot",
"chip": "esp32h2", "chip": "esp32",
"port": "COM8", "port": "COM14",
"monitor_baud": 115200, "monitor_baud": 115200,
"flash_baud": 460800, "flash_baud": 460800,
"flash_mode": "dio", "flash_mode": "dio",
"flash_freq": "48m", "flash_freq": "40m",
"flash_size": "2MB", "flash_size": "2MB",
"before": "default-reset", "before": "default-reset",
"after": "hard-reset" "after": "hard-reset"