Compare commits
18 Commits
c4ca91bf84
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| d427859804 | |||
| 40bea065a7 | |||
|
|
3bce9e772c | ||
|
|
31e0e3a148 | ||
|
|
a272a15bcf | ||
|
|
8a1966ea90 | ||
|
|
b8a3a09e9f | ||
|
|
115105c032 | ||
|
|
19e8ca30c3 | ||
|
|
de7041c1f5 | ||
|
|
fe69dc6f19 | ||
|
|
bca2f6ea9c | ||
|
|
5a893a034c | ||
| 2513a9e7fb | |||
|
|
04d2c71d01 | ||
|
|
a89fdc6843 | ||
|
|
439c6ef22d | ||
|
|
25f875b3b2 |
32
.claude/settings.local.json
Normal file
32
.claude/settings.local.json
Normal 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
17
.gitignore
vendored
@@ -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
|
||||||
37
.vscode/c_cpp_properties.json
vendored
37
.vscode/c_cpp_properties.json
vendored
@@ -1,15 +1,38 @@
|
|||||||
{
|
{
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "Linux",
|
"name": "Win32",
|
||||||
"includePath": [
|
"includePath": [
|
||||||
"${workspaceFolder}/**"
|
"${workspaceFolder}/**",
|
||||||
|
"${env:USERPROFILE}/esp/v5.4.1/esp-idf/components/**",
|
||||||
|
"${env:USERPROFILE}/.espressif/tools/xtensa-esp-elf/**",
|
||||||
|
"${workspaceFolder}/build/config",
|
||||||
|
"${workspaceFolder}/managed_components/**"
|
||||||
],
|
],
|
||||||
"defines": [],
|
"defines": [
|
||||||
"compilerPath": "/usr/bin/gcc",
|
"ESP_PLATFORM"
|
||||||
"cStandard": "c17",
|
],
|
||||||
"cppStandard": "gnu++17",
|
"compilerPath": "${env:USERPROFILE}/.espressif/tools/xtensa-esp-elf/esp-13.2.0_20241113/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc.exe",
|
||||||
"intelliSenseMode": "linux-gcc-x64"
|
"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
|
"version": 4
|
||||||
|
|||||||
50
.vscode/launch.json
vendored
Normal file
50
.vscode/launch.json
vendored
Normal 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"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
14
.vscode/settings.json
vendored
14
.vscode/settings.json
vendored
@@ -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",
|
||||||
@@ -37,8 +38,11 @@
|
|||||||
"lv_slider.h": "c",
|
"lv_slider.h": "c",
|
||||||
"lv_menu.h": "c",
|
"lv_menu.h": "c",
|
||||||
"stdint.h": "c",
|
"stdint.h": "c",
|
||||||
"random": "c"
|
"random": "c",
|
||||||
|
"string.h": "c"
|
||||||
},
|
},
|
||||||
"git.ignoreLimitWarning": true,
|
"git.ignoreLimitWarning": true,
|
||||||
"idf.pythonInstallPath": "/usr/bin/python"
|
"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
37
.vscode/tasks.json
vendored
Normal 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
147
CLAUDE.md
Normal 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.
|
||||||
141
docker.md
Normal file
141
docker.md
Normal 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 repo’s `README.md`. It’s 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 container’s 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 doesn’t 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
4
flash_gui.bat
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
@echo off
|
||||||
|
echo Starting ESP32 Firmware Flash GUI...
|
||||||
|
python flash_tool/gui_flasher.py
|
||||||
|
pause
|
||||||
9
flash_tool/.claude/settings.local.json
Normal file
9
flash_tool/.claude/settings.local.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(python:*)"
|
||||||
|
],
|
||||||
|
"deny": [],
|
||||||
|
"ask": []
|
||||||
|
}
|
||||||
|
}
|
||||||
110
flash_tool/BUILD_NOTES.md
Normal file
110
flash_tool/BUILD_NOTES.md
Normal 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
|
||||||
|
```
|
||||||
43
flash_tool/ESP32_Flasher.spec
Normal file
43
flash_tool/ESP32_Flasher.spec
Normal 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,
|
||||||
|
)
|
||||||
45
flash_tool/ESP32_Flasher_Windows.spec
Normal file
45
flash_tool/ESP32_Flasher_Windows.spec
Normal 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
|
||||||
|
)
|
||||||
56
flash_tool/ESP32_Flasher_macOS.spec
Normal file
56
flash_tool/ESP32_Flasher_macOS.spec
Normal 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',
|
||||||
|
},
|
||||||
|
)
|
||||||
81
flash_tool/ESP32_WebFlasher_Windows.spec
Normal file
81
flash_tool/ESP32_WebFlasher_Windows.spec
Normal 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
|
||||||
|
)
|
||||||
69
flash_tool/ESP32_WebFlasher_macOS.spec
Normal file
69
flash_tool/ESP32_WebFlasher_macOS.spec
Normal 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
148
flash_tool/README.md
Normal 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
BIN
flash_tool/SoundShot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 105 KiB |
171
flash_tool/build.py
Executable file
171
flash_tool/build.py
Executable 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
7
flash_tool/build_exe.bat
Normal 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
|
||||||
49
flash_tool/build_executable.py
Normal file
49
flash_tool/build_executable.py
Normal 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()
|
||||||
24
flash_tool/build_from_spec.bat
Normal file
24
flash_tool/build_from_spec.bat
Normal 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
45
flash_tool/build_macos.sh
Executable 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
43
flash_tool/build_web_macos.sh
Executable 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
|
||||||
32
flash_tool/build_web_windows.bat
Normal file
32
flash_tool/build_web_windows.bat
Normal 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
|
||||||
14
flash_tool/build_with_auto_py_to_exe.bat
Normal file
14
flash_tool/build_with_auto_py_to_exe.bat
Normal 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
|
||||||
337
flash_tool/gui_flasher.py
Normal file
337
flash_tool/gui_flasher.py
Normal 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()
|
||||||
6
flash_tool/requirements.txt
Normal file
6
flash_tool/requirements.txt
Normal 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
|
||||||
BIN
flash_tool/static/SoundShot.png
Normal file
BIN
flash_tool/static/SoundShot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 105 KiB |
570
flash_tool/templates/index.html
Normal file
570
flash_tool/templates/index.html
Normal 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
343
flash_tool/web_flasher.py
Normal 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()
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
idf_component_register(SRCS "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
|
idf_component_register(SRCS "battery.c" "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
|
||||||
"gui.c"
|
"gui.c"
|
||||||
"lsm6dsv.c"
|
"lsm6dsv.c"
|
||||||
INCLUDE_DIRS "."
|
INCLUDE_DIRS "."
|
||||||
@@ -8,5 +8,6 @@ idf_component_register(SRCS "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
|
|||||||
"esp_lvgl_port"
|
"esp_lvgl_port"
|
||||||
"esp_timer"
|
"esp_timer"
|
||||||
"nvs_flash"
|
"nvs_flash"
|
||||||
"bt")
|
"bt"
|
||||||
|
"esp_adc")
|
||||||
|
|
||||||
|
|||||||
271
main/battery.c
Normal file
271
main/battery.c
Normal 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
56
main/battery.h
Normal 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
|
||||||
753
main/bt_app.c
753
main/bt_app.c
@@ -24,6 +24,10 @@
|
|||||||
#include "esp_gap_bt_api.h"
|
#include "esp_gap_bt_api.h"
|
||||||
#include "esp_a2dp_api.h"
|
#include "esp_a2dp_api.h"
|
||||||
#include "esp_avrc_api.h"
|
#include "esp_avrc_api.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
#include "nvs.h"
|
||||||
|
#include "esp_timer.h"
|
||||||
|
|
||||||
|
|
||||||
/* log tags */
|
/* log tags */
|
||||||
#define BT_AV_TAG "BT_AV"
|
#define BT_AV_TAG "BT_AV"
|
||||||
@@ -31,12 +35,18 @@
|
|||||||
|
|
||||||
/* device name */
|
/* device name */
|
||||||
#define TARGET_DEVICE_NAME "ESP_SPEAKER"
|
#define TARGET_DEVICE_NAME "ESP_SPEAKER"
|
||||||
#define LOCAL_DEVICE_NAME "ESP_A2DP_SRC"
|
#define LOCAL_DEVICE_NAME "SOUNDSHOT"
|
||||||
|
|
||||||
/* AVRCP used transaction label */
|
/* AVRCP used transaction label */
|
||||||
#define APP_RC_CT_TL_GET_CAPS (0)
|
#define APP_RC_CT_TL_GET_CAPS (0)
|
||||||
#define APP_RC_CT_TL_RN_VOLUME_CHANGE (1)
|
#define APP_RC_CT_TL_RN_VOLUME_CHANGE (1)
|
||||||
|
|
||||||
|
/* NVS storage constants */
|
||||||
|
#define NVS_NAMESPACE "bt_devices"
|
||||||
|
#define NVS_KEY_PREFIX "device_"
|
||||||
|
#define NVS_KEY_COUNT "dev_count"
|
||||||
|
#define MAX_PAIRED_DEVICES 10
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
BT_APP_STACK_UP_EVT = 0x0000, /* event for stack up */
|
BT_APP_STACK_UP_EVT = 0x0000, /* event for stack up */
|
||||||
BT_APP_HEART_BEAT_EVT = 0xff00, /* event for heart beat */
|
BT_APP_HEART_BEAT_EVT = 0xff00, /* event for heart beat */
|
||||||
@@ -97,7 +107,13 @@ static void bt_app_a2d_heart_beat(TimerHandle_t arg);
|
|||||||
static void bt_app_av_sm_hdlr(uint16_t event, void *param);
|
static void bt_app_av_sm_hdlr(uint16_t event, void *param);
|
||||||
|
|
||||||
/* utils for transfer BLuetooth Deveice Address into string form */
|
/* utils for transfer BLuetooth Deveice Address into string form */
|
||||||
static char *bda2str(esp_bd_addr_t bda, char *str, size_t size);
|
static char *bda2str(const uint8_t *bda, char *str, size_t size);
|
||||||
|
|
||||||
|
static esp_err_t bt_try_connect_known_devices(void);
|
||||||
|
static void bt_debug_print_known_devices(void);
|
||||||
|
static esp_err_t bt_add_discovered_device(esp_bd_addr_t bda, const char *name);
|
||||||
|
static esp_err_t bt_try_connect_all_known_devices(void);
|
||||||
|
static esp_err_t bt_try_next_known_device(void);
|
||||||
|
|
||||||
/* A2DP application state machine handler for each state */
|
/* A2DP application state machine handler for each state */
|
||||||
static void bt_app_av_state_unconnected_hdlr(uint16_t event, void *param);
|
static void bt_app_av_state_unconnected_hdlr(uint16_t event, void *param);
|
||||||
@@ -105,6 +121,8 @@ static void bt_app_av_state_connecting_hdlr(uint16_t event, void *param);
|
|||||||
static void bt_app_av_state_connected_hdlr(uint16_t event, void *param);
|
static void bt_app_av_state_connected_hdlr(uint16_t event, void *param);
|
||||||
static void bt_app_av_state_disconnecting_hdlr(uint16_t event, void *param);
|
static void bt_app_av_state_disconnecting_hdlr(uint16_t event, void *param);
|
||||||
|
|
||||||
|
static void add_device_to_list(esp_bd_addr_t bda, const char *name, bool is_paired, int rssi);
|
||||||
|
|
||||||
/*********************************
|
/*********************************
|
||||||
* STATIC VARIABLE DEFINITIONS
|
* STATIC VARIABLE DEFINITIONS
|
||||||
********************************/
|
********************************/
|
||||||
@@ -119,13 +137,337 @@ static int s_media_state = APP_AV_MEDIA_STATE_IDLE; /* sub states of A
|
|||||||
static int s_intv_cnt = 0; /* count of heart beat intervals */
|
static int s_intv_cnt = 0; /* count of heart beat intervals */
|
||||||
static int s_connecting_intv = 0; /* count of heart beat intervals for connecting */
|
static int s_connecting_intv = 0; /* count of heart beat intervals for connecting */
|
||||||
static uint32_t s_pkt_cnt = 0; /* count of packets */
|
static uint32_t s_pkt_cnt = 0; /* count of packets */
|
||||||
|
|
||||||
|
/* Device list for GUI */
|
||||||
|
static bt_device_list_t s_device_list = {0};
|
||||||
static esp_avrc_rn_evt_cap_mask_t s_avrc_peer_rn_cap; /* AVRC target notification event capability bit mask */
|
static esp_avrc_rn_evt_cap_mask_t s_avrc_peer_rn_cap; /* AVRC target notification event capability bit mask */
|
||||||
static TimerHandle_t s_tmr;
|
static TimerHandle_t s_tmr;
|
||||||
|
static int s_current_device_index = -1; /* index of device currently being attempted */
|
||||||
|
static paired_device_t s_known_devices[MAX_PAIRED_DEVICES]; /* cached list of known devices */
|
||||||
|
static size_t s_known_device_count = 0; /* count of cached known devices */
|
||||||
|
|
||||||
|
/* Volume control */
|
||||||
|
static uint8_t s_volume_level = 64; /* Current volume (0-127, default ~50%) */
|
||||||
|
static bool s_volume_control_available = false; /* Whether AVRC volume control is available */
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
* NVS STORAGE FUNCTION DEFINITIONS
|
||||||
|
********************************/
|
||||||
|
|
||||||
|
// This function is no longer used - replaced by system_savePairedDevice
|
||||||
|
|
||||||
|
// This function is no longer used - replaced by system_loadPairedDevices
|
||||||
|
|
||||||
|
// This function is no longer used - replaced by system_isDeviceKnown
|
||||||
|
|
||||||
|
static esp_err_t bt_try_connect_known_devices(void)
|
||||||
|
{
|
||||||
|
paired_device_t devices[MAX_PAIRED_DEVICES];
|
||||||
|
size_t count = MAX_PAIRED_DEVICES;
|
||||||
|
|
||||||
|
esp_err_t ret = system_loadPairedDevices(devices, &count);
|
||||||
|
if (ret != ESP_OK || count == 0) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "No known devices to connect to");
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter out devices that have never been connected (last_connected == 0)
|
||||||
|
// and sort by last_connected timestamp (most recent first)
|
||||||
|
paired_device_t connected_devices[MAX_PAIRED_DEVICES];
|
||||||
|
size_t connected_count = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (devices[i].last_connected > 0) {
|
||||||
|
connected_devices[connected_count++] = devices[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connected_count == 0) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "No previously connected devices to reconnect to");
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort connected devices by last_connected timestamp (most recent first)
|
||||||
|
for (int i = 0; i < connected_count - 1; i++) {
|
||||||
|
for (int j = i + 1; j < connected_count; j++) {
|
||||||
|
if (connected_devices[i].last_connected < connected_devices[j].last_connected) {
|
||||||
|
paired_device_t temp = connected_devices[i];
|
||||||
|
connected_devices[i] = connected_devices[j];
|
||||||
|
connected_devices[j] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to connect to the most recently connected device
|
||||||
|
char bda_str[18];
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Attempting to connect to previously connected device: %s (%s)",
|
||||||
|
connected_devices[0].name, bda2str(connected_devices[0].bda, bda_str, sizeof(bda_str)));
|
||||||
|
|
||||||
|
memcpy(s_peer_bda, connected_devices[0].bda, ESP_BD_ADDR_LEN);
|
||||||
|
strcpy((char*)s_peer_bdname, connected_devices[0].name);
|
||||||
|
|
||||||
|
ret = esp_a2d_source_connect(s_peer_bda);
|
||||||
|
if (ret == ESP_OK) {
|
||||||
|
s_a2d_state = APP_AV_STATE_CONNECTING;
|
||||||
|
s_connecting_intv = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bt_debug_print_known_devices(void)
|
||||||
|
{
|
||||||
|
const paired_device_t* devices;
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
devices = system_getPairedDevices(&count);
|
||||||
|
if (!devices) {
|
||||||
|
ESP_LOGE(BT_AV_TAG, "Failed to load devices for debug");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(BT_AV_TAG, "=== Known Paired Devices (%d) ===", count);
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
char bda_str[18];
|
||||||
|
ESP_LOGI(BT_AV_TAG, "%d: %s (%s) last_connected: %lu",
|
||||||
|
i + 1, devices[i].name,
|
||||||
|
bda2str(devices[i].bda, bda_str, sizeof(bda_str)),
|
||||||
|
devices[i].last_connected);
|
||||||
|
}
|
||||||
|
ESP_LOGI(BT_AV_TAG, "=== End Device List ===");
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t __attribute__((unused)) nvs_remove_paired_device(esp_bd_addr_t bda)
|
||||||
|
{
|
||||||
|
paired_device_t devices[MAX_PAIRED_DEVICES];
|
||||||
|
size_t count = MAX_PAIRED_DEVICES;
|
||||||
|
|
||||||
|
esp_err_t ret = system_loadPairedDevices(devices, &count);
|
||||||
|
if (ret != ESP_OK || count == 0) {
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find device to remove
|
||||||
|
int found_index = -1;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (memcmp(devices[i].bda, bda, ESP_BD_ADDR_LEN) == 0) {
|
||||||
|
found_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_index == -1) {
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open NVS for writing
|
||||||
|
nvs_handle_t nvs_handle;
|
||||||
|
ret = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shift remaining devices
|
||||||
|
for (int i = found_index; i < count - 1; i++) {
|
||||||
|
devices[i] = devices[i + 1];
|
||||||
|
}
|
||||||
|
count--;
|
||||||
|
|
||||||
|
// Save updated devices
|
||||||
|
char key[32];
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
snprintf(key, sizeof(key), "%s%d", NVS_KEY_PREFIX, i);
|
||||||
|
ret = nvs_set_blob(nvs_handle, key, &devices[i], sizeof(paired_device_t));
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
nvs_close(nvs_handle);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the last device slot
|
||||||
|
snprintf(key, sizeof(key), "%s%d", NVS_KEY_PREFIX, (int)count);
|
||||||
|
nvs_erase_key(nvs_handle, key);
|
||||||
|
|
||||||
|
// Update count
|
||||||
|
ret = nvs_set_blob(nvs_handle, NVS_KEY_COUNT, &count, sizeof(size_t));
|
||||||
|
if (ret == ESP_OK) {
|
||||||
|
ret = nvs_commit(nvs_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_close(nvs_handle);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t __attribute__((unused)) nvs_get_known_device_count(size_t *count)
|
||||||
|
{
|
||||||
|
if (!count) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_handle_t nvs_handle;
|
||||||
|
esp_err_t ret = nvs_open(NVS_NAMESPACE, NVS_READONLY, &nvs_handle);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
*count = 0;
|
||||||
|
return ESP_OK; // No devices is not an error
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t required_size = sizeof(size_t);
|
||||||
|
ret = nvs_get_blob(nvs_handle, NVS_KEY_COUNT, count, &required_size);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
*count = 0;
|
||||||
|
ret = ESP_OK; // No devices is not an error
|
||||||
|
}
|
||||||
|
|
||||||
|
nvs_close(nvs_handle);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t bt_add_discovered_device(esp_bd_addr_t bda, const char *name)
|
||||||
|
{
|
||||||
|
if (!bda || !name) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't save discovered devices to NVS - they're not paired yet!
|
||||||
|
// They will only be saved to NVS when successfully connected.
|
||||||
|
// Just log that we discovered this device.
|
||||||
|
char bda_str[18];
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Discovered device: %s (%s)",
|
||||||
|
name, bda2str(bda, bda_str, sizeof(bda_str)));
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t __attribute__((unused)) nvs_update_connection_timestamp(esp_bd_addr_t bda)
|
||||||
|
{
|
||||||
|
if (!bda) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
paired_device_t devices[MAX_PAIRED_DEVICES];
|
||||||
|
size_t count = MAX_PAIRED_DEVICES;
|
||||||
|
|
||||||
|
esp_err_t ret = system_loadPairedDevices(devices, &count);
|
||||||
|
if (ret != ESP_OK || count == 0) {
|
||||||
|
ESP_LOGW(BT_AV_TAG, "No devices found to update timestamp");
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the device and update its timestamp
|
||||||
|
int device_index = -1;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (memcmp(devices[i].bda, bda, ESP_BD_ADDR_LEN) == 0) {
|
||||||
|
device_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device_index == -1) {
|
||||||
|
ESP_LOGW(BT_AV_TAG, "Device not found in NVS to update timestamp");
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update timestamp to current time (using ESP timer)
|
||||||
|
devices[device_index].last_connected = (uint32_t)(esp_timer_get_time() / 1000000); // Convert to seconds
|
||||||
|
|
||||||
|
// Save updated device
|
||||||
|
ret = system_savePairedDevice(&devices[device_index]);
|
||||||
|
if (ret == ESP_OK) {
|
||||||
|
char bda_str[18];
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Updated connection timestamp for device: %s (%s)",
|
||||||
|
devices[device_index].name, bda2str(devices[device_index].bda, bda_str, sizeof(bda_str)));
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(BT_AV_TAG, "Failed to update connection timestamp: %s", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t bt_try_connect_all_known_devices(void)
|
||||||
|
{
|
||||||
|
// Load all known devices into cache
|
||||||
|
s_known_device_count = MAX_PAIRED_DEVICES;
|
||||||
|
esp_err_t ret = system_loadPairedDevices(s_known_devices, &s_known_device_count);
|
||||||
|
if (ret != ESP_OK || s_known_device_count == 0) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "No known devices to connect to");
|
||||||
|
s_current_device_index = -1;
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort devices by last_connected timestamp (most recent first)
|
||||||
|
// This prioritizes recently connected devices
|
||||||
|
for (int i = 0; i < s_known_device_count - 1; i++) {
|
||||||
|
for (int j = i + 1; j < s_known_device_count; j++) {
|
||||||
|
if (s_known_devices[i].last_connected < s_known_devices[j].last_connected) {
|
||||||
|
paired_device_t temp = s_known_devices[i];
|
||||||
|
s_known_devices[i] = s_known_devices[j];
|
||||||
|
s_known_devices[j] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start with the first (most recently connected) device
|
||||||
|
s_current_device_index = 0;
|
||||||
|
|
||||||
|
char bda_str[18];
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Attempting to connect to device %d/%d: %s (%s)",
|
||||||
|
s_current_device_index + 1, (int)s_known_device_count,
|
||||||
|
s_known_devices[s_current_device_index].name,
|
||||||
|
bda2str(s_known_devices[s_current_device_index].bda, bda_str, sizeof(bda_str)));
|
||||||
|
|
||||||
|
memcpy(s_peer_bda, s_known_devices[s_current_device_index].bda, ESP_BD_ADDR_LEN);
|
||||||
|
strcpy((char*)s_peer_bdname, s_known_devices[s_current_device_index].name);
|
||||||
|
|
||||||
|
ret = esp_a2d_source_connect(s_peer_bda);
|
||||||
|
if (ret == ESP_OK) {
|
||||||
|
s_a2d_state = APP_AV_STATE_CONNECTING;
|
||||||
|
s_connecting_intv = 0;
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(BT_AV_TAG, "Failed to initiate connection: %s", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t bt_try_next_known_device(void)
|
||||||
|
{
|
||||||
|
if (s_current_device_index < 0 || s_known_device_count == 0) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "No more devices to try");
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to next device
|
||||||
|
s_current_device_index++;
|
||||||
|
if (s_current_device_index >= s_known_device_count) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Exhausted all known devices, starting discovery...");
|
||||||
|
s_current_device_index = -1;
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
char bda_str[18];
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Attempting to connect to next device %d/%d: %s (%s)",
|
||||||
|
s_current_device_index + 1, (int)s_known_device_count,
|
||||||
|
s_known_devices[s_current_device_index].name,
|
||||||
|
bda2str(s_known_devices[s_current_device_index].bda, bda_str, sizeof(bda_str)));
|
||||||
|
|
||||||
|
memcpy(s_peer_bda, s_known_devices[s_current_device_index].bda, ESP_BD_ADDR_LEN);
|
||||||
|
strcpy((char*)s_peer_bdname, s_known_devices[s_current_device_index].name);
|
||||||
|
|
||||||
|
esp_err_t ret = esp_a2d_source_connect(s_peer_bda);
|
||||||
|
if (ret == ESP_OK) {
|
||||||
|
s_a2d_state = APP_AV_STATE_CONNECTING;
|
||||||
|
s_connecting_intv = 0;
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(BT_AV_TAG, "Failed to initiate connection: %s", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************
|
/*********************************
|
||||||
* STATIC FUNCTION DEFINITIONS
|
* STATIC FUNCTION DEFINITIONS
|
||||||
********************************/
|
********************************/
|
||||||
static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
|
static char *bda2str(const uint8_t *bda, char *str, size_t size)
|
||||||
{
|
{
|
||||||
if (bda == NULL || str == NULL || size < 18) {
|
if (bda == NULL || str == NULL || size < 18) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -199,9 +541,14 @@ static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log device details for debugging
|
||||||
|
ESP_LOGI(BT_AV_TAG, " CoD: 0x%"PRIx32", Valid: %d, RSSI: %"PRId32", EIR: %p",
|
||||||
|
cod, esp_bt_gap_is_valid_cod(cod), rssi, eir);
|
||||||
|
|
||||||
/* search for device with MAJOR service class as "rendering" in COD */
|
/* search for device with MAJOR service class as "rendering" in COD */
|
||||||
if (!esp_bt_gap_is_valid_cod(cod) ||
|
if (!esp_bt_gap_is_valid_cod(cod) ||
|
||||||
!(esp_bt_gap_get_cod_srvc(cod) & ESP_BT_COD_SRVC_RENDERING)) {
|
!(esp_bt_gap_get_cod_srvc(cod) & ESP_BT_COD_SRVC_RENDERING)) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, " Device filtered out - not an audio rendering device");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,14 +559,18 @@ static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
|
|||||||
/* search for target device in its Extended Inqury Response */
|
/* search for target device in its Extended Inqury Response */
|
||||||
if (eir) {
|
if (eir) {
|
||||||
get_name_from_eir(eir, s_peer_bdname, NULL);
|
get_name_from_eir(eir, s_peer_bdname, NULL);
|
||||||
//if (strcmp((char *)s_peer_bdname, TARGET_DEVICE_NAME) == 0)
|
|
||||||
{
|
// Save discovered audio device to NVS (but don't connect to it)
|
||||||
ESP_LOGI(BT_AV_TAG, "Found a target device, address %s, name %s", bda_str, s_peer_bdname);
|
bt_add_discovered_device(param->disc_res.bda, (char *)s_peer_bdname);
|
||||||
s_a2d_state = APP_AV_STATE_DISCOVERED;
|
|
||||||
memcpy(s_peer_bda, param->disc_res.bda, ESP_BD_ADDR_LEN);
|
// Add to device list for GUI
|
||||||
ESP_LOGI(BT_AV_TAG, "Cancel device discovery ...");
|
add_device_to_list(param->disc_res.bda, (char *)s_peer_bdname, false, rssi);
|
||||||
esp_bt_gap_cancel_discovery();
|
|
||||||
}
|
ESP_LOGI(BT_AV_TAG, "Found audio device, address %s, name %s (added to list)",
|
||||||
|
bda_str, s_peer_bdname);
|
||||||
|
|
||||||
|
// Don't automatically connect - just continue discovering more devices
|
||||||
|
// User will manually select a device from the menu to connect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,27 +579,34 @@ static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *pa
|
|||||||
switch (event) {
|
switch (event) {
|
||||||
/* when device discovered a result, this event comes */
|
/* when device discovered a result, this event comes */
|
||||||
case ESP_BT_GAP_DISC_RES_EVT: {
|
case ESP_BT_GAP_DISC_RES_EVT: {
|
||||||
if (s_a2d_state == APP_AV_STATE_DISCOVERING) {
|
// Log ALL discovered devices for debugging
|
||||||
|
char bda_str[18];
|
||||||
|
ESP_LOGI(BT_AV_TAG, "*** Device discovered: %s (A2DP state: %d)",
|
||||||
|
bda2str(param->disc_res.bda, bda_str, 18), s_a2d_state);
|
||||||
|
|
||||||
|
// Process the result regardless of A2DP state
|
||||||
filter_inquiry_scan_result(param);
|
filter_inquiry_scan_result(param);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* when discovery state changed, this event comes */
|
/* when discovery state changed, this event comes */
|
||||||
case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: {
|
case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: {
|
||||||
if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) {
|
if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Device discovery stopped.");
|
||||||
|
s_device_list.discovery_active = false;
|
||||||
|
|
||||||
|
// Notify GUI that discovery is complete so it can refresh the display
|
||||||
|
system_notifyAll(EM_EVENT_BT_DISCOVERY_COMPLETE);
|
||||||
|
|
||||||
|
// Don't automatically connect - wait for user selection
|
||||||
|
// Only connect if we're in DISCOVERED state (manually triggered by bt_connect_device)
|
||||||
if (s_a2d_state == APP_AV_STATE_DISCOVERED) {
|
if (s_a2d_state == APP_AV_STATE_DISCOVERED) {
|
||||||
s_a2d_state = APP_AV_STATE_CONNECTING;
|
s_a2d_state = APP_AV_STATE_CONNECTING;
|
||||||
ESP_LOGI(BT_AV_TAG, "Device discovery stopped.");
|
|
||||||
ESP_LOGI(BT_AV_TAG, "a2dp connecting to peer: %s", s_peer_bdname);
|
ESP_LOGI(BT_AV_TAG, "a2dp connecting to peer: %s", s_peer_bdname);
|
||||||
/* connect source to peer device specified by Bluetooth Device Address */
|
|
||||||
esp_a2d_source_connect(s_peer_bda);
|
esp_a2d_source_connect(s_peer_bda);
|
||||||
} else {
|
|
||||||
/* not discovered, continue to discover */
|
|
||||||
ESP_LOGI(BT_AV_TAG, "Device discovery failed, continue to discover...");
|
|
||||||
esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
|
|
||||||
}
|
}
|
||||||
} else if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STARTED) {
|
} else if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STARTED) {
|
||||||
ESP_LOGI(BT_AV_TAG, "Discovery started.");
|
ESP_LOGI(BT_AV_TAG, "Discovery started.");
|
||||||
|
s_device_list.discovery_active = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -344,9 +702,19 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
|
|||||||
esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
|
esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
|
||||||
esp_bt_gap_get_device_name();
|
esp_bt_gap_get_device_name();
|
||||||
|
|
||||||
ESP_LOGI(BT_AV_TAG, "Starting device discovery...");
|
// Print list of saved devices from NVS
|
||||||
s_a2d_state = APP_AV_STATE_DISCOVERING;
|
bt_debug_print_known_devices();
|
||||||
esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
|
|
||||||
|
// Try to connect to known devices automatically (those we've connected to before)
|
||||||
|
esp_err_t connect_ret = bt_try_connect_known_devices();
|
||||||
|
if (connect_ret != ESP_OK) {
|
||||||
|
// No known devices found - stay in unconnected state
|
||||||
|
// Don't start discovery automatically - user must do it from menu
|
||||||
|
ESP_LOGI(BT_AV_TAG, "No previously connected devices found. User can discover devices from menu.");
|
||||||
|
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Attempting to connect to previously connected device...");
|
||||||
|
}
|
||||||
|
|
||||||
/* create and start heart beat timer */
|
/* create and start heart beat timer */
|
||||||
do {
|
do {
|
||||||
@@ -365,6 +733,7 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
|
static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
|
||||||
{
|
{
|
||||||
bt_app_work_dispatch(bt_app_av_sm_hdlr, event, param, sizeof(esp_a2d_cb_param_t), NULL);
|
bt_app_work_dispatch(bt_app_av_sm_hdlr, event, param, sizeof(esp_a2d_cb_param_t), NULL);
|
||||||
@@ -413,7 +782,7 @@ void generate_synth_pcm(uint8_t *buf, int len) {
|
|||||||
#define MAX_RATE_HZ 440.0f
|
#define MAX_RATE_HZ 440.0f
|
||||||
#define CLICK_AMPLITUDE 32000 // 16-bit
|
#define CLICK_AMPLITUDE 32000 // 16-bit
|
||||||
#define EXP_K 3.0f
|
#define EXP_K 3.0f
|
||||||
#define DEADBAND_ANGLE 0.25f
|
#define DEADBAND_ANGLE 0.5f
|
||||||
|
|
||||||
static float click_timer = 0.0f;
|
static float click_timer = 0.0f;
|
||||||
|
|
||||||
@@ -429,6 +798,8 @@ void generate_exp(uint8_t *buf, int len, float balance)
|
|||||||
//float rate_hz = MIN_RATE_HZ * powf(MAX_RATE_HZ / MIN_RATE_HZ, abs_balance);
|
//float rate_hz = MIN_RATE_HZ * powf(MAX_RATE_HZ / MIN_RATE_HZ, abs_balance);
|
||||||
float samples_per_click = SAMPLE_RATE / rate_hz;
|
float samples_per_click = SAMPLE_RATE / rate_hz;
|
||||||
|
|
||||||
|
bool swap_lr = system_getSwapLR();
|
||||||
|
|
||||||
for (int i = 0; i < samples_needed; i++) {
|
for (int i = 0; i < samples_needed; i++) {
|
||||||
int16_t left = 0;
|
int16_t left = 0;
|
||||||
int16_t right = 0;
|
int16_t right = 0;
|
||||||
@@ -445,8 +816,13 @@ void generate_exp(uint8_t *buf, int len, float balance)
|
|||||||
|
|
||||||
click_timer -= 1.0f;
|
click_timer -= 1.0f;
|
||||||
|
|
||||||
|
if (swap_lr) {
|
||||||
|
samples[i * 2 + 0] = right;
|
||||||
|
samples[i * 2 + 1] = left;
|
||||||
|
} else {
|
||||||
samples[i * 2 + 0] = left;
|
samples[i * 2 + 0] = left;
|
||||||
samples[i * 2 + 1] = right;
|
samples[i * 2 + 1] = right;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -585,6 +961,10 @@ void audio_producer_task(void *pvParameters) {
|
|||||||
/* generate some random noise to simulate source audio */
|
/* generate some random noise to simulate source audio */
|
||||||
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
|
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
|
||||||
{
|
{
|
||||||
|
if (data == NULL || len <= 0 || audio_stream_buf == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
size_t bytes_read = xStreamBufferReceive(audio_stream_buf, data, len, 0);
|
size_t bytes_read = xStreamBufferReceive(audio_stream_buf, data, len, 0);
|
||||||
|
|
||||||
if (bytes_read < len) {
|
if (bytes_read < len) {
|
||||||
@@ -697,12 +1077,8 @@ static void bt_app_av_state_unconnected_hdlr(uint16_t event, void *param)
|
|||||||
case ESP_A2D_MEDIA_CTRL_ACK_EVT:
|
case ESP_A2D_MEDIA_CTRL_ACK_EVT:
|
||||||
break;
|
break;
|
||||||
case BT_APP_HEART_BEAT_EVT: {
|
case BT_APP_HEART_BEAT_EVT: {
|
||||||
uint8_t *bda = s_peer_bda;
|
// Don't automatically try to reconnect - wait for user to select device
|
||||||
ESP_LOGI(BT_AV_TAG, "a2dp connecting to peer: %02x:%02x:%02x:%02x:%02x:%02x",
|
// from the menu
|
||||||
bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
|
|
||||||
esp_a2d_source_connect(s_peer_bda);
|
|
||||||
s_a2d_state = APP_AV_STATE_CONNECTING;
|
|
||||||
s_connecting_intv = 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ESP_A2D_REPORT_SNK_DELAY_VALUE_EVT: {
|
case ESP_A2D_REPORT_SNK_DELAY_VALUE_EVT: {
|
||||||
@@ -729,7 +1105,33 @@ static void bt_app_av_state_connecting_hdlr(uint16_t event, void *param)
|
|||||||
ESP_LOGI(BT_AV_TAG, "a2dp connected");
|
ESP_LOGI(BT_AV_TAG, "a2dp connected");
|
||||||
s_a2d_state = APP_AV_STATE_CONNECTED;
|
s_a2d_state = APP_AV_STATE_CONNECTED;
|
||||||
s_media_state = APP_AV_MEDIA_STATE_IDLE;
|
s_media_state = APP_AV_MEDIA_STATE_IDLE;
|
||||||
|
|
||||||
|
// Check if device is already paired, if not, add it as paired
|
||||||
|
if (!system_isDeviceKnown(s_peer_bda)) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Device not in paired list, adding: %s", s_peer_bdname);
|
||||||
|
paired_device_t new_device;
|
||||||
|
memcpy(new_device.bda, s_peer_bda, ESP_BD_ADDR_LEN);
|
||||||
|
strncpy(new_device.name, (char*)s_peer_bdname, DEVICE_NAME_MAX_LEN - 1);
|
||||||
|
new_device.name[DEVICE_NAME_MAX_LEN - 1] = '\0';
|
||||||
|
new_device.last_connected = (uint32_t)(esp_timer_get_time() / 1000000);
|
||||||
|
system_savePairedDevice(&new_device);
|
||||||
|
|
||||||
|
// Update the device in the GUI list to show it as paired
|
||||||
|
for (int i = 0; i < s_device_list.count; i++) {
|
||||||
|
if (memcmp(s_device_list.devices[i].bda, s_peer_bda, ESP_BD_ADDR_LEN) == 0) {
|
||||||
|
s_device_list.devices[i].is_paired = true;
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Marked device as paired in GUI list: %s", s_peer_bdname);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Update connection timestamp for this device
|
||||||
|
system_updateConnectionTimestamp(s_peer_bda);
|
||||||
|
}
|
||||||
} else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
|
} else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Connection failed.");
|
||||||
|
// If device was previously connected (known device), don't retry automatically
|
||||||
|
// User can manually reconnect from menu
|
||||||
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -744,6 +1146,9 @@ static void bt_app_av_state_connecting_hdlr(uint16_t event, void *param)
|
|||||||
* when connecting lasts more than 2 heart beat intervals.
|
* when connecting lasts more than 2 heart beat intervals.
|
||||||
*/
|
*/
|
||||||
if (++s_connecting_intv >= 2) {
|
if (++s_connecting_intv >= 2) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Connection timeout.");
|
||||||
|
// Return to unconnected state - don't retry automatically
|
||||||
|
// User can manually reconnect from menu
|
||||||
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
||||||
s_connecting_intv = 0;
|
s_connecting_intv = 0;
|
||||||
}
|
}
|
||||||
@@ -938,8 +1343,8 @@ void bt_av_notify_evt_handler(uint8_t event_id, esp_avrc_rn_param_t *event_param
|
|||||||
/* when volume changed locally on target, this event comes */
|
/* when volume changed locally on target, this event comes */
|
||||||
case ESP_AVRC_RN_VOLUME_CHANGE: {
|
case ESP_AVRC_RN_VOLUME_CHANGE: {
|
||||||
ESP_LOGI(BT_RC_CT_TAG, "Volume changed: %d", event_parameter->volume);
|
ESP_LOGI(BT_RC_CT_TAG, "Volume changed: %d", event_parameter->volume);
|
||||||
ESP_LOGI(BT_RC_CT_TAG, "Set absolute volume: volume %d", event_parameter->volume + 5);
|
// Update our stored volume level
|
||||||
esp_avrc_ct_send_set_absolute_volume_cmd(APP_RC_CT_TL_RN_VOLUME_CHANGE, event_parameter->volume + 5);
|
s_volume_level = event_parameter->volume;
|
||||||
bt_av_volume_changed();
|
bt_av_volume_changed();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -966,6 +1371,7 @@ static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param)
|
|||||||
esp_avrc_ct_send_get_rn_capabilities_cmd(APP_RC_CT_TL_GET_CAPS);
|
esp_avrc_ct_send_get_rn_capabilities_cmd(APP_RC_CT_TL_GET_CAPS);
|
||||||
} else {
|
} else {
|
||||||
s_avrc_peer_rn_cap.bits = 0;
|
s_avrc_peer_rn_cap.bits = 0;
|
||||||
|
s_volume_control_available = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -998,12 +1404,23 @@ static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param)
|
|||||||
rc->get_rn_caps_rsp.evt_set.bits);
|
rc->get_rn_caps_rsp.evt_set.bits);
|
||||||
s_avrc_peer_rn_cap.bits = rc->get_rn_caps_rsp.evt_set.bits;
|
s_avrc_peer_rn_cap.bits = rc->get_rn_caps_rsp.evt_set.bits;
|
||||||
|
|
||||||
|
// Check if volume control is available
|
||||||
|
if (esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_TEST, &s_avrc_peer_rn_cap, ESP_AVRC_RN_VOLUME_CHANGE)) {
|
||||||
|
s_volume_control_available = true;
|
||||||
|
ESP_LOGI(BT_RC_CT_TAG, "Volume control is available");
|
||||||
|
} else {
|
||||||
|
s_volume_control_available = false;
|
||||||
|
ESP_LOGI(BT_RC_CT_TAG, "Volume control is not available");
|
||||||
|
}
|
||||||
|
|
||||||
bt_av_volume_changed();
|
bt_av_volume_changed();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* when set absolute volume responded, this event comes */
|
/* when set absolute volume responded, this event comes */
|
||||||
case ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT: {
|
case ESP_AVRC_CT_SET_ABSOLUTE_VOLUME_RSP_EVT: {
|
||||||
ESP_LOGI(BT_RC_CT_TAG, "Set absolute volume response: volume %d", rc->set_volume_rsp.volume);
|
ESP_LOGI(BT_RC_CT_TAG, "Set absolute volume response: volume %d", rc->set_volume_rsp.volume);
|
||||||
|
// Update our stored volume level with the confirmed value
|
||||||
|
s_volume_level = rc->set_volume_rsp.volume;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* other */
|
/* other */
|
||||||
@@ -1044,8 +1461,32 @@ static void bt_app_task_handler(void *arg)
|
|||||||
ESP_LOGI("MY_TASK", "Running on core %d", core_id);
|
ESP_LOGI("MY_TASK", "Running on core %d", core_id);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
// Check for system events first
|
||||||
|
uint32_t notifiedBits = 0;
|
||||||
|
if (xTaskNotifyWait(0xFFFFFFFF, 0xFFFFFFFF, ¬ifiedBits, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||||
|
if (notifiedBits & EM_EVENT_BT_REFRESH) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "BT Refresh event received");
|
||||||
|
bt_clear_discovered_devices();
|
||||||
|
bt_start_discovery(); // Start new discovery after clearing
|
||||||
|
// Notify GUI that refresh is done - could add completion event if needed
|
||||||
|
}
|
||||||
|
if (notifiedBits & EM_EVENT_BT_CONNECT) {
|
||||||
|
int device_index = system_getBtDeviceIndex();
|
||||||
|
ESP_LOGI(BT_AV_TAG, "BT Connect event received for device %d", device_index);
|
||||||
|
bt_connect_device(device_index);
|
||||||
|
}
|
||||||
|
if (notifiedBits & EM_EVENT_VOLUME_UP) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Volume Up event received");
|
||||||
|
bt_volume_up();
|
||||||
|
}
|
||||||
|
if (notifiedBits & EM_EVENT_VOLUME_DOWN) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Volume Down event received");
|
||||||
|
bt_volume_down();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* receive message from work queue and handle it */
|
/* receive message from work queue and handle it */
|
||||||
if (pdTRUE == xQueueReceive(s_bt_app_task_queue, &msg, (TickType_t)portMAX_DELAY)) {
|
if (pdTRUE == xQueueReceive(s_bt_app_task_queue, &msg, pdMS_TO_TICKS(10))) {
|
||||||
ESP_LOGD(BT_APP_CORE_TAG, "%s, signal: 0x%x, event: 0x%x", __func__, msg.sig, msg.event);
|
ESP_LOGD(BT_APP_CORE_TAG, "%s, signal: 0x%x, event: 0x%x", __func__, msg.sig, msg.event);
|
||||||
|
|
||||||
switch (msg.sig) {
|
switch (msg.sig) {
|
||||||
@@ -1100,7 +1541,10 @@ void bt_app_task_start_up(void)
|
|||||||
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
|
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
|
||||||
//xTaskCreate(bt_app_task_handler, "BtAppTask", 8192, NULL, 10, &s_bt_app_task_handle);
|
//xTaskCreate(bt_app_task_handler, "BtAppTask", 8192, NULL, 10, &s_bt_app_task_handle);
|
||||||
|
|
||||||
xTaskCreatePinnedToCore(bt_app_task_handler, "BtAppTask", 8192, NULL, 10, NULL, 1);
|
xTaskCreatePinnedToCore(bt_app_task_handler, "BtAppTask", 8192, NULL, 10, &s_bt_app_task_handle, 1);
|
||||||
|
|
||||||
|
// Subscribe to system events for GUI communication
|
||||||
|
system_subscribe(s_bt_app_task_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_app_task_shut_down(void)
|
void bt_app_task_shut_down(void)
|
||||||
@@ -1205,7 +1649,244 @@ void bt_app_init(void)
|
|||||||
ESP_LOGI(BT_APP_CORE_TAG, "Audio synth producer started");
|
ESP_LOGI(BT_APP_CORE_TAG, "Audio synth producer started");
|
||||||
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
* BLUETOOTH DEVICE LIST MANAGEMENT FOR GUI
|
||||||
|
********************************/
|
||||||
|
|
||||||
|
static void add_device_to_list(esp_bd_addr_t bda, const char *name, bool is_paired, int rssi) {
|
||||||
|
if (!bda) {
|
||||||
|
ESP_LOGE(BT_AV_TAG, "Null BDA in add_device_to_list");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if device already exists
|
||||||
|
for (int i = 0; i < s_device_list.count; i++) {
|
||||||
|
if (memcmp(s_device_list.devices[i].bda, bda, ESP_BD_ADDR_LEN) == 0) {
|
||||||
|
// Update existing device
|
||||||
|
strncpy(s_device_list.devices[i].name, name ? name : "Unknown", MAX_BT_NAME_LEN - 1);
|
||||||
|
s_device_list.devices[i].name[MAX_BT_NAME_LEN - 1] = '\0';
|
||||||
|
s_device_list.devices[i].is_paired = is_paired;
|
||||||
|
s_device_list.devices[i].rssi = rssi;
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Updated existing device: %s (%s)",
|
||||||
|
s_device_list.devices[i].name,
|
||||||
|
is_paired ? "paired" : "discovered");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new device if there's space
|
||||||
|
if (s_device_list.count < MAX_BT_DEVICES) {
|
||||||
|
memcpy(s_device_list.devices[s_device_list.count].bda, bda, ESP_BD_ADDR_LEN);
|
||||||
|
strncpy(s_device_list.devices[s_device_list.count].name, name ? name : "Unknown", MAX_BT_NAME_LEN - 1);
|
||||||
|
s_device_list.devices[s_device_list.count].name[MAX_BT_NAME_LEN - 1] = '\0';
|
||||||
|
s_device_list.devices[s_device_list.count].is_paired = is_paired;
|
||||||
|
s_device_list.devices[s_device_list.count].rssi = rssi;
|
||||||
|
s_device_list.count++;
|
||||||
|
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Added new device to list: %s (%s), total devices: %d",
|
||||||
|
s_device_list.devices[s_device_list.count - 1].name,
|
||||||
|
is_paired ? "paired" : "discovered",
|
||||||
|
s_device_list.count);
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(BT_AV_TAG, "Device list full, cannot add device: %s", name ? name : "Unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load_paired_devices_to_list(void) {
|
||||||
|
paired_device_t paired_devices[MAX_PAIRED_DEVICES];
|
||||||
|
size_t count = MAX_PAIRED_DEVICES;
|
||||||
|
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Attempting to load paired devices from NVS");
|
||||||
|
esp_err_t err = system_loadPairedDevices(paired_devices, &count);
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Successfully loaded %d paired devices from NVS", (int)count);
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
add_device_to_list(paired_devices[i].bda, paired_devices[i].name, true, 0);
|
||||||
|
}
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Added %d paired devices to device list", (int)count);
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(BT_AV_TAG, "Failed to load paired devices from NVS: %s", esp_err_to_name(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_device_list_t* bt_get_device_list(void) {
|
||||||
|
// Initialize device list if needed
|
||||||
|
if (s_device_list.count == 0) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Loading paired devices to list");
|
||||||
|
load_paired_devices_to_list();
|
||||||
|
}
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Device list has %d devices", s_device_list.count);
|
||||||
|
return &s_device_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bt_start_discovery(void) {
|
||||||
|
if (s_device_list.discovery_active) {
|
||||||
|
ESP_LOGW(BT_AV_TAG, "Discovery already active");
|
||||||
|
return false; // Already discovering
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if Bluetooth stack is initialized
|
||||||
|
if (!esp_bluedroid_get_status()) {
|
||||||
|
ESP_LOGE(BT_AV_TAG, "Bluetooth stack not initialized");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check current A2DP state - avoid discovery during connection attempts
|
||||||
|
if (s_a2d_state == APP_AV_STATE_CONNECTING || s_a2d_state == APP_AV_STATE_DISCOVERING) {
|
||||||
|
ESP_LOGW(BT_AV_TAG, "Cannot start discovery - A2DP state: %d", s_a2d_state);
|
||||||
|
// Still load paired devices for display
|
||||||
|
load_paired_devices_to_list();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bluetooth stack is initialized and A2DP state is good - proceed with discovery
|
||||||
|
|
||||||
|
// Load paired devices first
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Loading paired devices before discovery");
|
||||||
|
load_paired_devices_to_list();
|
||||||
|
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Starting Bluetooth device discovery (A2DP state: %d)", s_a2d_state);
|
||||||
|
|
||||||
|
// Cancel any previous discovery to ensure clean state
|
||||||
|
esp_bt_gap_cancel_discovery();
|
||||||
|
|
||||||
|
// Small delay to ensure clean state
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
|
||||||
|
// Set discovery state first to prevent race conditions
|
||||||
|
s_device_list.discovery_active = true;
|
||||||
|
|
||||||
|
esp_err_t result = esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
|
||||||
|
if (result == ESP_OK) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Device discovery started successfully");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(BT_AV_TAG, "Failed to start discovery: %s (0x%x)", esp_err_to_name(result), result);
|
||||||
|
s_device_list.discovery_active = false; // Reset on failure
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bt_stop_discovery(void) {
|
||||||
|
esp_err_t result = esp_bt_gap_cancel_discovery();
|
||||||
|
s_device_list.discovery_active = false;
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Device discovery stopped");
|
||||||
|
return (result == ESP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bt_connect_device(int device_index) {
|
||||||
|
if (device_index < 0 || device_index >= s_device_list.count) {
|
||||||
|
ESP_LOGE(BT_AV_TAG, "Invalid device index: %d", device_index);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_device_info_t *device = &s_device_list.devices[device_index];
|
||||||
|
|
||||||
|
// Stop any ongoing discovery
|
||||||
|
if (s_device_list.discovery_active) {
|
||||||
|
bt_stop_discovery();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy device info for connection attempt
|
||||||
|
memcpy(s_peer_bda, device->bda, ESP_BD_ADDR_LEN);
|
||||||
|
strncpy((char*)s_peer_bdname, device->name, ESP_BT_GAP_MAX_BDNAME_LEN);
|
||||||
|
s_peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN] = '\0';
|
||||||
|
|
||||||
|
// If device is paired, connect directly
|
||||||
|
if (device->is_paired) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Connecting to paired device: %s", device->name);
|
||||||
|
s_a2d_state = APP_AV_STATE_CONNECTING;
|
||||||
|
esp_a2d_source_connect(device->bda);
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Pairing and connecting to device: %s", device->name);
|
||||||
|
s_a2d_state = APP_AV_STATE_DISCOVERED;
|
||||||
|
// The GAP callback will handle the connection after discovery stops
|
||||||
|
esp_bt_gap_cancel_discovery();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_clear_discovered_devices(void) {
|
||||||
|
int new_count = 0;
|
||||||
|
|
||||||
|
// Keep only paired devices
|
||||||
|
for (int i = 0; i < s_device_list.count; i++) {
|
||||||
|
if (s_device_list.devices[i].is_paired) {
|
||||||
|
if (new_count != i) {
|
||||||
|
s_device_list.devices[new_count] = s_device_list.devices[i];
|
||||||
|
}
|
||||||
|
new_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_device_list.count = new_count;
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Cleared discovered devices, kept %d paired devices", new_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_clear_all_devices(void) {
|
||||||
|
s_device_list.count = 0;
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Cleared all devices from device list");
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_disconnect_current_device(void) {
|
||||||
|
if (s_a2d_state == APP_AV_STATE_CONNECTED) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Disconnecting from current device");
|
||||||
|
|
||||||
|
// Stop media first if playing
|
||||||
|
if (s_media_state == APP_AV_MEDIA_STATE_STARTED) {
|
||||||
|
esp_a2d_media_ctrl(ESP_A2D_MEDIA_CTRL_SUSPEND);
|
||||||
|
s_media_state = APP_AV_MEDIA_STATE_STOPPING;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect A2DP
|
||||||
|
esp_a2d_source_disconnect(s_peer_bda);
|
||||||
|
s_a2d_state = APP_AV_STATE_DISCONNECTING;
|
||||||
|
} else if (s_a2d_state == APP_AV_STATE_CONNECTING) {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Cancelling connection attempt");
|
||||||
|
// Cancel connection attempt
|
||||||
|
s_a2d_state = APP_AV_STATE_UNCONNECTED;
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(BT_AV_TAG, "No device connected (state: %d)", s_a2d_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_volume_up(void) {
|
||||||
|
if (!s_volume_control_available) {
|
||||||
|
ESP_LOGW(BT_AV_TAG, "Volume control not available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_volume_level < 127) {
|
||||||
|
s_volume_level += 10; // Increase by ~8%
|
||||||
|
if (s_volume_level > 127) s_volume_level = 127;
|
||||||
|
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Setting volume to %d", s_volume_level);
|
||||||
|
esp_avrc_ct_send_set_absolute_volume_cmd(APP_RC_CT_TL_RN_VOLUME_CHANGE, s_volume_level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_volume_down(void) {
|
||||||
|
if (!s_volume_control_available) {
|
||||||
|
ESP_LOGW(BT_AV_TAG, "Volume control not available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_volume_level > 0) {
|
||||||
|
if (s_volume_level < 10) {
|
||||||
|
s_volume_level = 0;
|
||||||
|
} else {
|
||||||
|
s_volume_level -= 10; // Decrease by ~8%
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(BT_AV_TAG, "Setting volume to %d", s_volume_level);
|
||||||
|
esp_avrc_ct_send_set_absolute_volume_cmd(APP_RC_CT_TL_RN_VOLUME_CHANGE, s_volume_level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int bt_get_current_volume(void) {
|
||||||
|
// Convert from 0-127 to 0-100 for GUI
|
||||||
|
return (s_volume_level * 100) / 127;
|
||||||
}
|
}
|
||||||
@@ -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__ */
|
||||||
|
|||||||
10
main/gpio.h
10
main/gpio.h
@@ -4,9 +4,15 @@
|
|||||||
// 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
|
||||||
|
|||||||
1484
main/gui.c
1484
main/gui.c
File diff suppressed because it is too large
Load Diff
@@ -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.
|
||||||
|
|||||||
77
main/main.c
77
main/main.c
@@ -13,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"
|
||||||
@@ -27,13 +28,24 @@
|
|||||||
#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]
|
||||||
@@ -88,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
|
||||||
@@ -247,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();
|
||||||
@@ -255,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();
|
||||||
@@ -314,7 +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
|
||||||
}
|
}
|
||||||
|
|||||||
562
main/system.c
562
main/system.c
@@ -1,20 +1,49 @@
|
|||||||
#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)
|
||||||
@@ -43,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,3 +272,458 @@ void system_notifyAll(uint32_t eventBits) {
|
|||||||
xSemaphoreGive(em->mutex);
|
xSemaphoreGive(em->mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void system_requestBtRefresh(void) {
|
||||||
|
ESP_LOGI("system", "BT Refresh requested");
|
||||||
|
system_notifyAll(EM_EVENT_BT_REFRESH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void system_requestBtConnect(int device_index) {
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
|
_systemState.btDeviceIndex = device_index;
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
|
|
||||||
|
ESP_LOGI("system", "BT Connect requested for device %d", device_index);
|
||||||
|
system_notifyAll(EM_EVENT_BT_CONNECT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int system_getBtDeviceIndex(void) {
|
||||||
|
int index;
|
||||||
|
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);
|
||||||
|
_systemState.volume = volume;
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
|
|
||||||
|
ESP_LOGI("system", "Volume set to %d", volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
int system_getVolume(void) {
|
||||||
|
int volume;
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
|
volume = _systemState.volume;
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t system_saveVolume(void) {
|
||||||
|
nvs_handle_t nvs_handle;
|
||||||
|
esp_err_t ret;
|
||||||
|
|
||||||
|
int volume = system_getVolume();
|
||||||
|
|
||||||
|
ret = nvs_open(NVS_NAMESPACE_SETTINGS, NVS_READWRITE, &nvs_handle);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE("system", "Failed to open NVS namespace for volume write: %s", esp_err_to_name(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nvs_set_i32(nvs_handle, NVS_KEY_VOLUME, volume);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE("system", "Failed to write volume 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", "Volume %d saved to NVS", volume);
|
||||||
|
} else {
|
||||||
|
ESP_LOGE("system", "Failed to commit volume to NVS: %s", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t system_loadVolume(void) {
|
||||||
|
nvs_handle_t nvs_handle;
|
||||||
|
esp_err_t ret;
|
||||||
|
int32_t volume = 50; // Default value
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nvs_get_i32(nvs_handle, NVS_KEY_VOLUME, &volume);
|
||||||
|
nvs_close(nvs_handle);
|
||||||
|
|
||||||
|
if (ret == ESP_OK) {
|
||||||
|
ESP_LOGI("system", "Loaded volume from NVS: %ld", volume);
|
||||||
|
system_setVolume(volume);
|
||||||
|
} else if (ret == ESP_ERR_NVS_NOT_FOUND) {
|
||||||
|
ESP_LOGI("system", "No saved volume found, using default: %ld", volume);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t system_savePairedDevice(const paired_device_t *device) {
|
||||||
|
if (!device) return ESP_ERR_INVALID_ARG;
|
||||||
|
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
|
|
||||||
|
size_t existing_index = SIZE_MAX;
|
||||||
|
for (size_t i = 0; i < _systemState.pairedDeviceCount; i++) {
|
||||||
|
if (memcmp(_systemState.pairedDevices[i].bda, device->bda, ESP_BD_ADDR_LEN) == 0) {
|
||||||
|
existing_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing_index != SIZE_MAX) {
|
||||||
|
_systemState.pairedDevices[existing_index] = *device;
|
||||||
|
} else if (_systemState.pairedDeviceCount < MAX_PAIRED_DEVICES) {
|
||||||
|
_systemState.pairedDevices[_systemState.pairedDeviceCount++] = *device;
|
||||||
|
} else {
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
|
|
||||||
|
nvs_request_t request = {
|
||||||
|
.operation = NVS_OP_SAVE_DEVICE,
|
||||||
|
.device = *device,
|
||||||
|
.requestor = xTaskGetCurrentTaskHandle()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (xQueueSend(_nvsRequestQueue, &request, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) {
|
||||||
|
uint32_t notification;
|
||||||
|
if (xTaskNotifyWait(0, UINT32_MAX, ¬ification, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) {
|
||||||
|
// 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, ¬ification, 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, ¬ification, 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;
|
||||||
|
}
|
||||||
@@ -4,9 +4,22 @@
|
|||||||
#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,
|
||||||
@@ -32,10 +45,30 @@ 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.4f // 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 RIFLE_AXIS Y
|
||||||
@@ -43,6 +76,11 @@ typedef struct SystemState_s
|
|||||||
#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,5 +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
|
||||||
|
void system_requestVolumeUp(void);
|
||||||
|
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);
|
||||||
|
|
||||||
|
// NVS Service
|
||||||
|
typedef enum {
|
||||||
|
NVS_OP_SAVE_DEVICE,
|
||||||
|
NVS_OP_LOAD_DEVICES,
|
||||||
|
NVS_OP_REMOVE_DEVICE,
|
||||||
|
NVS_OP_IS_DEVICE_KNOWN,
|
||||||
|
NVS_OP_GET_DEVICE_COUNT,
|
||||||
|
NVS_OP_UPDATE_TIMESTAMP
|
||||||
|
} nvs_operation_type_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
nvs_operation_type_t operation;
|
||||||
|
paired_device_t device;
|
||||||
|
esp_bd_addr_t bda;
|
||||||
|
TaskHandle_t requestor;
|
||||||
|
esp_err_t result;
|
||||||
|
bool response_ready;
|
||||||
|
} nvs_request_t;
|
||||||
|
|
||||||
|
void system_initNvsService(void);
|
||||||
|
void system_processNvsRequests(void);
|
||||||
|
esp_err_t system_savePairedDevice(const paired_device_t *device);
|
||||||
|
esp_err_t system_loadPairedDevices(paired_device_t *devices, size_t *count);
|
||||||
|
esp_err_t system_removePairedDevice(esp_bd_addr_t bda);
|
||||||
|
bool system_isDeviceKnown(esp_bd_addr_t bda);
|
||||||
|
esp_err_t system_getKnownDeviceCount(size_t *count);
|
||||||
|
esp_err_t system_updateConnectionTimestamp(esp_bd_addr_t bda);
|
||||||
|
const paired_device_t* system_getPairedDevices(size_t *count);
|
||||||
|
esp_err_t system_clearAllPairedDevices(void);
|
||||||
|
|
||||||
|
|
||||||
|
#define NVS_TIMEOUT_MS 5000
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
set(PROJECT_NAME "soundshot")
|
set(PROJECT_NAME "soundshot")
|
||||||
set(CHIP "esp32")
|
set(CHIP "esp32")
|
||||||
set(PORT "COM3")
|
set(PORT "COM14")
|
||||||
set(BAUD "460800")
|
set(BAUD "460800")
|
||||||
|
|||||||
210
sdkconfig
210
sdkconfig
@@ -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
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|||||||
3109
sdkconfig.old
3109
sdkconfig.old
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"project_name": "soundshot",
|
"project_name": "soundshot",
|
||||||
"chip": "esp32",
|
"chip": "esp32",
|
||||||
"port": "COM3",
|
"port": "COM14",
|
||||||
"monitor_baud": 115200,
|
"monitor_baud": 115200,
|
||||||
"flash_baud": 460800,
|
"flash_baud": 460800,
|
||||||
"flash_mode": "dio",
|
"flash_mode": "dio",
|
||||||
|
|||||||
Reference in New Issue
Block a user