Compare commits

..

14 Commits

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 19:55:32 -06:00
Brent Perteet
19e8ca30c3 everything working and tested on separate computer 2025-10-27 18:27:55 -05:00
Brent Perteet
de7041c1f5 EXE working but getting logging error 2025-10-25 11:52:11 -05:00
Brent Perteet
fe69dc6f19 flash works when not in EXE 2025-10-25 11:29:53 -05:00
Brent Perteet
bca2f6ea9c Added logo to flasher 2025-10-14 09:50:35 -05:00
Brent Perteet
5a893a034c update flasher 2025-10-13 20:51:52 -05:00
2513a9e7fb adding web flasher tool 2025-10-13 18:54:50 -05:00
36 changed files with 7011 additions and 406 deletions

View File

@@ -6,7 +6,26 @@
"Bash(git add:*)", "Bash(git add:*)",
"Bash(git commit:*)", "Bash(git commit:*)",
"Bash(pip install:*)", "Bash(pip install:*)",
"Bash(build_from_spec.bat)" "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": [] "deny": []
} }

19
.gitignore vendored
View File

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

View File

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

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

14
.vscode/settings.json vendored
View File

@@ -1,11 +1,12 @@
{ {
"C_Cpp.intelliSenseEngine": "default", "C_Cpp.intelliSenseEngine": "default",
"idf.espIdfPathWin": "C:\\esp\\frameworks\\esp-idf-v5.3.3", "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:\\esp\\frameworks\\esp-idf-v5.3.3\\tools\\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"
} }

26
.vscode/tasks.json vendored
View File

@@ -1,11 +1,35 @@
{ {
"version": "2.0.0", "version": "2.0.0",
"tasks": [ "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", "label": "ESP-IDF: Build (RAM) + Sync to Host",
"type": "shell", "type": "shell",
"command": "bash -lc 'source ${IDF_PATH:-/opt/esp/idf}/export.sh && idf.py build && rsync -a --delete \"$PWD/build/\" /host_build/'", "command": "bash -lc 'source ${IDF_PATH:-/opt/esp/idf}/export.sh && idf.py build && rsync -a --delete \"$PWD/build/\" /host_build/'",
"group": { "kind": "build", "isDefault": true }, "group": "build",
"problemMatcher": "$gcc" "problemMatcher": "$gcc"
} }
] ]

View File

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

110
flash_tool/BUILD_NOTES.md Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

148
flash_tool/README.md Normal file
View File

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

BIN
flash_tool/SoundShot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

171
flash_tool/build.py Executable file
View File

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

View File

@@ -1,11 +1,24 @@
@echo off @echo off
echo === ESP32 Flasher - Windows Build Script ===
echo.
echo Installing dependencies... echo Installing dependencies...
pip install pyinstaller esptool pyserial pip install pyinstaller esptool pyserial
echo. echo.
echo Building executable from spec file... echo Building Windows executable...
pyinstaller ESP32_Flasher.spec pyinstaller ESP32_Flasher_Windows.spec
echo. echo.
echo Build complete! Find ESP32_Flasher.exe in the dist folder. 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 pause

45
flash_tool/build_macos.sh Executable file
View File

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

43
flash_tool/build_web_macos.sh Executable file
View File

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

View File

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

View File

@@ -20,84 +20,150 @@ class ESP32FlasherGUI:
self.root = root self.root = root
self.root.title("ESP32 Firmware Flasher") self.root.title("ESP32 Firmware Flasher")
self.root.geometry("600x500") self.root.geometry("600x500")
# Configure colors for dark mode compatibility
self.setup_colors()
# Variables # Variables
self.port_var = tk.StringVar() self.port_var = tk.StringVar()
self.firmware_path_var = tk.StringVar() self.firmware_path_var = tk.StringVar()
self.temp_dir = None self.temp_dir = None
self.setup_ui() self.setup_ui()
self.refresh_ports() 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): def setup_ui(self):
# Main frame # Main frame
main_frame = ttk.Frame(self.root, padding="10") 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)) main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# Configure grid weights # Configure grid weights
self.root.columnconfigure(0, weight=1) self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1) self.root.rowconfigure(0, weight=1)
main_frame.columnconfigure(1, weight=1) main_frame.columnconfigure(1, weight=1)
# Port selection # Port selection
ttk.Label(main_frame, text="Serial Port:").grid(row=0, column=0, sticky=tk.W, pady=5) tk.Label(main_frame, text="Serial Port:", bg=self.bg_color, fg=self.fg_color).grid(
port_frame = ttk.Frame(main_frame) 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.grid(row=0, column=1, sticky=(tk.W, tk.E), pady=5)
port_frame.columnconfigure(0, weight=1) port_frame.columnconfigure(0, weight=1)
self.port_combo = ttk.Combobox(port_frame, textvariable=self.port_var, state="readonly") 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)) self.port_combo.grid(row=0, column=0, sticky=(tk.W, tk.E), padx=(0, 5))
ttk.Button(port_frame, text="Refresh", command=self.refresh_ports).grid(row=0, column=1) 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 # Firmware package selection
ttk.Label(main_frame, text="Firmware Package:").grid(row=1, column=0, sticky=tk.W, pady=5) tk.Label(main_frame, text="Firmware Package:", bg=self.bg_color, fg=self.fg_color).grid(
firmware_frame = ttk.Frame(main_frame) 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.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=5)
firmware_frame.columnconfigure(0, weight=1) firmware_frame.columnconfigure(0, weight=1)
self.firmware_entry = ttk.Entry(firmware_frame, textvariable=self.firmware_path_var, state="readonly") 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)) self.firmware_entry.grid(row=0, column=0, sticky=(tk.W, tk.E), padx=(0, 5))
ttk.Button(firmware_frame, text="Browse", command=self.browse_firmware).grid(row=0, column=1) 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 # Flash settings frame
settings_frame = ttk.LabelFrame(main_frame, text="Flash Settings", padding="5") 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.grid(row=2, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=10)
settings_frame.columnconfigure(1, weight=1) settings_frame.columnconfigure(1, weight=1)
# Flash settings # Flash settings
ttk.Label(settings_frame, text="Chip:").grid(row=0, column=0, sticky=tk.W, pady=2) 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") self.chip_var = tk.StringVar(value="esp32")
ttk.Entry(settings_frame, textvariable=self.chip_var, width=15).grid(row=0, column=1, sticky=tk.W, pady=2) 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)
ttk.Label(settings_frame, text="Baud Rate:").grid(row=1, column=0, 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") self.baud_var = tk.StringVar(value="460800")
ttk.Entry(settings_frame, textvariable=self.baud_var, width=15).grid(row=1, column=1, sticky=tk.W, pady=2) 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)
ttk.Label(settings_frame, text="Flash Mode:").grid(row=2, column=0, 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") self.flash_mode_var = tk.StringVar(value="dio")
ttk.Entry(settings_frame, textvariable=self.flash_mode_var, width=15).grid(row=2, column=1, sticky=tk.W, pady=2) 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)
ttk.Label(settings_frame, text="Flash Freq:").grid(row=3, column=0, 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") self.flash_freq_var = tk.StringVar(value="40m")
ttk.Entry(settings_frame, textvariable=self.flash_freq_var, width=15).grid(row=3, column=1, sticky=tk.W, pady=2) 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)
ttk.Label(settings_frame, text="Flash Size:").grid(row=4, column=0, 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") self.flash_size_var = tk.StringVar(value="2MB")
ttk.Entry(settings_frame, textvariable=self.flash_size_var, width=15).grid(row=4, column=1, sticky=tk.W, pady=2) 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 # Flash button
self.flash_button = ttk.Button(main_frame, text="Flash Firmware", command=self.flash_firmware) 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) self.flash_button.grid(row=3, column=0, columnspan=2, pady=10)
# Progress bar # Progress bar
self.progress = ttk.Progressbar(main_frame, mode='indeterminate') self.progress = ttk.Progressbar(main_frame, mode='indeterminate')
self.progress.grid(row=4, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5) self.progress.grid(row=4, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)
# Log output # Log output
ttk.Label(main_frame, text="Output:").grid(row=5, column=0, sticky=tk.W, pady=(10, 0)) tk.Label(main_frame, text="Output:", bg=self.bg_color, fg=self.fg_color).grid(
self.log_text = scrolledtext.ScrolledText(main_frame, height=15, width=70) 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) 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) main_frame.rowconfigure(6, weight=1)

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

View File

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

343
flash_tool/web_flasher.py Normal file
View File

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

View File

@@ -1,12 +1,13 @@
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 "."
REQUIRES "driver" REQUIRES "driver"
"esp_lcd" "esp_lcd"
"lvgl" "lvgl"
"esp_lvgl_port" "esp_lvgl_port"
"esp_timer" "esp_timer"
"nvs_flash" "nvs_flash"
"bt") "bt"
"esp_adc")

271
main/battery.c Normal file
View File

@@ -0,0 +1,271 @@
#include "battery.h"
#include "system.h"
#include "gpio.h"
#include "esp_log.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
static const char *TAG = "battery";
static adc_oneshot_unit_handle_t adc1_handle = NULL;
static adc_cali_handle_t adc1_cali_handle = NULL;
static bool adc_calibration_enabled = false;
// ADC Calibration initialization
static bool adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle)
{
adc_cali_handle_t handle = NULL;
esp_err_t ret = ESP_FAIL;
bool calibrated = false;
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
if (!calibrated) {
ESP_LOGI(TAG, "Calibration scheme: Curve Fitting");
adc_cali_curve_fitting_config_t cali_config = {
.unit_id = unit,
.chan = channel,
.atten = atten,
.bitwidth = BATTERY_ADC_WIDTH,
};
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
#endif
#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
if (!calibrated) {
ESP_LOGI(TAG, "Calibration scheme: Line Fitting");
adc_cali_line_fitting_config_t cali_config = {
.unit_id = unit,
.atten = atten,
.bitwidth = BATTERY_ADC_WIDTH,
};
ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
#endif
*out_handle = handle;
if (ret == ESP_OK) {
ESP_LOGI(TAG, "ADC calibration successful");
} else {
ESP_LOGW(TAG, "ADC calibration failed: %s", esp_err_to_name(ret));
}
return calibrated;
}
esp_err_t battery_init(void)
{
esp_err_t ret;
// Configure ADC1 oneshot mode
adc_oneshot_unit_init_cfg_t init_config = {
.unit_id = ADC_UNIT_1,
};
ret = adc_oneshot_new_unit(&init_config, &adc1_handle);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize ADC unit: %s", esp_err_to_name(ret));
return ret;
}
// Configure ADC channel
adc_oneshot_chan_cfg_t config = {
.bitwidth = BATTERY_ADC_WIDTH,
.atten = BATTERY_ADC_ATTEN,
};
ret = adc_oneshot_config_channel(adc1_handle, BATTERY_ADC_CHANNEL, &config);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to configure ADC channel: %s", esp_err_to_name(ret));
return ret;
}
// Initialize calibration
adc_calibration_enabled = adc_calibration_init(ADC_UNIT_1, BATTERY_ADC_CHANNEL,
BATTERY_ADC_ATTEN, &adc1_cali_handle);
ESP_LOGI(TAG, "Battery monitoring initialized on GPIO34 (ADC1_CH6)");
return ESP_OK;
}
int battery_read_raw(void)
{
int adc_raw = 0;
esp_err_t ret = adc_oneshot_read(adc1_handle, BATTERY_ADC_CHANNEL, &adc_raw);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to read ADC: %s", esp_err_to_name(ret));
return -1;
}
return adc_raw;
}
int battery_read_voltage_mv(void)
{
int voltage_mv = 0;
int adc_sum = 0;
int valid_samples = 0;
// Take multiple samples and average
for (int i = 0; i < BATTERY_SAMPLES; i++) {
int adc_raw = battery_read_raw();
if (adc_raw >= 0) {
adc_sum += adc_raw;
valid_samples++;
}
vTaskDelay(pdMS_TO_TICKS(1)); // Small delay between samples
}
if (valid_samples == 0) {
ESP_LOGE(TAG, "No valid ADC samples");
return -1;
}
int adc_avg = adc_sum / valid_samples;
// Convert to voltage using calibration if available
if (adc_calibration_enabled) {
esp_err_t ret = adc_cali_raw_to_voltage(adc1_cali_handle, adc_avg, &voltage_mv);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "Calibration conversion failed, using raw calculation");
adc_calibration_enabled = false; // Disable for future reads
}
}
// Fallback to manual calculation if calibration not available
if (!adc_calibration_enabled) {
// Simple linear conversion for 12-bit ADC with 12dB attenuation
// Approximate range: 0-3300mV for 0-4095 raw values
voltage_mv = (adc_avg * 3300) / 4095;
}
// Apply voltage divider ratio to get actual battery voltage
voltage_mv = (int)(voltage_mv * BATTERY_VOLTAGE_DIVIDER_RATIO);
return voltage_mv;
}
int battery_get_percentage(void)
{
int voltage_mv = battery_read_voltage_mv();
if (voltage_mv < 0) {
return -1;
}
// Clamp to min/max range
if (voltage_mv >= BATTERY_VOLTAGE_MAX) {
return 100;
}
if (voltage_mv <= BATTERY_VOLTAGE_MIN) {
return 0;
}
// Linear interpolation between min and max
int percentage = ((voltage_mv - BATTERY_VOLTAGE_MIN) * 100) /
(BATTERY_VOLTAGE_MAX - BATTERY_VOLTAGE_MIN);
return percentage;
}
// Battery monitoring task
static void battery_monitoring_task(void *pvParameters)
{
ESP_LOGI(TAG, "Battery monitoring task started");
bool led_toggle = false;
int loop_count = 0;
int voltage_mv = 0;
bool is_charging = false;
while (1)
{
// Read voltage every 20 iterations (5000ms)
if (loop_count % 20 == 0) {
voltage_mv = battery_read_voltage_mv();
int percentage = battery_get_percentage();
if (voltage_mv >= 0 && percentage >= 0) {
// Update system state with battery info
system_setBatteryVoltage(voltage_mv);
system_setBatteryPercentage(percentage);
ESP_LOGI(TAG, "Battery: %d mV (%d%%)", voltage_mv, percentage);
} else {
ESP_LOGW(TAG, "Failed to read battery voltage");
}
// Read charge status and update system
is_charging = !gpio_get_level(PIN_NUM_CHARGE_STATUS);
system_setChargeStatus(is_charging);
}
// LED control based on charging status and voltage (runs every 250ms)
if (is_charging)
{
// Charging: Red until voltage > 4150mV, then Green
if (voltage_mv > 4150) {
gpio_set_level(PIN_LED_GREEN, 1); // Green ON
gpio_set_level(PIN_LED_RED, 0); // Red OFF
} else {
gpio_set_level(PIN_LED_GREEN, 0); // Green OFF
gpio_set_level(PIN_LED_RED, 1); // Red ON
}
gpio_set_level(PIN_NUM_LED_2, 1);
}
else
{
// Not charging: voltage-based indication
if (voltage_mv > 3900)
{
// Good voltage: Green steady
gpio_set_level(PIN_LED_GREEN, 1); // Green ON
gpio_set_level(PIN_LED_RED, 0); // Red OFF
}
else
if (voltage_mv > 3700)
{
// Warning voltage: Green flashing at 2Hz
gpio_set_level(PIN_LED_GREEN, led_toggle ? 0 : 1);
gpio_set_level(PIN_LED_RED, 0); // Red OFF
led_toggle = !led_toggle;
}
else
if (voltage_mv > 3600)
{
// Low voltage: Red steady
gpio_set_level(PIN_LED_GREEN, 0); // Green OFF
gpio_set_level(PIN_LED_RED, 1); // Red ON
}
else
if (voltage_mv > 3500)
{
// Warning voltage: Red flashing at 2Hz
gpio_set_level(PIN_LED_RED, led_toggle ? 0 : 1);
gpio_set_level(PIN_LED_GREEN, 0); // Green OFF
led_toggle = !led_toggle;
}
else
{
// power off
gpio_set_level(PIN_NUM_nON, 0);
}
gpio_set_level(PIN_NUM_LED_2, 1);
}
loop_count++;
vTaskDelay(pdMS_TO_TICKS(250));
}
}
void battery_start_monitoring_task(void)
{
xTaskCreate(battery_monitoring_task, "battery_task", 3072, NULL, 5, NULL);
ESP_LOGI(TAG, "Battery monitoring task created");
}

56
main/battery.h Normal file
View File

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

View File

@@ -35,7 +35,7 @@
/* 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)
@@ -107,7 +107,7 @@ 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 esp_err_t bt_try_connect_known_devices(void);
static void bt_debug_print_known_devices(void); static void bt_debug_print_known_devices(void);
@@ -327,33 +327,15 @@ static esp_err_t bt_add_discovered_device(esp_bd_addr_t bda, const char *name)
if (!bda || !name) { if (!bda || !name) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
// Check if device is already known // Don't save discovered devices to NVS - they're not paired yet!
if (system_isDeviceKnown(bda)) { // They will only be saved to NVS when successfully connected.
char bda_str[18]; // Just log that we discovered this device.
ESP_LOGD(BT_AV_TAG, "Device %s (%s) already known, skipping", char bda_str[18];
name, bda2str(bda, bda_str, sizeof(bda_str))); ESP_LOGI(BT_AV_TAG, "Discovered device: %s (%s)",
return ESP_OK; name, bda2str(bda, bda_str, sizeof(bda_str)));
}
return ESP_OK;
// Create paired_device_t structure for discovered device
paired_device_t device;
memcpy(device.bda, bda, ESP_BD_ADDR_LEN);
strncpy(device.name, name, DEVICE_NAME_MAX_LEN - 1);
device.name[DEVICE_NAME_MAX_LEN - 1] = '\0';
device.last_connected = 0; // Never connected, set to 0
// Save to NVS
esp_err_t ret = system_savePairedDevice(&device);
if (ret == ESP_OK) {
char bda_str[18];
ESP_LOGI(BT_AV_TAG, "Added discovered device to NVS: %s (%s)",
device.name, bda2str(device.bda, bda_str, sizeof(bda_str)));
} else {
ESP_LOGE(BT_AV_TAG, "Failed to save discovered device: %s", esp_err_to_name(ret));
}
return ret;
} }
static esp_err_t __attribute__((unused)) nvs_update_connection_timestamp(esp_bd_addr_t bda) static esp_err_t __attribute__((unused)) nvs_update_connection_timestamp(esp_bd_addr_t bda)
@@ -485,7 +467,7 @@ static esp_err_t bt_try_next_known_device(void)
/********************************* /*********************************
* 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;
@@ -538,13 +520,13 @@ static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
esp_bt_gap_dev_prop_t *p; esp_bt_gap_dev_prop_t *p;
/* handle the discovery results */ /* handle the discovery results */
for (int i = 0; i < param->disc_res.num_prop; i++) { for (int i = 0; i < param->disc_res.num_prop; i++) {
p = param->disc_res.prop + i; p = param->disc_res.prop + i;
switch (p->type) { switch (p->type) {
case ESP_BT_GAP_DEV_PROP_COD: case ESP_BT_GAP_DEV_PROP_COD:
cod = *(uint32_t *)(p->val); cod = *(uint32_t *)(p->val);
break; break;
case ESP_BT_GAP_DEV_PROP_RSSI: case ESP_BT_GAP_DEV_PROP_RSSI:
rssi = *(int8_t *)(p->val); rssi = *(int8_t *)(p->val);
@@ -559,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;
} }
@@ -575,20 +562,15 @@ static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
// Save discovered audio device to NVS (but don't connect to it) // Save discovered audio device to NVS (but don't connect to it)
bt_add_discovered_device(param->disc_res.bda, (char *)s_peer_bdname); bt_add_discovered_device(param->disc_res.bda, (char *)s_peer_bdname);
// Add to device list for GUI // Add to device list for GUI
add_device_to_list(param->disc_res.bda, (char *)s_peer_bdname, false, rssi); add_device_to_list(param->disc_res.bda, (char *)s_peer_bdname, false, rssi);
ESP_LOGI(BT_AV_TAG, "Found audio device, address %s, name %s (saved to NVS, not connecting)", ESP_LOGI(BT_AV_TAG, "Found audio device, address %s, name %s (added to list)",
bda_str, s_peer_bdname); bda_str, s_peer_bdname);
// Don't automatically connect to discovered devices - just save them to NVS // Don't automatically connect - just continue discovering more devices
// The old code would set s_a2d_state = APP_AV_STATE_DISCOVERED and connect // User will manually select a device from the menu to connect
// Now we just continue discovery to find more devices
s_a2d_state = APP_AV_STATE_DISCOVERED;
memcpy(s_peer_bda, param->disc_res.bda, ESP_BD_ADDR_LEN);
ESP_LOGI(BT_AV_TAG, "Cancel device discovery ...");
esp_bt_gap_cancel_discovery();
} }
} }
@@ -597,28 +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
filter_inquiry_scan_result(param); 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);
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...");
s_a2d_state = APP_AV_STATE_UNCONNECTED;
//esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
} }
} else if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STARTED) { } 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;
} }
@@ -717,15 +705,15 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
// Print list of saved devices from NVS // Print list of saved devices from NVS
bt_debug_print_known_devices(); bt_debug_print_known_devices();
// Try to connect to all known devices sequentially // Try to connect to known devices automatically (those we've connected to before)
esp_err_t connect_ret = bt_try_connect_all_known_devices(); esp_err_t connect_ret = bt_try_connect_known_devices();
if (connect_ret != ESP_OK) { if (connect_ret != ESP_OK) {
// No known devices found, start discovery to find new devices // No known devices found - stay in unconnected state
ESP_LOGI(BT_AV_TAG, "No known devices found, starting discovery..."); // Don't start discovery automatically - user must do it from menu
s_a2d_state = APP_AV_STATE_DISCOVERING; ESP_LOGI(BT_AV_TAG, "No previously connected devices found. User can discover devices from menu.");
esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0); s_a2d_state = APP_AV_STATE_UNCONNECTED;
} else { } else {
ESP_LOGI(BT_AV_TAG, "Attempting to connect to known devices..."); ESP_LOGI(BT_AV_TAG, "Attempting to connect to previously connected device...");
} }
/* create and start heart beat timer */ /* create and start heart beat timer */
@@ -810,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;
@@ -826,8 +816,13 @@ void generate_exp(uint8_t *buf, int len, float balance)
click_timer -= 1.0f; click_timer -= 1.0f;
samples[i * 2 + 0] = left; if (swap_lr) {
samples[i * 2 + 1] = right; samples[i * 2 + 0] = right;
samples[i * 2 + 1] = left;
} else {
samples[i * 2 + 0] = left;
samples[i * 2 + 1] = right;
}
} }
} }
@@ -1082,15 +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: {
// Try to connect to known devices, or start discovery if none available // Don't automatically try to reconnect - wait for user to select device
esp_err_t connect_ret = bt_try_connect_all_known_devices(); // from the menu
if (connect_ret != ESP_OK) {
// No known devices, start discovery
ESP_LOGI(BT_AV_TAG, "No known devices available, starting discovery...");
s_a2d_state = APP_AV_STATE_DISCOVERING;
esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
}
break; break;
} }
case ESP_A2D_REPORT_SNK_DELAY_VALUE_EVT: { case ESP_A2D_REPORT_SNK_DELAY_VALUE_EVT: {
@@ -1117,20 +1105,34 @@ 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;
// Update connection timestamp for this device // Check if device is already paired, if not, add it as paired
system_updateConnectionTimestamp(s_peer_bda); if (!system_isDeviceKnown(s_peer_bda)) {
} else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) { ESP_LOGI(BT_AV_TAG, "Device not in paired list, adding: %s", s_peer_bdname);
ESP_LOGI(BT_AV_TAG, "Connection failed, trying next device..."); paired_device_t new_device;
// Try next known device before giving up memcpy(new_device.bda, s_peer_bda, ESP_BD_ADDR_LEN);
esp_err_t next_ret = bt_try_next_known_device(); strncpy(new_device.name, (char*)s_peer_bdname, DEVICE_NAME_MAX_LEN - 1);
if (next_ret != ESP_OK) { new_device.name[DEVICE_NAME_MAX_LEN - 1] = '\0';
// No more devices to try, go to unconnected state new_device.last_connected = (uint32_t)(esp_timer_get_time() / 1000000);
//s_a2d_state = APP_AV_STATE_UNCONNECTED; system_savePairedDevice(&new_device);
ESP_LOGI(BT_AV_TAG, "No known devices available, starting discovery...");
s_a2d_state = APP_AV_STATE_DISCOVERING; // Update the device in the GUI list to show it as paired
esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0); 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) {
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;
} }
break; break;
} }
@@ -1144,13 +1146,10 @@ 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, trying next device..."); ESP_LOGI(BT_AV_TAG, "Connection timeout.");
// Try next known device before giving up // Return to unconnected state - don't retry automatically
esp_err_t next_ret = bt_try_next_known_device(); // User can manually reconnect from menu
if (next_ret != ESP_OK) { s_a2d_state = APP_AV_STATE_UNCONNECTED;
// No more devices to try, go to unconnected state
s_a2d_state = APP_AV_STATE_UNCONNECTED;
}
s_connecting_intv = 0; s_connecting_intv = 0;
} }
break; break;
@@ -1468,6 +1467,7 @@ static void bt_app_task_handler(void *arg)
if (notifiedBits & EM_EVENT_BT_REFRESH) { if (notifiedBits & EM_EVENT_BT_REFRESH) {
ESP_LOGI(BT_AV_TAG, "BT Refresh event received"); ESP_LOGI(BT_AV_TAG, "BT Refresh event received");
bt_clear_discovered_devices(); bt_clear_discovered_devices();
bt_start_discovery(); // Start new discovery after clearing
// Notify GUI that refresh is done - could add completion event if needed // Notify GUI that refresh is done - could add completion event if needed
} }
if (notifiedBits & EM_EVENT_BT_CONNECT) { if (notifiedBits & EM_EVENT_BT_CONNECT) {
@@ -1811,7 +1811,7 @@ bool bt_connect_device(int device_index) {
void bt_clear_discovered_devices(void) { void bt_clear_discovered_devices(void) {
int new_count = 0; int new_count = 0;
// Keep only paired devices // Keep only paired devices
for (int i = 0; i < s_device_list.count; i++) { for (int i = 0; i < s_device_list.count; i++) {
if (s_device_list.devices[i].is_paired) { if (s_device_list.devices[i].is_paired) {
@@ -1821,11 +1821,38 @@ void bt_clear_discovered_devices(void) {
new_count++; new_count++;
} }
} }
s_device_list.count = new_count; s_device_list.count = new_count;
ESP_LOGI(BT_AV_TAG, "Cleared discovered devices, kept %d paired devices", 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) { void bt_volume_up(void) {
if (!s_volume_control_available) { if (!s_volume_control_available) {
ESP_LOGW(BT_AV_TAG, "Volume control not available"); ESP_LOGW(BT_AV_TAG, "Volume control not available");
@@ -1848,8 +1875,11 @@ void bt_volume_down(void) {
} }
if (s_volume_level > 0) { if (s_volume_level > 0) {
s_volume_level -= 10; // Decrease by ~8% if (s_volume_level < 10) {
if (s_volume_level < 0) s_volume_level = 0; 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_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); esp_avrc_ct_send_set_absolute_volume_cmd(APP_RC_CT_TL_RN_VOLUME_CHANGE, s_volume_level);

View File

@@ -69,7 +69,7 @@ void bt_app_task_shut_down(void);
void bt_app_init(void); void bt_app_init(void);
/* Bluetooth device management for GUI */ /* Bluetooth device management for GUI */
#define MAX_BT_DEVICES 20 #define MAX_BT_DEVICES 8 // Reduced from 20 to save memory
#define MAX_BT_NAME_LEN 32 #define MAX_BT_NAME_LEN 32
typedef struct { typedef struct {
@@ -100,6 +100,12 @@ bool bt_connect_device(int device_index);
/* Clear discovered devices (keep paired devices) */ /* Clear discovered devices (keep paired devices) */
void bt_clear_discovered_devices(void); 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 */ /* Volume control functions */
void bt_volume_up(void); void bt_volume_up(void);
void bt_volume_down(void); void bt_volume_down(void);

View File

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

1217
main/gui.c

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,7 @@
#include "gpio.h" #include "gpio.h"
#include "keypad.h" #include "keypad.h"
#include "system.h" #include "system.h"
#include "battery.h"
@@ -104,26 +105,53 @@ static inline float LPF_Update(LowPassFilter *f, float input) {
* 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
// Configure output power signal // Configure output power signal
gpio_set_level(PIN_NUM_nON, 1); gpio_set_level(PIN_NUM_nON, 1);
io_conf.pin_bit_mask = (1ULL << PIN_NUM_nON); io_conf.pin_bit_mask = (1ULL << PIN_NUM_nON);
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;
@@ -131,7 +159,7 @@ static void init_gpio(void)
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_config(&io_conf); gpio_config(&io_conf);
#endif #endif
// Configure LCD Backlight GPIO // Configure LCD Backlight GPIO
@@ -275,21 +303,32 @@ void app_main(void)
print_heap_info("POST_SYSTEM"); 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"); print_heap_info("POST_IMU");
// Create IMU task // Create IMU task
TaskHandle_t h = xTaskCreate(imu_task, "imu_task", 2048, NULL, 5, NULL); TaskHandle_t h = NULL;
xTaskCreate(imu_task, "imu_task", 2048, NULL, 5, &h);
print_heap_info("POST_IMU_TASK"); print_heap_info("POST_IMU_TASK");
bt_app_init(); bt_app_init();
print_heap_info("POST_BLUETOOTH"); 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"); 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();
@@ -325,8 +364,10 @@ void app_main(void)
#else #else
while (1) while (1)
{ {
system_processNvsRequests(); system_processNvsRequests();
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(pdMS_TO_TICKS(10));
} }
#endif #endif
} }

View File

@@ -5,6 +5,7 @@
#include "esp_timer.h" #include "esp_timer.h"
#include <string.h> #include <string.h>
static SystemState_t _systemState; static SystemState_t _systemState;
static EventGroupHandle_t _systemEvent; static EventGroupHandle_t _systemEvent;
@@ -13,6 +14,9 @@ static EventManager_t _eventManager;
static QueueHandle_t _nvsRequestQueue; static QueueHandle_t _nvsRequestQueue;
static const char* NVS_NAMESPACE = "bt_devices"; static const char* NVS_NAMESPACE = "bt_devices";
static const char* NVS_KEY_COUNT = "count"; 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_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); static esp_err_t nvs_save_devices_internal(const paired_device_t *devices, size_t count);
@@ -22,13 +26,24 @@ void system_init(void)
_systemState.zeroAngle = 0.0f; _systemState.zeroAngle = 0.0f;
_systemState.primaryAxis = PRIMARY_AXIS; _systemState.primaryAxis = PRIMARY_AXIS;
_systemState.pairedDeviceCount = 0; _systemState.pairedDeviceCount = 0;
_systemState.isCharging = false;
_systemState.swapLR = false;
_systemState.volume = 50; // Default volume
_systemState.batteryVoltage_mv = 0;
_systemState.batteryPercentage = 0;
_systemEvent = xEventGroupCreate(); _systemEvent = xEventGroupCreate();
_eventManager.count = 0; _eventManager.count = 0;
_eventManager.mutex = xSemaphoreCreateMutex(); _eventManager.mutex = xSemaphoreCreateMutex();
system_initNvsService(); 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)
@@ -48,13 +63,89 @@ float system_getAngle(void)
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY); xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
angle = _systemState.imu.raw[_systemState.primaryAxis] - _systemState.zeroAngle; angle = _systemState.imu.raw[_systemState.primaryAxis] - _systemState.zeroAngle;
xSemaphoreGive(_eventManager.mutex); xSemaphoreGive(_eventManager.mutex);
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)
@@ -214,6 +305,146 @@ void system_requestVolumeDown(void) {
system_notifyAll(EM_EVENT_VOLUME_DOWN); 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) { void system_initNvsService(void) {
_nvsRequestQueue = xQueueCreate(10, sizeof(nvs_request_t)); _nvsRequestQueue = xQueueCreate(10, sizeof(nvs_request_t));
if (_nvsRequestQueue == NULL) { if (_nvsRequestQueue == NULL) {
@@ -349,16 +580,16 @@ void system_processNvsRequests(void) {
} }
break; break;
} }
default: default:
request.result = ESP_ERR_INVALID_ARG; request.result = ESP_ERR_INVALID_ARG;
break; break;
} }
xSemaphoreGive(_eventManager.mutex); xSemaphoreGive(_eventManager.mutex);
request.response_ready = true; // Send the result directly as the notification value (not a pointer)
if (request.requestor) { if (request.requestor) {
xTaskNotify(request.requestor, (uint32_t)&request, eSetValueWithOverwrite); xTaskNotify(request.requestor, (uint32_t)request.result, eSetValueWithOverwrite);
} }
} }
} }
@@ -396,8 +627,8 @@ esp_err_t system_savePairedDevice(const paired_device_t *device) {
if (xQueueSend(_nvsRequestQueue, &request, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) { if (xQueueSend(_nvsRequestQueue, &request, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) {
uint32_t notification; uint32_t notification;
if (xTaskNotifyWait(0, UINT32_MAX, &notification, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) { if (xTaskNotifyWait(0, UINT32_MAX, &notification, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) {
nvs_request_t *response = (nvs_request_t*)notification; // notification contains the result directly (not a pointer)
return response->result; return (esp_err_t)notification;
} }
} }
return ESP_ERR_TIMEOUT; return ESP_ERR_TIMEOUT;
@@ -425,8 +656,8 @@ esp_err_t system_removePairedDevice(esp_bd_addr_t bda) {
if (xQueueSend(_nvsRequestQueue, &request, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) { if (xQueueSend(_nvsRequestQueue, &request, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) {
uint32_t notification; uint32_t notification;
if (xTaskNotifyWait(0, UINT32_MAX, &notification, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) { if (xTaskNotifyWait(0, UINT32_MAX, &notification, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) {
nvs_request_t *response = (nvs_request_t*)notification; // notification contains the result directly (not a pointer)
return response->result; return (esp_err_t)notification;
} }
} }
return ESP_ERR_TIMEOUT; return ESP_ERR_TIMEOUT;
@@ -464,8 +695,8 @@ esp_err_t system_updateConnectionTimestamp(esp_bd_addr_t bda) {
if (xQueueSend(_nvsRequestQueue, &request, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) { if (xQueueSend(_nvsRequestQueue, &request, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) {
uint32_t notification; uint32_t notification;
if (xTaskNotifyWait(0, UINT32_MAX, &notification, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) { if (xTaskNotifyWait(0, UINT32_MAX, &notification, pdMS_TO_TICKS(NVS_TIMEOUT_MS)) == pdTRUE) {
nvs_request_t *response = (nvs_request_t*)notification; // notification contains the result directly (not a pointer)
return response->result; return (esp_err_t)notification;
} }
} }
return ESP_ERR_TIMEOUT; return ESP_ERR_TIMEOUT;
@@ -473,10 +704,26 @@ esp_err_t system_updateConnectionTimestamp(esp_bd_addr_t bda) {
const paired_device_t* system_getPairedDevices(size_t *count) { const paired_device_t* system_getPairedDevices(size_t *count) {
if (!count) return NULL; if (!count) return NULL;
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY); xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
*count = _systemState.pairedDeviceCount; *count = _systemState.pairedDeviceCount;
xSemaphoreGive(_eventManager.mutex); xSemaphoreGive(_eventManager.mutex);
return (const paired_device_t*)_systemState.pairedDevices; return (const paired_device_t*)_systemState.pairedDevices;
}
esp_err_t system_clearAllPairedDevices(void) {
// Directly clear in-memory state and save to NVS
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
_systemState.pairedDeviceCount = 0;
esp_err_t ret = nvs_save_devices_internal(_systemState.pairedDevices, 0);
xSemaphoreGive(_eventManager.mutex);
if (ret == ESP_OK) {
ESP_LOGI("system", "Cleared all paired devices from NVS");
} else {
ESP_LOGE("system", "Failed to clear paired devices: %s", esp_err_to_name(ret));
}
return ret;
} }

View File

@@ -47,11 +47,24 @@ typedef struct SystemState_s
// BT event data // BT event data
int btDeviceIndex; int btDeviceIndex;
// NVS cached data // NVS cached data
paired_device_t pairedDevices[MAX_PAIRED_DEVICES]; paired_device_t pairedDevices[MAX_PAIRED_DEVICES];
size_t pairedDeviceCount; 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;
@@ -67,6 +80,7 @@ typedef struct SystemState_s
#define EM_EVENT_BT_CONNECT (1UL<<3) #define EM_EVENT_BT_CONNECT (1UL<<3)
#define EM_EVENT_VOLUME_UP (1UL<<4) #define EM_EVENT_VOLUME_UP (1UL<<4)
#define EM_EVENT_VOLUME_DOWN (1UL<<5) #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 {
@@ -83,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);
@@ -104,6 +132,10 @@ int system_getBtDeviceIndex(void);
// Volume control functions // Volume control functions
void system_requestVolumeUp(void); void system_requestVolumeUp(void);
void system_requestVolumeDown(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 // NVS Service
typedef enum { typedef enum {
@@ -133,6 +165,7 @@ bool system_isDeviceKnown(esp_bd_addr_t bda);
esp_err_t system_getKnownDeviceCount(size_t *count); esp_err_t system_getKnownDeviceCount(size_t *count);
esp_err_t system_updateConnectionTimestamp(esp_bd_addr_t bda); esp_err_t system_updateConnectionTimestamp(esp_bd_addr_t bda);
const paired_device_t* system_getPairedDevices(size_t *count); const paired_device_t* system_getPairedDevices(size_t *count);
esp_err_t system_clearAllPairedDevices(void);
#define NVS_TIMEOUT_MS 5000 #define NVS_TIMEOUT_MS 5000

196
sdkconfig
View File

@@ -1,6 +1,6 @@
# #
# Automatically generated file. DO NOT EDIT. # Automatically generated file. DO NOT EDIT.
# Espressif IoT Development Framework (ESP-IDF) 5.3.1 Project Configuration # Espressif IoT Development Framework (ESP-IDF) 5.4.1 Project Configuration
# #
CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined" CONFIG_SOC_BROWNOUT_RESET_SUPPORTED="Not determined"
CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined" CONFIG_SOC_TWAI_BRP_DIV_SUPPORTED="Not determined"
@@ -91,12 +91,14 @@ CONFIG_SOC_GPIO_OUT_RANGE_MAX=33
CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0xEF0FEA CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0xEF0FEA
CONFIG_SOC_GPIO_CLOCKOUT_BY_IO_MUX=y CONFIG_SOC_GPIO_CLOCKOUT_BY_IO_MUX=y
CONFIG_SOC_GPIO_CLOCKOUT_CHANNEL_NUM=3 CONFIG_SOC_GPIO_CLOCKOUT_CHANNEL_NUM=3
CONFIG_SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP=y
CONFIG_SOC_I2C_NUM=2 CONFIG_SOC_I2C_NUM=2
CONFIG_SOC_HP_I2C_NUM=2 CONFIG_SOC_HP_I2C_NUM=2
CONFIG_SOC_I2C_FIFO_LEN=32 CONFIG_SOC_I2C_FIFO_LEN=32
CONFIG_SOC_I2C_CMD_REG_NUM=16 CONFIG_SOC_I2C_CMD_REG_NUM=16
CONFIG_SOC_I2C_SUPPORT_SLAVE=y CONFIG_SOC_I2C_SUPPORT_SLAVE=y
CONFIG_SOC_I2C_SUPPORT_APB=y CONFIG_SOC_I2C_SUPPORT_APB=y
CONFIG_SOC_I2C_SUPPORT_10BIT_ADDR=y
CONFIG_SOC_I2C_STOP_INDEPENDENT=y CONFIG_SOC_I2C_STOP_INDEPENDENT=y
CONFIG_SOC_I2S_NUM=2 CONFIG_SOC_I2S_NUM=2
CONFIG_SOC_I2S_HW_VERSION_1=y CONFIG_SOC_I2S_HW_VERSION_1=y
@@ -111,6 +113,7 @@ CONFIG_SOC_I2S_SUPPORTS_ADC_DAC=y
CONFIG_SOC_I2S_SUPPORTS_ADC=y CONFIG_SOC_I2S_SUPPORTS_ADC=y
CONFIG_SOC_I2S_SUPPORTS_DAC=y CONFIG_SOC_I2S_SUPPORTS_DAC=y
CONFIG_SOC_I2S_SUPPORTS_LCD_CAMERA=y CONFIG_SOC_I2S_SUPPORTS_LCD_CAMERA=y
CONFIG_SOC_I2S_MAX_DATA_WIDTH=24
CONFIG_SOC_I2S_TRANS_SIZE_ALIGN_WORD=y CONFIG_SOC_I2S_TRANS_SIZE_ALIGN_WORD=y
CONFIG_SOC_I2S_LCD_I80_VARIANT=y CONFIG_SOC_I2S_LCD_I80_VARIANT=y
CONFIG_SOC_LCD_I80_SUPPORTED=y CONFIG_SOC_LCD_I80_SUPPORTED=y
@@ -120,6 +123,7 @@ CONFIG_SOC_LEDC_HAS_TIMER_SPECIFIC_MUX=y
CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y CONFIG_SOC_LEDC_SUPPORT_APB_CLOCK=y
CONFIG_SOC_LEDC_SUPPORT_REF_TICK=y CONFIG_SOC_LEDC_SUPPORT_REF_TICK=y
CONFIG_SOC_LEDC_SUPPORT_HS_MODE=y CONFIG_SOC_LEDC_SUPPORT_HS_MODE=y
CONFIG_SOC_LEDC_TIMER_NUM=4
CONFIG_SOC_LEDC_CHANNEL_NUM=8 CONFIG_SOC_LEDC_CHANNEL_NUM=8
CONFIG_SOC_LEDC_TIMER_BIT_WIDTH=20 CONFIG_SOC_LEDC_TIMER_BIT_WIDTH=20
CONFIG_SOC_MCPWM_GROUPS=2 CONFIG_SOC_MCPWM_GROUPS=2
@@ -172,6 +176,8 @@ CONFIG_SOC_TIMER_GROUP_TIMERS_PER_GROUP=2
CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64 CONFIG_SOC_TIMER_GROUP_COUNTER_BIT_WIDTH=64
CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4 CONFIG_SOC_TIMER_GROUP_TOTAL_TIMERS=4
CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y CONFIG_SOC_TIMER_GROUP_SUPPORT_APB=y
CONFIG_SOC_LP_TIMER_BIT_WIDTH_LO=32
CONFIG_SOC_LP_TIMER_BIT_WIDTH_HI=16
CONFIG_SOC_TOUCH_SENSOR_VERSION=1 CONFIG_SOC_TOUCH_SENSOR_VERSION=1
CONFIG_SOC_TOUCH_SENSOR_NUM=10 CONFIG_SOC_TOUCH_SENSOR_NUM=10
CONFIG_SOC_TOUCH_SAMPLE_CFG_NUM=1 CONFIG_SOC_TOUCH_SAMPLE_CFG_NUM=1
@@ -214,6 +220,7 @@ CONFIG_SOC_PM_SUPPORT_RC_FAST_PD=y
CONFIG_SOC_PM_SUPPORT_VDDSDIO_PD=y CONFIG_SOC_PM_SUPPORT_VDDSDIO_PD=y
CONFIG_SOC_PM_SUPPORT_MODEM_PD=y CONFIG_SOC_PM_SUPPORT_MODEM_PD=y
CONFIG_SOC_CONFIGURABLE_VDDSDIO_SUPPORTED=y CONFIG_SOC_CONFIGURABLE_VDDSDIO_SUPPORTED=y
CONFIG_SOC_PM_MODEM_PD_BY_SW=y
CONFIG_SOC_CLK_APLL_SUPPORTED=y CONFIG_SOC_CLK_APLL_SUPPORTED=y
CONFIG_SOC_CLK_RC_FAST_D256_SUPPORTED=y CONFIG_SOC_CLK_RC_FAST_D256_SUPPORTED=y
CONFIG_SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256=y CONFIG_SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256=y
@@ -236,10 +243,11 @@ CONFIG_SOC_PHY_COMBO_MODULE=y
CONFIG_SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK=y CONFIG_SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK=y
CONFIG_IDF_CMAKE=y CONFIG_IDF_CMAKE=y
CONFIG_IDF_TOOLCHAIN="gcc" CONFIG_IDF_TOOLCHAIN="gcc"
CONFIG_IDF_TOOLCHAIN_GCC=y
CONFIG_IDF_TARGET_ARCH_XTENSA=y CONFIG_IDF_TARGET_ARCH_XTENSA=y
CONFIG_IDF_TARGET_ARCH="xtensa" CONFIG_IDF_TARGET_ARCH="xtensa"
CONFIG_IDF_TARGET="esp32" CONFIG_IDF_TARGET="esp32"
CONFIG_IDF_INIT_VERSION="5.3.1" CONFIG_IDF_INIT_VERSION="5.4.1"
CONFIG_IDF_TARGET_ESP32=y CONFIG_IDF_TARGET_ESP32=y
CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000
@@ -273,6 +281,10 @@ CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set
# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set
# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set # CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set
#
# Log
#
# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set # CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set # CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set # CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
@@ -281,6 +293,14 @@ CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set # CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set
CONFIG_BOOTLOADER_LOG_LEVEL=3 CONFIG_BOOTLOADER_LOG_LEVEL=3
#
# Format
#
# CONFIG_BOOTLOADER_LOG_COLORS is not set
CONFIG_BOOTLOADER_LOG_TIMESTAMP_SOURCE_CPU_TICKS=y
# end of Format
# end of Log
# #
# Serial Flash Configurations # Serial Flash Configurations
# #
@@ -336,6 +356,7 @@ CONFIG_ESP_ROM_HAS_SW_FLOAT=y
CONFIG_ESP_ROM_USB_OTG_NUM=-1 CONFIG_ESP_ROM_USB_OTG_NUM=-1
CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=-1 CONFIG_ESP_ROM_USB_SERIAL_DEVICE_NUM=-1
CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB=y CONFIG_ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB=y
CONFIG_ESP_ROM_HAS_OUTPUT_PUTC_FUNC=y
# #
# Serial flasher config # Serial flasher config
@@ -377,6 +398,7 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
# CONFIG_PARTITION_TABLE_SINGLE_APP is not set # CONFIG_PARTITION_TABLE_SINGLE_APP is not set
# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set # CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set
# CONFIG_PARTITION_TABLE_TWO_OTA is not set # CONFIG_PARTITION_TABLE_TWO_OTA is not set
# CONFIG_PARTITION_TABLE_TWO_OTA_LARGE is not set
CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
@@ -400,6 +422,7 @@ CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
# CONFIG_COMPILER_ASSERT_NDEBUG_EVALUATE is not set
CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2
# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set # CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set
@@ -410,14 +433,18 @@ CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set # CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set
# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set # CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set
# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set # CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set
# CONFIG_COMPILER_NO_MERGE_CONSTANTS is not set
# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set # CONFIG_COMPILER_WARN_WRITE_STRINGS is not set
# CONFIG_COMPILER_DISABLE_DEFAULT_ERRORS is not set
# CONFIG_COMPILER_DISABLE_GCC12_WARNINGS is not set # CONFIG_COMPILER_DISABLE_GCC12_WARNINGS is not set
# CONFIG_COMPILER_DISABLE_GCC13_WARNINGS is not set # CONFIG_COMPILER_DISABLE_GCC13_WARNINGS is not set
# CONFIG_COMPILER_DISABLE_GCC14_WARNINGS is not set
# CONFIG_COMPILER_DUMP_RTL_FILES is not set # CONFIG_COMPILER_DUMP_RTL_FILES is not set
CONFIG_COMPILER_RT_LIB_GCCLIB=y CONFIG_COMPILER_RT_LIB_GCCLIB=y
CONFIG_COMPILER_RT_LIB_NAME="gcc" CONFIG_COMPILER_RT_LIB_NAME="gcc"
# CONFIG_COMPILER_ORPHAN_SECTIONS_WARNING is not set # CONFIG_COMPILER_ORPHAN_SECTIONS_WARNING is not set
CONFIG_COMPILER_ORPHAN_SECTIONS_PLACE=y CONFIG_COMPILER_ORPHAN_SECTIONS_PLACE=y
# CONFIG_COMPILER_STATIC_ANALYZER is not set
# end of Compiler options # end of Compiler options
# #
@@ -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
@@ -2247,7 +2369,7 @@ CONFIG_LV_ATTRIBUTE_MEM_ALIGN_SIZE=1
# Enable built-in fonts # Enable built-in fonts
# #
CONFIG_LV_FONT_MONTSERRAT_8=y 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=y 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
@@ -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

3008
sdkconfig.old Normal file

File diff suppressed because it is too large Load Diff