Compare commits
2 Commits
4feb4c0a98
...
4697b369db
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4697b369db | ||
|
|
dc2885e02e |
42
.vscode/settings.json
vendored
42
.vscode/settings.json
vendored
@@ -1,3 +1,41 @@
|
|||||||
{
|
{
|
||||||
"idf.pythonInstallPath": "/usr/bin/python"
|
"C_Cpp.intelliSenseEngine": "default",
|
||||||
}
|
"idf.espIdfPathWin": "C:\\Users\\brent.RPX\\esp\\v5.3.1\\esp-idf",
|
||||||
|
"idf.openOcdConfigs": [
|
||||||
|
"board/esp32-wrover-kit-3.3v.cfg"
|
||||||
|
],
|
||||||
|
"idf.portWin": "COM4",
|
||||||
|
"idf.toolsPathWin": "C:\\Users\\brent.RPX\\.espressif\\tools",
|
||||||
|
"idf.flashType": "UART",
|
||||||
|
"files.associations": {
|
||||||
|
"esp_system.h": "c",
|
||||||
|
"task.h": "c",
|
||||||
|
"bt_app_core.h": "c",
|
||||||
|
"math.h": "c",
|
||||||
|
"esp_log.h": "c",
|
||||||
|
"freertos.h": "c",
|
||||||
|
"queue.h": "c",
|
||||||
|
"unistd.h": "c",
|
||||||
|
"inttypes.h": "c",
|
||||||
|
"esp_idf_version.h": "c",
|
||||||
|
"timers.h": "c",
|
||||||
|
"lvgl.h": "c",
|
||||||
|
"esp_timer.h": "c",
|
||||||
|
"esp_bt_device.h": "c",
|
||||||
|
"esp_lvgl_port.h": "c",
|
||||||
|
"lv_global.h": "c",
|
||||||
|
"stdio.h": "c",
|
||||||
|
"compare": "c",
|
||||||
|
"cstdint": "c",
|
||||||
|
"spi_master.h": "c",
|
||||||
|
"bitset": "c",
|
||||||
|
"format": "c",
|
||||||
|
"system.h": "c",
|
||||||
|
"esp_lcd_panel_ops.h": "c",
|
||||||
|
"semphr.h": "c",
|
||||||
|
"lv_spinbox.h": "c",
|
||||||
|
"lv_slider.h": "c",
|
||||||
|
"lv_menu.h": "c"
|
||||||
|
},
|
||||||
|
"git.ignoreLimitWarning": true
|
||||||
|
}
|
||||||
|
|||||||
394
README.md
394
README.md
@@ -1,90 +1,304 @@
|
|||||||
| Supported Targets | ESP32 |
|
<<<<<<< HEAD
|
||||||
| ----------------- | ----- |
|
## 🐳 ESP-IDF Dockerized Development Environment (Windows)
|
||||||
|
|
||||||
A2DP-SOURCE EXAMPLE
|
This project includes a fully containerized [ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/index.html) development environment using **Docker** and **Visual Studio Code**.
|
||||||
========================
|
|
||||||
|
Follow these instructions to set up, build, and flash the firmware inside a VS Code **Dev Container** on **Windows**.
|
||||||
Example of A2DP audio source role
|
|
||||||
|
---
|
||||||
This is the example of using Advanced Audio Distribution Profile (A2DP) APIs to transmit audio stream. Application can take advantage of this example to implement portable audio players or microphones to transmit audio stream to A2DP sink devices.
|
|
||||||
|
### ✅ Prerequisites
|
||||||
## How to use this example
|
Ensure the following are installed on your system:
|
||||||
|
|
||||||
### Hardware Required
|
1. [**Docker Desktop for Windows**](https://www.docker.com/products/docker-desktop)
|
||||||
|
|
||||||
This example is able to run on any commonly available ESP32 development board, and is supposed to connect to [A2DP sink example](../a2dp_sink) in ESP-IDF.
|
* Enable **WSL 2 backend** during installation.
|
||||||
|
2. [**Visual Studio Code**](https://code.visualstudio.com/)
|
||||||
### Configure the project
|
3. [**Dev Containers Extension**](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
|
||||||
|
|
||||||
```
|
* In VS Code: `Extensions → Search "Dev Containers" → Install`
|
||||||
idf.py menuconfig
|
4. [**Espressif IDF Extension** for VS Code](https://marketplace.visualstudio.com/items?itemName=espressif.esp-idf-extension)
|
||||||
```
|
|
||||||
|
* In VS Code: `Extensions → Search "ESP-IDF" → Install`
|
||||||
* Enable Classic Bluetooth and A2DP under Component config --> Bluetooth --> Bluedroid Enable
|
|
||||||
|
> 💡 **Optional (recommended):** Install [WSL 2 with Ubuntu](https://learn.microsoft.com/en-us/windows/wsl/install) for improved Linux compatibility inside Docker.
|
||||||
### Build and Flash
|
|
||||||
|
---
|
||||||
Build the project and flash it to the board, then run monitor tool to view serial output.
|
|
||||||
|
### 🚀 Getting Started
|
||||||
```
|
|
||||||
idf.py -p PORT flash monitor
|
#### 1. Clone this repository
|
||||||
```
|
|
||||||
|
```bash
|
||||||
(Replace PORT with the name of the serial port to use.)
|
git clone https://git.sparksoftdesign.com/firstpass/soundshot.git
|
||||||
|
cd soundshot
|
||||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
```
|
||||||
|
---
|
||||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
You can also clone with TortoiseGit or VS Code directly.
|
||||||
|
#### 2. Open in Visual Studio Code
|
||||||
## Example Output
|
|
||||||
|
From the project root:
|
||||||
For the first step, this example performs device discovery to search for a target device (A2DP sink) whose device name is "ESP_SPEAKER" and whose "Rendering" bit of its Service Class field is set in its Class of Device (COD). If a candidate target is found, the local device will initiate connection with it.
|
|
||||||
|
```bash
|
||||||
After connection with A2DP sink is established, the example performs the following running loop 1-2-3-4-1:
|
code .
|
||||||
1. audio transmission starts and lasts for a while
|
```
|
||||||
2. audio transmission stops
|
|
||||||
3. disconnect with target device
|
> Ensure you're opening the folder that contains `.devcontainer/`.
|
||||||
4. reconnect to target device
|
|
||||||
|
---
|
||||||
The example implements an event loop triggered by a periodic "heart beat" timer and events from Bluetooth protocol stack callback functions.
|
|
||||||
|
#### 3. Reopen in Dev Container
|
||||||
After the local device discovers the target device and initiates connection, there will be logging message like this:
|
|
||||||
|
In VS Code:
|
||||||
```
|
|
||||||
I (4090) BT_AV: Found a target device, address xx:xx:xx:xx:xx:xx, name ESP_SPEAKER
|
* Press `F1` or `Ctrl+Shift+P`
|
||||||
I (4090) BT_AV: Cancel device discovery ...
|
* Run: **Dev Containers: Reopen in Container**
|
||||||
I (4100) BT_AV: Device discovery stopped.
|
|
||||||
I (4100) BT_AV: a2dp connecting to peer: ESP_SPEAKER
|
VS Code will:
|
||||||
```
|
|
||||||
|
* Build the Docker image (based on the provided `Dockerfile`)
|
||||||
If connection is set up successfully, there will be such message:
|
* Set up the ESP-IDF environment
|
||||||
|
* Install extensions automatically
|
||||||
```
|
|
||||||
I (5100) BT_AV: a2dp connected
|
---
|
||||||
```
|
|
||||||
|
#### 4. Verify Environment
|
||||||
Starting of audio transmission has the following notification message:
|
|
||||||
|
Once setup is complete:
|
||||||
```
|
|
||||||
I (10880) BT_AV: a2dp media ready checking ...
|
* A terminal should launch inside the container
|
||||||
...
|
* Run:
|
||||||
I (10880) BT_AV: a2dp media ready, starting ...
|
|
||||||
...
|
```bash
|
||||||
I (11400) BT_AV: a2dp media start successfully.
|
idf.py --version
|
||||||
```
|
```
|
||||||
|
|
||||||
Stop of audio transmission, and disconnection with remote device generate the following notification message:
|
to confirm ESP-IDF is active and available.
|
||||||
|
|
||||||
```
|
---
|
||||||
I (110880) BT_AV: a2dp media stopping...
|
|
||||||
...
|
#### 5. Build the Firmware
|
||||||
I (110920) BT_AV: a2dp media stopped successfully, disconnecting...
|
|
||||||
...
|
Inside the container’s terminal:
|
||||||
I (111040) BT_AV: a2dp disconnected
|
|
||||||
```
|
```bash
|
||||||
|
idf.py build
|
||||||
## Troubleshooting
|
```
|
||||||
* For current stage, the supported audio codec in ESP32 A2DP is SBC. SBC audio stream is encoded from PCM data normally formatted as 44.1kHz sampling rate, two-channel 16-bit sample data.
|
|
||||||
* The raw PCM media stream in the example is generated by a sequence of random number, so the sound played on the sink side will be piercing noise.
|
You should see standard ESP-IDF build output and a `.bin` firmware file in the `build/` directory.
|
||||||
* As a usage limitation, ESP32 A2DP source can support at most one connection with remote A2DP sink devices. Also, A2DP source cannot be used together with A2DP sink at the same time, but can be used with other profiles such as SPP and HFP.
|
|
||||||
* Usually, the `ACL_CONN_NUM` is set to `2` but not `1` as one is used for a2dp connection and the other is used for avrcp connection.
|
---
|
||||||
|
|
||||||
|
## 🛠️ ESP32 Programming Setup & Workflow Guide
|
||||||
|
|
||||||
|
This project provides a fully portable development and flashing toolchain for ESP32, using Python scripts and configuration-driven workflows.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 📦 1. Environment Setup
|
||||||
|
|
||||||
|
> Run once after cloning the repo (Windows only)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
setup-env.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
This:
|
||||||
|
|
||||||
|
* Creates a `.venv` virtual environment
|
||||||
|
* Installs required Python packages (`esptool`, `pyserial`, etc.)
|
||||||
|
* Prepares the tooling for flashing and monitoring
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ⚙️ 2. Configure `settings.json`
|
||||||
|
|
||||||
|
Customize `settings.json` in the project root:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"project_name": "soundshot",
|
||||||
|
"chip": "esp32",
|
||||||
|
"port": "COM3",
|
||||||
|
"baud": 460800,
|
||||||
|
"flash_mode": "dio",
|
||||||
|
"flash_freq": "48m",
|
||||||
|
"flash_size": "2MB",
|
||||||
|
"before": "default-reset",
|
||||||
|
"after": "hard-reset"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This controls:
|
||||||
|
|
||||||
|
* Flashing chip type and parameters
|
||||||
|
* Serial monitor settings
|
||||||
|
* Build artifact naming
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🚀 3. Flashing the Firmware
|
||||||
|
|
||||||
|
After building your firmware (e.g. via VS Code + Dev Container):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
build/
|
||||||
|
├── bootloader/bootloader.bin
|
||||||
|
├── soundshot.bin ← ← ← (project_name)
|
||||||
|
├── partition_table/partition-table.bin
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the flash tool:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flash.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
This:
|
||||||
|
|
||||||
|
* Loads `settings.json`
|
||||||
|
* Verifies all required binaries
|
||||||
|
* Calls `esptool.py` with all correct arguments and offsets
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🛰 4. Monitoring Serial Output
|
||||||
|
|
||||||
|
To view device output:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
monitor.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
Features:
|
||||||
|
|
||||||
|
* Uses `pyserial`
|
||||||
|
* Displays real-time output from the ESP32
|
||||||
|
* Preserves color formatting (if enabled in firmware)
|
||||||
|
* Cleanly exits with `Ctrl+C` (no "Terminate batch job" prompts)
|
||||||
|
|
||||||
|
> Tip: Run `idf.py menuconfig` and enable
|
||||||
|
> `Component config → Log output → Enable color log output`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ✅ Workflow Summary
|
||||||
|
|
||||||
|
| Action | Tool | Command |
|
||||||
|
| ------------------ | ------------------- | ----------------- |
|
||||||
|
| Install tooling | `setup-env.bat` | `setup-env.bat` |
|
||||||
|
| Flash device | `flash.py` script | `flash.bat` |
|
||||||
|
| Monitor logs | `monitor.py` script | `monitor.bat` |
|
||||||
|
| Configure behavior | `settings.json` | *(edit manually)* |
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🧰 Notes
|
||||||
|
|
||||||
|
* The ESP-IDF version is pinned in the Dockerfile (e.g., `espressif/idf:v5.2.1`)
|
||||||
|
* The container automatically runs `source $IDF_PATH/export.sh` to prepare the environment.
|
||||||
|
* VS Code extensions (`.devcontainer.json`) include:
|
||||||
|
|
||||||
|
* `ms-vscode.cpptools`
|
||||||
|
* `ms-vscode.cmake-tools`
|
||||||
|
* `espressif.esp-idf-extension`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🛠 Troubleshooting
|
||||||
|
|
||||||
|
* If `idf.py` is not found, make sure the container terminal sources `export.sh`
|
||||||
|
|
||||||
|
=======
|
||||||
|
| Supported Targets | ESP32 |
|
||||||
|
| ----------------- | ----- |
|
||||||
|
|
||||||
|
A2DP-SOURCE EXAMPLE
|
||||||
|
========================
|
||||||
|
|
||||||
|
Example of A2DP audio source role
|
||||||
|
|
||||||
|
This is the example of using Advanced Audio Distribution Profile (A2DP) APIs to transmit audio stream. Application can take advantage of this example to implement portable audio players or microphones to transmit audio stream to A2DP sink devices.
|
||||||
|
|
||||||
|
## How to use this example
|
||||||
|
|
||||||
|
### Hardware Required
|
||||||
|
|
||||||
|
This example is able to run on any commonly available ESP32 development board, and is supposed to connect to [A2DP sink example](../a2dp_sink) in ESP-IDF.
|
||||||
|
|
||||||
|
### Configure the project
|
||||||
|
|
||||||
|
```
|
||||||
|
idf.py menuconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
* Enable Classic Bluetooth and A2DP under Component config --> Bluetooth --> Bluedroid Enable
|
||||||
|
|
||||||
|
### Build and Flash
|
||||||
|
|
||||||
|
Build the project and flash it to the board, then run monitor tool to view serial output.
|
||||||
|
|
||||||
|
```
|
||||||
|
idf.py -p PORT flash monitor
|
||||||
|
```
|
||||||
|
|
||||||
|
(Replace PORT with the name of the serial port to use.)
|
||||||
|
|
||||||
|
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||||
|
|
||||||
|
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||||
|
|
||||||
|
## Example Output
|
||||||
|
|
||||||
|
For the first step, this example performs device discovery to search for a target device (A2DP sink) whose device name is "ESP_SPEAKER" and whose "Rendering" bit of its Service Class field is set in its Class of Device (COD). If a candidate target is found, the local device will initiate connection with it.
|
||||||
|
|
||||||
|
After connection with A2DP sink is established, the example performs the following running loop 1-2-3-4-1:
|
||||||
|
1. audio transmission starts and lasts for a while
|
||||||
|
2. audio transmission stops
|
||||||
|
3. disconnect with target device
|
||||||
|
4. reconnect to target device
|
||||||
|
|
||||||
|
The example implements an event loop triggered by a periodic "heart beat" timer and events from Bluetooth protocol stack callback functions.
|
||||||
|
|
||||||
|
After the local device discovers the target device and initiates connection, there will be logging message like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
I (4090) BT_AV: Found a target device, address xx:xx:xx:xx:xx:xx, name ESP_SPEAKER
|
||||||
|
I (4090) BT_AV: Cancel device discovery ...
|
||||||
|
I (4100) BT_AV: Device discovery stopped.
|
||||||
|
I (4100) BT_AV: a2dp connecting to peer: ESP_SPEAKER
|
||||||
|
```
|
||||||
|
|
||||||
|
If connection is set up successfully, there will be such message:
|
||||||
|
|
||||||
|
```
|
||||||
|
I (5100) BT_AV: a2dp connected
|
||||||
|
```
|
||||||
|
|
||||||
|
Starting of audio transmission has the following notification message:
|
||||||
|
|
||||||
|
```
|
||||||
|
I (10880) BT_AV: a2dp media ready checking ...
|
||||||
|
...
|
||||||
|
I (10880) BT_AV: a2dp media ready, starting ...
|
||||||
|
...
|
||||||
|
I (11400) BT_AV: a2dp media start successfully.
|
||||||
|
```
|
||||||
|
|
||||||
|
Stop of audio transmission, and disconnection with remote device generate the following notification message:
|
||||||
|
|
||||||
|
```
|
||||||
|
I (110880) BT_AV: a2dp media stopping...
|
||||||
|
...
|
||||||
|
I (110920) BT_AV: a2dp media stopped successfully, disconnecting...
|
||||||
|
...
|
||||||
|
I (111040) BT_AV: a2dp disconnected
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
* For current stage, the supported audio codec in ESP32 A2DP is SBC. SBC audio stream is encoded from PCM data normally formatted as 44.1kHz sampling rate, two-channel 16-bit sample data.
|
||||||
|
* The raw PCM media stream in the example is generated by a sequence of random number, so the sound played on the sink side will be piercing noise.
|
||||||
|
* As a usage limitation, ESP32 A2DP source can support at most one connection with remote A2DP sink devices. Also, A2DP source cannot be used together with A2DP sink at the same time, but can be used with other profiles such as SPP and HFP.
|
||||||
|
* Usually, the `ACL_CONN_NUM` is set to `2` but not `1` as one is used for a2dp connection and the other is used for avrcp connection.
|
||||||
|
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||||
|
|||||||
22
flash.bat
Normal file
22
flash.bat
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
@echo off
|
||||||
|
REM =============================================
|
||||||
|
REM Flash ESP32 using Python script + settings.json
|
||||||
|
REM =============================================
|
||||||
|
|
||||||
|
REM Check for venv
|
||||||
|
IF NOT EXIST .venv\Scripts\python.exe (
|
||||||
|
echo [ERROR] Python virtual environment not found at .venv\
|
||||||
|
echo Run setup-env.bat first.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Activate venv and run flash.py
|
||||||
|
call .venv\Scripts\activate.bat
|
||||||
|
|
||||||
|
echo [INFO] Flashing firmware using flash.py and settings.json...
|
||||||
|
python flash_tool\flash.py
|
||||||
|
|
||||||
|
REM Pause to view output
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
60
flash_tool/flash.py
Normal file
60
flash_tool/flash.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def main():
|
||||||
|
root = Path(__file__).resolve().parent.parent
|
||||||
|
config_file = root / "settings.json"
|
||||||
|
|
||||||
|
if not config_file.exists():
|
||||||
|
print(f"[ERROR] settings.json not found at {config_file}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open(config_file) as f:
|
||||||
|
cfg = json.load(f)
|
||||||
|
|
||||||
|
project = cfg["project_name"]
|
||||||
|
chip = cfg.get("chip", "esp32")
|
||||||
|
port = cfg.get("port", "COM3")
|
||||||
|
baud = cfg.get("flash_baud", 460800)
|
||||||
|
flash_mode = cfg.get("flash_mode", "dio")
|
||||||
|
flash_freq = cfg.get("flash_freq", "40m")
|
||||||
|
flash_size = cfg.get("flash_size", "4MB")
|
||||||
|
before = cfg.get("before", "default_reset")
|
||||||
|
after = cfg.get("after", "hard_reset")
|
||||||
|
|
||||||
|
# Define binaries and offsets
|
||||||
|
bootloader = root / "build" / "bootloader" / "bootloader.bin"
|
||||||
|
firmware = root / "build" / f"{project}.bin"
|
||||||
|
partition = root / "build" / "partition_table" / "partition-table.bin"
|
||||||
|
|
||||||
|
# Verify binaries exist
|
||||||
|
for f in [bootloader, firmware, partition]:
|
||||||
|
if not f.exists():
|
||||||
|
print(f"[ERROR] File not found: {f}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Build esptool command
|
||||||
|
cmd = [
|
||||||
|
sys.executable, "-m", "esptool",
|
||||||
|
"--chip", chip,
|
||||||
|
"--port", port,
|
||||||
|
"--baud", str(baud),
|
||||||
|
"--before", before,
|
||||||
|
"--after", after,
|
||||||
|
"write-flash", # ✅ hyphenated command
|
||||||
|
"--flash-mode", flash_mode, # ✅ hyphenated flags
|
||||||
|
"--flash-freq", flash_freq,
|
||||||
|
"--flash-size", flash_size,
|
||||||
|
"0x0", str(bootloader),
|
||||||
|
"0x10000", str(firmware),
|
||||||
|
"0x8000", str(partition)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
print(f"[Flashing] Running: {' '.join(cmd)}")
|
||||||
|
subprocess.run(cmd, check=True)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
45
flash_tool/monitor.py
Normal file
45
flash_tool/monitor.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import json
|
||||||
|
import serial
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
# import colorama
|
||||||
|
# colorama.just_fix_windows_console()
|
||||||
|
|
||||||
|
print("\x1b[0;32mThis should be green\x1b[0m")
|
||||||
|
print("\x1b[0;31mThis should be red\x1b[0m")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Load config
|
||||||
|
root = Path(__file__).resolve().parent.parent
|
||||||
|
config_file = root / "settings.json"
|
||||||
|
if not config_file.exists():
|
||||||
|
print(f"Error: settings.json not found at {config_file}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open(config_file) as f:
|
||||||
|
cfg = json.load(f)
|
||||||
|
|
||||||
|
port = cfg.get("port", "COM3")
|
||||||
|
baud = cfg.get("monitor_baud", 115200)
|
||||||
|
|
||||||
|
print(f"[Serial Monitor] Connecting to {port} at {baud} baud...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with serial.Serial(port, baud, timeout=0.5) as ser:
|
||||||
|
print("[Serial Monitor] Press Ctrl+C to exit.\n")
|
||||||
|
while True:
|
||||||
|
if ser.in_waiting:
|
||||||
|
line = ser.readline().decode(errors="replace")
|
||||||
|
if line:
|
||||||
|
print(line, end="")
|
||||||
|
|
||||||
|
time.sleep(0.01)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n[Serial Monitor] Disconnected.")
|
||||||
|
except serial.SerialException as e:
|
||||||
|
print(f"[Error] Could not open serial port {port}: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
14
flashmon.bat
Normal file
14
flashmon.bat
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
@echo off
|
||||||
|
REM =============================================
|
||||||
|
REM ESP32 Serial Monitor using settings.json
|
||||||
|
REM =============================================
|
||||||
|
|
||||||
|
IF NOT EXIST .venv\Scripts\python.exe (
|
||||||
|
echo [ERROR] .venv not found. Run setup-env.bat first.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
call .venv\Scripts\activate.bat
|
||||||
|
python flash_tool\flash.py
|
||||||
|
python flash_tool\monitor.py
|
||||||
@@ -1,12 +1,28 @@
|
|||||||
idf_component_register(SRCS "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
|
<<<<<<< HEAD
|
||||||
|
idf_component_register(SRCS "system.c.LOCAL.c" "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
|
||||||
"gui.c"
|
|
||||||
"lsm6dsv.c"
|
"gui.c"
|
||||||
INCLUDE_DIRS "."
|
"lsm6dsv.c"
|
||||||
REQUIRES "driver"
|
INCLUDE_DIRS "."
|
||||||
"esp_lcd"
|
REQUIRES "driver"
|
||||||
"lvgl"
|
"esp_lcd"
|
||||||
"esp_lvgl_port"
|
"lvgl"
|
||||||
"esp_timer"
|
"esp_lvgl_port"
|
||||||
"nvs_flash"
|
"esp_timer"
|
||||||
"bt")
|
"nvs_flash"
|
||||||
|
"bt")
|
||||||
|
=======
|
||||||
|
idf_component_register(SRCS "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
|
||||||
|
|
||||||
|
"gui.c"
|
||||||
|
"lsm6dsv.c"
|
||||||
|
INCLUDE_DIRS "."
|
||||||
|
REQUIRES "driver"
|
||||||
|
"esp_lcd"
|
||||||
|
"lvgl"
|
||||||
|
"esp_lvgl_port"
|
||||||
|
"esp_timer"
|
||||||
|
"nvs_flash"
|
||||||
|
"bt")
|
||||||
|
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||||
|
|
||||||
|
|||||||
3483
main/bt_app.c
3483
main/bt_app.c
File diff suppressed because it is too large
Load Diff
87
main/gpio.h
87
main/gpio.h
@@ -1,29 +1,60 @@
|
|||||||
#ifndef GPIO_H
|
<<<<<<< HEAD
|
||||||
#define GPIO_H
|
#ifndef GPIO_H
|
||||||
|
#define GPIO_H
|
||||||
// Define keypad buttons
|
|
||||||
#define PIN_NUM_BUTTON_0 36
|
// Define keypad buttons
|
||||||
#define PIN_NUM_BUTTON_1 39
|
#define PIN_NUM_BUTTON_0 36
|
||||||
#define PIN_NUM_LED_1 32
|
#define PIN_NUM_BUTTON_1 39
|
||||||
#define PIN_NUM_LED_2 33
|
#define PIN_NUM_LED_1 32
|
||||||
#define PIN_NUM_nON 26
|
#define PIN_NUM_LED_2 33
|
||||||
|
#define PIN_NUM_nON 26
|
||||||
|
|
||||||
// Define GPIO pins
|
|
||||||
#ifdef DEVKIT
|
// Define GPIO pins
|
||||||
#define PIN_NUM_MOSI 23 // SDA pin for LCD
|
#ifdef DEVKIT
|
||||||
#define PIN_NUM_CLK 18 // SCL pin for LCD
|
#define PIN_NUM_MOSI 23 // SDA pin for LCD
|
||||||
#define PIN_NUM_CS 2 // CS pin
|
#define PIN_NUM_CLK 18 // SCL pin for LCD
|
||||||
#define PIN_NUM_DC 12 // Data/Command pin (RS)
|
#define PIN_NUM_CS 2 // CS pin
|
||||||
#define PIN_NUM_RST 13 // Reset pin
|
#define PIN_NUM_DC 12 // Data/Command pin (RS)
|
||||||
#define PIN_NUM_BK_LIGHT -1 // Backlight control pin, -1 if not used
|
#define PIN_NUM_RST 13 // Reset pin
|
||||||
#else
|
#define PIN_NUM_BK_LIGHT -1 // Backlight control pin, -1 if not used
|
||||||
#define PIN_NUM_MOSI 23 // SDA pin for LCD
|
#else
|
||||||
#define PIN_NUM_CLK 18 // SCL pin for LCD
|
#define PIN_NUM_MOSI 23 // SDA pin for LCD
|
||||||
#define PIN_NUM_CS 12 // CS pin
|
#define PIN_NUM_CLK 18 // SCL pin for LCD
|
||||||
#define PIN_NUM_DC 15 // Data/Command pin (RS)
|
#define PIN_NUM_CS 12 // CS pin
|
||||||
#define PIN_NUM_RST 13 // Reset pin
|
#define PIN_NUM_DC 15 // Data/Command pin (RS)
|
||||||
#define PIN_NUM_BK_LIGHT 5 // Backlight control pin, -1 if not used
|
#define PIN_NUM_RST 13 // Reset pin
|
||||||
#endif
|
#define PIN_NUM_BK_LIGHT 5 // Backlight control pin, -1 if not used
|
||||||
|
#endif
|
||||||
|
|
||||||
|
=======
|
||||||
|
#ifndef GPIO_H
|
||||||
|
#define GPIO_H
|
||||||
|
|
||||||
|
// Define keypad buttons
|
||||||
|
#define PIN_NUM_BUTTON_0 36
|
||||||
|
#define PIN_NUM_BUTTON_1 39
|
||||||
|
#define PIN_NUM_LED_1 32
|
||||||
|
#define PIN_NUM_LED_2 33
|
||||||
|
#define PIN_NUM_nON 26
|
||||||
|
|
||||||
|
|
||||||
|
// Define GPIO pins
|
||||||
|
#ifdef DEVKIT
|
||||||
|
#define PIN_NUM_MOSI 23 // SDA pin for LCD
|
||||||
|
#define PIN_NUM_CLK 18 // SCL pin for LCD
|
||||||
|
#define PIN_NUM_CS 2 // CS pin
|
||||||
|
#define PIN_NUM_DC 12 // Data/Command pin (RS)
|
||||||
|
#define PIN_NUM_RST 13 // Reset pin
|
||||||
|
#define PIN_NUM_BK_LIGHT -1 // Backlight control pin, -1 if not used
|
||||||
|
#else
|
||||||
|
#define PIN_NUM_MOSI 23 // SDA pin for LCD
|
||||||
|
#define PIN_NUM_CLK 18 // SCL pin for LCD
|
||||||
|
#define PIN_NUM_CS 12 // CS pin
|
||||||
|
#define PIN_NUM_DC 15 // Data/Command pin (RS)
|
||||||
|
#define PIN_NUM_RST 13 // Reset pin
|
||||||
|
#define PIN_NUM_BK_LIGHT 5 // Backlight control pin, -1 if not used
|
||||||
|
#endif
|
||||||
|
|
||||||
|
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||||
#endif
|
#endif
|
||||||
1857
main/gui.c
1857
main/gui.c
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,48 @@
|
|||||||
#ifndef _KEYPAD_H
|
<<<<<<< HEAD
|
||||||
#define _KEYPAD_H
|
#ifndef _KEYPAD_H
|
||||||
|
#define _KEYPAD_H
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/queue.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
typedef enum
|
|
||||||
{
|
typedef enum
|
||||||
KEY0 = (1 << 0),
|
{
|
||||||
KEY1 = (1 << 1),
|
KEY0 = (1 << 0),
|
||||||
} keycode_t;
|
KEY1 = (1 << 1),
|
||||||
|
} keycode_t;
|
||||||
|
|
||||||
#define KEY_SHORT_PRESS 0
|
|
||||||
#define KEY_LONG_PRESS 4
|
#define KEY_SHORT_PRESS 0
|
||||||
|
#define KEY_LONG_PRESS 4
|
||||||
#define KEY_UP KEY0
|
|
||||||
#define KEY_DOWN KEY1
|
#define KEY_UP KEY0
|
||||||
|
#define KEY_DOWN KEY1
|
||||||
void keypad_start(void);
|
|
||||||
QueueHandle_t keypad_getQueue(void);
|
void keypad_start(void);
|
||||||
|
QueueHandle_t keypad_getQueue(void);
|
||||||
|
|
||||||
|
=======
|
||||||
|
#ifndef _KEYPAD_H
|
||||||
|
#define _KEYPAD_H
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
KEY0 = (1 << 0),
|
||||||
|
KEY1 = (1 << 1),
|
||||||
|
} keycode_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define KEY_SHORT_PRESS 0
|
||||||
|
#define KEY_LONG_PRESS 4
|
||||||
|
|
||||||
|
#define KEY_UP KEY0
|
||||||
|
#define KEY_DOWN KEY1
|
||||||
|
|
||||||
|
void keypad_start(void);
|
||||||
|
QueueHandle_t keypad_getQueue(void);
|
||||||
|
|
||||||
|
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||||
#endif
|
#endif
|
||||||
876
main/main.c
876
main/main.c
@@ -1,291 +1,585 @@
|
|||||||
/*
|
<<<<<<< HEAD
|
||||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
/*
|
||||||
*
|
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
*
|
||||||
*/
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
|
*/
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <unistd.h>
|
||||||
#include <inttypes.h>
|
#include <string.h>
|
||||||
#include "math.h"
|
#include <inttypes.h>
|
||||||
|
#include "math.h"
|
||||||
#include "esp_system.h"
|
|
||||||
#include "esp_log.h"
|
#include "esp_system.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "esp_log.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/timers.h"
|
#include "freertos/task.h"
|
||||||
#include "driver/gpio.h"
|
#include "freertos/timers.h"
|
||||||
#include "nvs.h"
|
#include "driver/gpio.h"
|
||||||
#include "nvs_flash.h"
|
#include "nvs.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
|
||||||
#include "bt_app.h"
|
|
||||||
#include "lsm6dsv.h"
|
#include "bt_app.h"
|
||||||
#include "gui.h"
|
#include "lsm6dsv.h"
|
||||||
#include "gpio.h"
|
#include "gui.h"
|
||||||
#include "keypad.h"
|
#include "gpio.h"
|
||||||
#include "system.h"
|
#include "keypad.h"
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************
|
|
||||||
* STATIC FUNCTION DECLARATIONS
|
/*********************************
|
||||||
********************************/
|
* STATIC FUNCTION DECLARATIONS
|
||||||
typedef struct {
|
********************************/
|
||||||
float alpha; // smoothing factor, 0<alpha<1
|
typedef struct {
|
||||||
float prev_output; // y[n-1]
|
float alpha; // smoothing factor, 0<alpha<1
|
||||||
} LowPassFilter;
|
float prev_output; // y[n-1]
|
||||||
|
} LowPassFilter;
|
||||||
// Initialize the filter. alpha = smoothing factor.
|
|
||||||
// e.g. alpha = dt/(RC+dt) if you derive from cutoff freq & sample time.
|
// Initialize the filter. alpha = smoothing factor.
|
||||||
// init_output can be 0 or your first sample to avoid startup glitch.
|
// e.g. alpha = dt/(RC+dt) if you derive from cutoff freq & sample time.
|
||||||
static inline void LPF_Init(LowPassFilter *f, float alpha, float init_output) {
|
// init_output can be 0 or your first sample to avoid startup glitch.
|
||||||
f->alpha = alpha;
|
static inline void LPF_Init(LowPassFilter *f, float alpha, float init_output) {
|
||||||
f->prev_output = init_output;
|
f->alpha = alpha;
|
||||||
}
|
f->prev_output = init_output;
|
||||||
|
}
|
||||||
// Run one input sample through the filter.
|
|
||||||
// Returns y[n] = alpha * x[n] + (1-alpha) * y[n-1].
|
// Run one input sample through the filter.
|
||||||
static inline float LPF_Update(LowPassFilter *f, float input) {
|
// Returns y[n] = alpha * x[n] + (1-alpha) * y[n-1].
|
||||||
float out = f->alpha * input + (1.0f - f->alpha) * f->prev_output;
|
static inline float LPF_Update(LowPassFilter *f, float input) {
|
||||||
f->prev_output = out;
|
float out = f->alpha * input + (1.0f - f->alpha) * f->prev_output;
|
||||||
return out;
|
f->prev_output = out;
|
||||||
}
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************
|
|
||||||
* STATIC VARIABLE DEFINITIONS
|
/*********************************
|
||||||
********************************/
|
* STATIC VARIABLE DEFINITIONS
|
||||||
static const char *TAG = "main";
|
********************************/
|
||||||
|
static const char *TAG = "main";
|
||||||
/*********************************
|
|
||||||
* STATIC FUNCTION DEFINITIONS
|
/*********************************
|
||||||
********************************/
|
* STATIC FUNCTION DEFINITIONS
|
||||||
|
********************************/
|
||||||
static void init_gpio(void)
|
|
||||||
{
|
static void init_gpio(void)
|
||||||
gpio_config_t io_conf;
|
{
|
||||||
|
gpio_config_t io_conf;
|
||||||
|
|
||||||
// Configure output GPIO
|
|
||||||
io_conf.pin_bit_mask = (1ULL << PIN_NUM_LED_1) | (1ULL << PIN_NUM_LED_2);
|
// Configure output GPIO
|
||||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
io_conf.pin_bit_mask = (1ULL << PIN_NUM_LED_1) | (1ULL << PIN_NUM_LED_2);
|
||||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||||
gpio_config(&io_conf);
|
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||||
|
gpio_config(&io_conf);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
// Configure output power signal
|
#if 1
|
||||||
gpio_set_level(PIN_NUM_nON, 1);
|
// Configure output power signal
|
||||||
|
gpio_set_level(PIN_NUM_nON, 1);
|
||||||
io_conf.pin_bit_mask = (1ULL << PIN_NUM_nON);
|
|
||||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
io_conf.pin_bit_mask = (1ULL << PIN_NUM_nON);
|
||||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||||
gpio_config(&io_conf);
|
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||||
#endif
|
gpio_config(&io_conf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Configure LCD Backlight GPIO
|
|
||||||
io_conf.pin_bit_mask = (1ULL << PIN_NUM_BK_LIGHT);
|
// Configure LCD Backlight GPIO
|
||||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
io_conf.pin_bit_mask = (1ULL << PIN_NUM_BK_LIGHT);
|
||||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||||
gpio_config(&io_conf);
|
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||||
}
|
gpio_config(&io_conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// IMU task to read sensor data
|
|
||||||
static void imu_task(void *pvParameters) {
|
// IMU task to read sensor data
|
||||||
lsm6dsv_data_t imu_data;
|
static void imu_task(void *pvParameters) {
|
||||||
char data_str[128];
|
lsm6dsv_data_t imu_data;
|
||||||
|
char data_str[128];
|
||||||
float roll, pitch, yaw;
|
|
||||||
lsm6dsv_fifo_t fifo;
|
float roll, pitch, yaw;
|
||||||
|
lsm6dsv_fifo_t fifo;
|
||||||
ImuData_t imu;
|
|
||||||
|
ImuData_t imu;
|
||||||
LowPassFilter lpf;
|
|
||||||
LPF_Init(&lpf, FILTER_COEFF, 0);
|
LowPassFilter lpf;
|
||||||
|
LPF_Init(&lpf, FILTER_COEFF, 0);
|
||||||
while (1) {
|
|
||||||
|
while (1) {
|
||||||
// uint8_t samples = lsm6dsv_fifo_ready();
|
|
||||||
|
// uint8_t samples = lsm6dsv_fifo_ready();
|
||||||
//ESP_LOGI(TAG, "Samples: %d", samples);
|
|
||||||
// while (samples)
|
//ESP_LOGI(TAG, "Samples: %d", samples);
|
||||||
// {
|
// while (samples)
|
||||||
// lsm6dsv_fifo_read(&fifo);
|
// {
|
||||||
|
// lsm6dsv_fifo_read(&fifo);
|
||||||
|
|
||||||
|
|
||||||
// // snprintf(data_str, sizeof(data_str),
|
|
||||||
// // "tag: %d, count: %d, (%d, %d, %d)",
|
// // snprintf(data_str, sizeof(data_str),
|
||||||
// // fifo.tag, fifo.count, x, y, z);
|
// // "tag: %d, count: %d, (%d, %d, %d)",
|
||||||
|
// // fifo.tag, fifo.count, x, y, z);
|
||||||
// // ESP_LOGI(TAG, "%s", data_str);
|
|
||||||
|
// // ESP_LOGI(TAG, "%s", data_str);
|
||||||
// samples--;
|
|
||||||
// }
|
// samples--;
|
||||||
|
// }
|
||||||
// lsm6dsv_getAttitude(&fifo, &roll, &pitch, &yaw);
|
|
||||||
|
// lsm6dsv_getAttitude(&fifo, &roll, &pitch, &yaw);
|
||||||
// snprintf(data_str, sizeof(data_str),
|
|
||||||
// "r: %0.3f, p: %0.3f, y: %0.3f",
|
// snprintf(data_str, sizeof(data_str),
|
||||||
// roll, pitch, yaw);
|
// "r: %0.3f, p: %0.3f, y: %0.3f",
|
||||||
|
// roll, pitch, yaw);
|
||||||
// ESP_LOGI(TAG, "%s", data_str);
|
|
||||||
|
// ESP_LOGI(TAG, "%s", data_str);
|
||||||
float xz;
|
|
||||||
float yz;
|
float xz;
|
||||||
float xy;
|
float yz;
|
||||||
|
float xy;
|
||||||
#if 1
|
|
||||||
if (lsm6dsv_read_data(&imu_data) == ESP_OK)
|
#if 1
|
||||||
{
|
if (lsm6dsv_read_data(&imu_data) == ESP_OK)
|
||||||
// snprintf(data_str, sizeof(data_str),
|
{
|
||||||
// "Acc: %.2f, %.2f, %.2f; "
|
// snprintf(data_str, sizeof(data_str),
|
||||||
// "Gyro: %.2f, %.2f, %.2f (%d)\n",
|
// "Acc: %.2f, %.2f, %.2f; "
|
||||||
// imu_data.acc_x, imu_data.acc_y, imu_data.acc_z,
|
// "Gyro: %.2f, %.2f, %.2f (%d)\n",
|
||||||
// imu_data.gyro_x, imu_data.gyro_y, imu_data.gyro_z, lsm6dsv_fifo_ready());
|
// imu_data.acc_x, imu_data.acc_y, imu_data.acc_z,
|
||||||
|
// imu_data.gyro_x, imu_data.gyro_y, imu_data.gyro_z, lsm6dsv_fifo_ready());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
imu.raw[ANGLE_XZ] = atan2f((float)imu_data.acc_z, (float)imu_data.acc_x) * 180 / M_PI;
|
#if 1
|
||||||
imu.raw[ANGLE_YZ] = atan2f((float)imu_data.acc_z, (float)imu_data.acc_y) * 180 / M_PI;
|
imu.raw[ANGLE_XZ] = atan2f((float)imu_data.acc_z, (float)imu_data.acc_x) * 180 / M_PI;
|
||||||
imu.raw[ANGLE_XY] = atan2f((float)imu_data.acc_x, (float)imu_data.acc_y) * 180 / M_PI;
|
imu.raw[ANGLE_YZ] = atan2f((float)imu_data.acc_z, (float)imu_data.acc_y) * 180 / M_PI;
|
||||||
|
imu.raw[ANGLE_XY] = atan2f((float)imu_data.acc_x, (float)imu_data.acc_y) * 180 / M_PI;
|
||||||
|
|
||||||
float angle;
|
|
||||||
|
float angle;
|
||||||
|
|
||||||
angle = system_getAngle();
|
|
||||||
|
angle = system_getAngle();
|
||||||
if (angle > MAX_INDICATION_ANGLE)
|
|
||||||
{
|
if (angle > MAX_INDICATION_ANGLE)
|
||||||
angle = MAX_INDICATION_ANGLE;
|
{
|
||||||
}
|
angle = MAX_INDICATION_ANGLE;
|
||||||
else
|
}
|
||||||
if (angle < -MAX_INDICATION_ANGLE)
|
else
|
||||||
{
|
if (angle < -MAX_INDICATION_ANGLE)
|
||||||
angle = -MAX_INDICATION_ANGLE;
|
{
|
||||||
}
|
angle = -MAX_INDICATION_ANGLE;
|
||||||
|
}
|
||||||
// low pass filter the angle measurement
|
|
||||||
imu.angle = LPF_Update(&lpf, angle);
|
// low pass filter the angle measurement
|
||||||
|
imu.angle = LPF_Update(&lpf, angle);
|
||||||
//imu.filtered[ANGLE_XY] = LPF_Update(&lpf, imu.raw[ANGLE_XY]);
|
|
||||||
|
//imu.filtered[ANGLE_XY] = LPF_Update(&lpf, imu.raw[ANGLE_XY]);
|
||||||
system_setImuData(imu);
|
|
||||||
|
system_setImuData(imu);
|
||||||
// snprintf(data_str, sizeof(data_str),
|
|
||||||
// "(%.2f, %.2f, %.2f)", xy, yz, xy);
|
// snprintf(data_str, sizeof(data_str),
|
||||||
#endif
|
// "(%.2f, %.2f, %.2f)", xy, yz, xy);
|
||||||
|
#endif
|
||||||
#if 0
|
|
||||||
snprintf(data_str, sizeof(data_str),
|
#if 0
|
||||||
"(%.1f, %.1f, %.1f) (%.2f, %.2f, %.2f)",
|
snprintf(data_str, sizeof(data_str),
|
||||||
imu.raw[ANGLE_XZ], imu.raw[ANGLE_YZ], imu.raw[ANGLE_XY],
|
"(%.1f, %.1f, %.1f) (%.2f, %.2f, %.2f)",
|
||||||
(float)imu_data.acc_x, (float)imu_data.acc_y, (float)imu_data.acc_z);
|
imu.raw[ANGLE_XZ], imu.raw[ANGLE_YZ], imu.raw[ANGLE_XY],
|
||||||
ESP_LOGI(TAG, "%s", data_str);
|
(float)imu_data.acc_x, (float)imu_data.acc_y, (float)imu_data.acc_z);
|
||||||
#endif
|
ESP_LOGI(TAG, "%s", data_str);
|
||||||
// Update label text in LVGL task
|
#endif
|
||||||
//lv_label_set_text(imu_label, data_str);
|
// Update label text in LVGL task
|
||||||
|
//lv_label_set_text(imu_label, data_str);
|
||||||
}
|
|
||||||
#endif
|
}
|
||||||
vTaskDelay(pdMS_TO_TICKS(100)); // Update every 100ms
|
#endif
|
||||||
}
|
vTaskDelay(pdMS_TO_TICKS(100)); // Update every 100ms
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/*********************************
|
|
||||||
* MAIN ENTRY POINT
|
/*********************************
|
||||||
********************************/
|
* MAIN ENTRY POINT
|
||||||
|
********************************/
|
||||||
void app_main(void)
|
|
||||||
{
|
void app_main(void)
|
||||||
|
{
|
||||||
/* initialize NVS — it is used to store PHY calibration data */
|
|
||||||
esp_err_t ret = nvs_flash_init();
|
/* initialize NVS — it is used to store PHY calibration data */
|
||||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
esp_err_t ret = nvs_flash_init();
|
||||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||||
ret = nvs_flash_init();
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
}
|
ret = nvs_flash_init();
|
||||||
ESP_ERROR_CHECK(ret);
|
}
|
||||||
|
ESP_ERROR_CHECK(ret);
|
||||||
init_gpio();
|
|
||||||
|
init_gpio();
|
||||||
system_init();
|
|
||||||
|
system_init();
|
||||||
|
|
||||||
|
|
||||||
// Initialize IMU
|
|
||||||
ESP_ERROR_CHECK(lsm6dsv_init(22, 21)); // SCL = IO14, SDA = IO15
|
// Initialize IMU
|
||||||
|
ESP_ERROR_CHECK(lsm6dsv_init(22, 21)); // SCL = IO14, SDA = IO15
|
||||||
|
|
||||||
|
|
||||||
// Create IMU task
|
|
||||||
TaskHandle_t h = xTaskCreate(imu_task, "imu_task", 4096, NULL, 5, NULL);
|
// Create IMU task
|
||||||
|
TaskHandle_t h = xTaskCreate(imu_task, "imu_task", 4096, NULL, 5, NULL);
|
||||||
|
|
||||||
|
|
||||||
bt_app_init();
|
|
||||||
|
bt_app_init();
|
||||||
gui_start();
|
|
||||||
|
gui_start();
|
||||||
gpio_set_level(PIN_NUM_LED_2, 1);
|
|
||||||
|
gpio_set_level(PIN_NUM_LED_2, 1);
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
#if 0
|
||||||
keypad_start();
|
|
||||||
QueueHandle_t q = keypad_getQueue();
|
keypad_start();
|
||||||
uint32_t ev = 0;
|
QueueHandle_t q = keypad_getQueue();
|
||||||
|
uint32_t ev = 0;
|
||||||
//gpio_set_level(PIN_NUM_LED_1, 1);
|
|
||||||
gpio_set_level(PIN_NUM_LED_2, 1);
|
//gpio_set_level(PIN_NUM_LED_1, 1);
|
||||||
|
gpio_set_level(PIN_NUM_LED_2, 1);
|
||||||
// Main loop - LVGL task will run automatically
|
|
||||||
while (1) {
|
// Main loop - LVGL task will run automatically
|
||||||
|
while (1) {
|
||||||
if (xQueueReceive(q, &ev, pdMS_TO_TICKS(10)) == pdTRUE)
|
|
||||||
{
|
if (xQueueReceive(q, &ev, pdMS_TO_TICKS(10)) == pdTRUE)
|
||||||
switch (ev)
|
{
|
||||||
{
|
switch (ev)
|
||||||
case (KEY_UP << KEY_LONG_PRESS):
|
{
|
||||||
{
|
case (KEY_UP << KEY_LONG_PRESS):
|
||||||
system_setZeroAngle();
|
{
|
||||||
break;
|
system_setZeroAngle();
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
case (KEY_DOWN << KEY_LONG_PRESS):
|
|
||||||
{
|
case (KEY_DOWN << KEY_LONG_PRESS):
|
||||||
system_clearZeroAngle();
|
{
|
||||||
break;
|
system_clearZeroAngle();
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
}
|
|
||||||
#else
|
}
|
||||||
while (1)
|
#else
|
||||||
{
|
while (1)
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
{
|
||||||
}
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
#endif
|
}
|
||||||
}
|
#endif
|
||||||
|
}
|
||||||
|
=======
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "math.h"
|
||||||
|
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/timers.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "nvs.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "bt_app.h"
|
||||||
|
#include "lsm6dsv.h"
|
||||||
|
#include "gui.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "keypad.h"
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
* STATIC FUNCTION DECLARATIONS
|
||||||
|
********************************/
|
||||||
|
typedef struct {
|
||||||
|
float alpha; // smoothing factor, 0<alpha<1
|
||||||
|
float prev_output; // y[n-1]
|
||||||
|
} LowPassFilter;
|
||||||
|
|
||||||
|
// Initialize the filter. alpha = smoothing factor.
|
||||||
|
// e.g. alpha = dt/(RC+dt) if you derive from cutoff freq & sample time.
|
||||||
|
// init_output can be 0 or your first sample to avoid startup glitch.
|
||||||
|
static inline void LPF_Init(LowPassFilter *f, float alpha, float init_output) {
|
||||||
|
f->alpha = alpha;
|
||||||
|
f->prev_output = init_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run one input sample through the filter.
|
||||||
|
// Returns y[n] = alpha * x[n] + (1-alpha) * y[n-1].
|
||||||
|
static inline float LPF_Update(LowPassFilter *f, float input) {
|
||||||
|
float out = f->alpha * input + (1.0f - f->alpha) * f->prev_output;
|
||||||
|
f->prev_output = out;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
* STATIC VARIABLE DEFINITIONS
|
||||||
|
********************************/
|
||||||
|
static const char *TAG = "main";
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
* STATIC FUNCTION DEFINITIONS
|
||||||
|
********************************/
|
||||||
|
|
||||||
|
static void init_gpio(void)
|
||||||
|
{
|
||||||
|
gpio_config_t io_conf;
|
||||||
|
|
||||||
|
|
||||||
|
// Configure output GPIO
|
||||||
|
io_conf.pin_bit_mask = (1ULL << PIN_NUM_LED_1) | (1ULL << PIN_NUM_LED_2);
|
||||||
|
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||||
|
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||||
|
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||||
|
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||||
|
gpio_config(&io_conf);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
// Configure output power signal
|
||||||
|
gpio_set_level(PIN_NUM_nON, 1);
|
||||||
|
|
||||||
|
io_conf.pin_bit_mask = (1ULL << PIN_NUM_nON);
|
||||||
|
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||||
|
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||||
|
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||||
|
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||||
|
gpio_config(&io_conf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Configure LCD Backlight GPIO
|
||||||
|
io_conf.pin_bit_mask = (1ULL << PIN_NUM_BK_LIGHT);
|
||||||
|
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||||
|
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||||
|
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||||
|
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||||
|
gpio_config(&io_conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// IMU task to read sensor data
|
||||||
|
static void imu_task(void *pvParameters) {
|
||||||
|
lsm6dsv_data_t imu_data;
|
||||||
|
char data_str[128];
|
||||||
|
|
||||||
|
float roll, pitch, yaw;
|
||||||
|
lsm6dsv_fifo_t fifo;
|
||||||
|
|
||||||
|
ImuData_t imu;
|
||||||
|
|
||||||
|
LowPassFilter lpf;
|
||||||
|
LPF_Init(&lpf, FILTER_COEFF, 0);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
// uint8_t samples = lsm6dsv_fifo_ready();
|
||||||
|
|
||||||
|
//ESP_LOGI(TAG, "Samples: %d", samples);
|
||||||
|
// while (samples)
|
||||||
|
// {
|
||||||
|
// lsm6dsv_fifo_read(&fifo);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // snprintf(data_str, sizeof(data_str),
|
||||||
|
// // "tag: %d, count: %d, (%d, %d, %d)",
|
||||||
|
// // fifo.tag, fifo.count, x, y, z);
|
||||||
|
|
||||||
|
// // ESP_LOGI(TAG, "%s", data_str);
|
||||||
|
|
||||||
|
// samples--;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// lsm6dsv_getAttitude(&fifo, &roll, &pitch, &yaw);
|
||||||
|
|
||||||
|
// snprintf(data_str, sizeof(data_str),
|
||||||
|
// "r: %0.3f, p: %0.3f, y: %0.3f",
|
||||||
|
// roll, pitch, yaw);
|
||||||
|
|
||||||
|
// ESP_LOGI(TAG, "%s", data_str);
|
||||||
|
|
||||||
|
float xz;
|
||||||
|
float yz;
|
||||||
|
float xy;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
if (lsm6dsv_read_data(&imu_data) == ESP_OK)
|
||||||
|
{
|
||||||
|
// snprintf(data_str, sizeof(data_str),
|
||||||
|
// "Acc: %.2f, %.2f, %.2f; "
|
||||||
|
// "Gyro: %.2f, %.2f, %.2f (%d)\n",
|
||||||
|
// imu_data.acc_x, imu_data.acc_y, imu_data.acc_z,
|
||||||
|
// imu_data.gyro_x, imu_data.gyro_y, imu_data.gyro_z, lsm6dsv_fifo_ready());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
imu.raw[ANGLE_XZ] = atan2f((float)imu_data.acc_z, (float)imu_data.acc_x) * 180 / M_PI;
|
||||||
|
imu.raw[ANGLE_YZ] = atan2f((float)imu_data.acc_z, (float)imu_data.acc_y) * 180 / M_PI;
|
||||||
|
imu.raw[ANGLE_XY] = atan2f((float)imu_data.acc_x, (float)imu_data.acc_y) * 180 / M_PI;
|
||||||
|
|
||||||
|
|
||||||
|
float angle;
|
||||||
|
|
||||||
|
|
||||||
|
angle = system_getAngle();
|
||||||
|
|
||||||
|
if (angle > MAX_INDICATION_ANGLE)
|
||||||
|
{
|
||||||
|
angle = MAX_INDICATION_ANGLE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (angle < -MAX_INDICATION_ANGLE)
|
||||||
|
{
|
||||||
|
angle = -MAX_INDICATION_ANGLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// low pass filter the angle measurement
|
||||||
|
imu.angle = LPF_Update(&lpf, angle);
|
||||||
|
|
||||||
|
//imu.filtered[ANGLE_XY] = LPF_Update(&lpf, imu.raw[ANGLE_XY]);
|
||||||
|
|
||||||
|
system_setImuData(imu);
|
||||||
|
|
||||||
|
// snprintf(data_str, sizeof(data_str),
|
||||||
|
// "(%.2f, %.2f, %.2f)", xy, yz, xy);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
snprintf(data_str, sizeof(data_str),
|
||||||
|
"(%.1f, %.1f, %.1f) (%.2f, %.2f, %.2f)",
|
||||||
|
imu.raw[ANGLE_XZ], imu.raw[ANGLE_YZ], imu.raw[ANGLE_XY],
|
||||||
|
(float)imu_data.acc_x, (float)imu_data.acc_y, (float)imu_data.acc_z);
|
||||||
|
ESP_LOGI(TAG, "%s", data_str);
|
||||||
|
#endif
|
||||||
|
// Update label text in LVGL task
|
||||||
|
//lv_label_set_text(imu_label, data_str);
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100)); // Update every 100ms
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************
|
||||||
|
* MAIN ENTRY POINT
|
||||||
|
********************************/
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* initialize NVS — it is used to store PHY calibration data */
|
||||||
|
esp_err_t ret = nvs_flash_init();
|
||||||
|
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
ret = nvs_flash_init();
|
||||||
|
}
|
||||||
|
ESP_ERROR_CHECK(ret);
|
||||||
|
|
||||||
|
init_gpio();
|
||||||
|
|
||||||
|
system_init();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize IMU
|
||||||
|
ESP_ERROR_CHECK(lsm6dsv_init(22, 21)); // SCL = IO14, SDA = IO15
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Create IMU task
|
||||||
|
TaskHandle_t h = xTaskCreate(imu_task, "imu_task", 4096, NULL, 5, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bt_app_init();
|
||||||
|
|
||||||
|
gui_start();
|
||||||
|
|
||||||
|
gpio_set_level(PIN_NUM_LED_2, 1);
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
keypad_start();
|
||||||
|
QueueHandle_t q = keypad_getQueue();
|
||||||
|
uint32_t ev = 0;
|
||||||
|
|
||||||
|
//gpio_set_level(PIN_NUM_LED_1, 1);
|
||||||
|
gpio_set_level(PIN_NUM_LED_2, 1);
|
||||||
|
|
||||||
|
// Main loop - LVGL task will run automatically
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
if (xQueueReceive(q, &ev, pdMS_TO_TICKS(10)) == pdTRUE)
|
||||||
|
{
|
||||||
|
switch (ev)
|
||||||
|
{
|
||||||
|
case (KEY_UP << KEY_LONG_PRESS):
|
||||||
|
{
|
||||||
|
system_setZeroAngle();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case (KEY_DOWN << KEY_LONG_PRESS):
|
||||||
|
{
|
||||||
|
system_clearZeroAngle();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||||
|
|||||||
507
main/system.c
507
main/system.c
@@ -1,169 +1,340 @@
|
|||||||
#include "system.h"
|
<<<<<<< HEAD
|
||||||
#include "esp_log.h"
|
#include "system.h"
|
||||||
|
#include "esp_log.h"
|
||||||
static SystemState_t _systemState;
|
|
||||||
|
static SystemState_t _systemState;
|
||||||
static EventGroupHandle_t _systemEvent;
|
|
||||||
static EventManager_t _eventManager;
|
static EventGroupHandle_t _systemEvent;
|
||||||
|
static EventManager_t _eventManager;
|
||||||
void system_init(void)
|
|
||||||
{
|
void system_init(void)
|
||||||
_systemState.zeroAngle = 0.0f;
|
{
|
||||||
_systemState.primaryAxis = PRIMARY_AXIS;
|
_systemState.zeroAngle = 0.0f;
|
||||||
|
_systemState.primaryAxis = PRIMARY_AXIS;
|
||||||
EventGroupHandle_t evt = xEventGroupCreate();
|
|
||||||
|
EventGroupHandle_t evt = xEventGroupCreate();
|
||||||
_eventManager.count = 0;
|
|
||||||
_eventManager.mutex = xSemaphoreCreateMutex();
|
_eventManager.count = 0;
|
||||||
}
|
_eventManager.mutex = xSemaphoreCreateMutex();
|
||||||
|
}
|
||||||
int system_getPrimaryAxis(void)
|
|
||||||
{
|
int system_getPrimaryAxis(void)
|
||||||
int axis;
|
{
|
||||||
|
int axis;
|
||||||
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
|
||||||
axis = _systemState.primaryAxis;
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
xSemaphoreGive(_eventManager.mutex);
|
axis = _systemState.primaryAxis;
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
return axis;
|
|
||||||
}
|
return axis;
|
||||||
|
}
|
||||||
float system_getAngle(void)
|
|
||||||
{
|
float system_getAngle(void)
|
||||||
float angle;
|
{
|
||||||
|
float angle;
|
||||||
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_setZeroAngle(void)
|
|
||||||
{
|
void system_setZeroAngle(void)
|
||||||
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
{
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
|
|
||||||
_systemState.zeroAngle = _systemState.imu.raw[_systemState.primaryAxis];
|
|
||||||
|
_systemState.zeroAngle = _systemState.imu.raw[_systemState.primaryAxis];
|
||||||
ESP_LOGI("system", "Zero: %.1f", _systemState.zeroAngle);
|
|
||||||
|
ESP_LOGI("system", "Zero: %.1f", _systemState.zeroAngle);
|
||||||
xSemaphoreGive(_eventManager.mutex);
|
|
||||||
}
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
|
}
|
||||||
void system_clearZeroAngle(void)
|
|
||||||
{
|
void system_clearZeroAngle(void)
|
||||||
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
{
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
_systemState.zeroAngle = 0.0f;
|
|
||||||
|
_systemState.zeroAngle = 0.0f;
|
||||||
ESP_LOGI("system", "Zero: %.1f", _systemState.zeroAngle);
|
|
||||||
|
ESP_LOGI("system", "Zero: %.1f", _systemState.zeroAngle);
|
||||||
xSemaphoreGive(_eventManager.mutex);
|
|
||||||
}
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
|
}
|
||||||
float system_getZeroAngle(void)
|
|
||||||
{
|
float system_getZeroAngle(void)
|
||||||
float angle;
|
{
|
||||||
|
float angle;
|
||||||
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
angle = _systemState.zeroAngle;
|
|
||||||
|
angle = _systemState.zeroAngle;
|
||||||
xSemaphoreGive(_eventManager.mutex);
|
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
return angle;
|
|
||||||
}
|
return angle;
|
||||||
|
}
|
||||||
void system_setImuData(ImuData_t imu)
|
|
||||||
{
|
void system_setImuData(ImuData_t imu)
|
||||||
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
{
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
_systemState.imu = imu;
|
|
||||||
|
_systemState.imu = imu;
|
||||||
xSemaphoreGive(_eventManager.mutex);
|
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
//ESP_LOGI("g", "New IMU Data: %.2f", xy);
|
|
||||||
|
//ESP_LOGI("g", "New IMU Data: %.2f", xy);
|
||||||
system_notifyAll(EM_EVENT_NEW_DATA);
|
|
||||||
}
|
system_notifyAll(EM_EVENT_NEW_DATA);
|
||||||
|
}
|
||||||
ImuData_t system_getImuData(void)
|
|
||||||
{
|
ImuData_t system_getImuData(void)
|
||||||
ImuData_t imu;
|
{
|
||||||
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
ImuData_t imu;
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
imu = _systemState.imu;
|
|
||||||
|
imu = _systemState.imu;
|
||||||
xSemaphoreGive(_eventManager.mutex);
|
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
return imu;
|
|
||||||
}
|
return imu;
|
||||||
|
}
|
||||||
void system_waitForEvent(void)
|
|
||||||
{
|
void system_waitForEvent(void)
|
||||||
}
|
{
|
||||||
|
}
|
||||||
SystemState_t *system_getState(void)
|
|
||||||
{
|
SystemState_t *system_getState(void)
|
||||||
return &_systemState;
|
{
|
||||||
}
|
return &_systemState;
|
||||||
|
}
|
||||||
|
|
||||||
BaseType_t system_subscribe(TaskHandle_t task) {
|
|
||||||
|
BaseType_t system_subscribe(TaskHandle_t task) {
|
||||||
EventManager_t *em = &_eventManager;
|
|
||||||
|
EventManager_t *em = &_eventManager;
|
||||||
ESP_LOGI("g", "Subscribe: %p", task);
|
|
||||||
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdFALSE) {
|
ESP_LOGI("g", "Subscribe: %p", task);
|
||||||
return pdFAIL;
|
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdFALSE) {
|
||||||
}
|
return pdFAIL;
|
||||||
if (em->count < EM_MAX_SUBSCRIBERS) {
|
}
|
||||||
// avoid duplicates?
|
if (em->count < EM_MAX_SUBSCRIBERS) {
|
||||||
ESP_LOGI("g", "PASS");
|
// avoid duplicates?
|
||||||
em->subscribers[em->count++] = task;
|
ESP_LOGI("g", "PASS");
|
||||||
xSemaphoreGive(em->mutex);
|
em->subscribers[em->count++] = task;
|
||||||
return pdPASS;
|
xSemaphoreGive(em->mutex);
|
||||||
}
|
return pdPASS;
|
||||||
xSemaphoreGive(em->mutex);
|
}
|
||||||
return pdFAIL; // full
|
xSemaphoreGive(em->mutex);
|
||||||
}
|
return pdFAIL; // full
|
||||||
|
}
|
||||||
BaseType_t system_unsubscribe(TaskHandle_t task) {
|
|
||||||
|
BaseType_t system_unsubscribe(TaskHandle_t task) {
|
||||||
EventManager_t *em = &_eventManager;
|
|
||||||
|
EventManager_t *em = &_eventManager;
|
||||||
BaseType_t removed = pdFAIL;
|
|
||||||
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdTRUE) {
|
BaseType_t removed = pdFAIL;
|
||||||
for (size_t i = 0; i < em->count; ++i) {
|
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdTRUE) {
|
||||||
if (em->subscribers[i] == task) {
|
for (size_t i = 0; i < em->count; ++i) {
|
||||||
// shift down
|
if (em->subscribers[i] == task) {
|
||||||
for (size_t j = i; j + 1 < em->count; ++j)
|
// shift down
|
||||||
em->subscribers[j] = em->subscribers[j+1];
|
for (size_t j = i; j + 1 < em->count; ++j)
|
||||||
em->count--;
|
em->subscribers[j] = em->subscribers[j+1];
|
||||||
removed = pdPASS;
|
em->count--;
|
||||||
break;
|
removed = pdPASS;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
xSemaphoreGive(em->mutex);
|
}
|
||||||
}
|
xSemaphoreGive(em->mutex);
|
||||||
return removed;
|
}
|
||||||
}
|
return removed;
|
||||||
|
}
|
||||||
void system_notifyAll(uint32_t eventBits) {
|
|
||||||
EventManager_t *em = &_eventManager;
|
void system_notifyAll(uint32_t eventBits) {
|
||||||
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdTRUE) {
|
EventManager_t *em = &_eventManager;
|
||||||
for (size_t i = 0; i < em->count; ++i) {
|
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdTRUE) {
|
||||||
// set the bits in each task's notification value
|
for (size_t i = 0; i < em->count; ++i) {
|
||||||
//ESP_LOGI("g", "Notify: %p", em->subscribers[i]);
|
// set the bits in each task's notification value
|
||||||
xTaskNotify(em->subscribers[i],
|
//ESP_LOGI("g", "Notify: %p", em->subscribers[i]);
|
||||||
eventBits,
|
xTaskNotify(em->subscribers[i],
|
||||||
eSetBits);
|
eventBits,
|
||||||
}
|
eSetBits);
|
||||||
xSemaphoreGive(em->mutex);
|
}
|
||||||
}
|
xSemaphoreGive(em->mutex);
|
||||||
|
}
|
||||||
|
=======
|
||||||
|
#include "system.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
static SystemState_t _systemState;
|
||||||
|
|
||||||
|
static EventGroupHandle_t _systemEvent;
|
||||||
|
static EventManager_t _eventManager;
|
||||||
|
|
||||||
|
void system_init(void)
|
||||||
|
{
|
||||||
|
_systemState.zeroAngle = 0.0f;
|
||||||
|
_systemState.primaryAxis = PRIMARY_AXIS;
|
||||||
|
|
||||||
|
EventGroupHandle_t evt = xEventGroupCreate();
|
||||||
|
|
||||||
|
_eventManager.count = 0;
|
||||||
|
_eventManager.mutex = xSemaphoreCreateMutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
int system_getPrimaryAxis(void)
|
||||||
|
{
|
||||||
|
int axis;
|
||||||
|
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
|
axis = _systemState.primaryAxis;
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
|
|
||||||
|
return axis;
|
||||||
|
}
|
||||||
|
|
||||||
|
float system_getAngle(void)
|
||||||
|
{
|
||||||
|
float angle;
|
||||||
|
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
|
|
||||||
|
|
||||||
|
angle = _systemState.imu.raw[_systemState.primaryAxis] - _systemState.zeroAngle;
|
||||||
|
|
||||||
|
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
|
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void system_setZeroAngle(void)
|
||||||
|
{
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
|
|
||||||
|
|
||||||
|
_systemState.zeroAngle = _systemState.imu.raw[_systemState.primaryAxis];
|
||||||
|
|
||||||
|
ESP_LOGI("system", "Zero: %.1f", _systemState.zeroAngle);
|
||||||
|
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void system_clearZeroAngle(void)
|
||||||
|
{
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
|
|
||||||
|
_systemState.zeroAngle = 0.0f;
|
||||||
|
|
||||||
|
ESP_LOGI("system", "Zero: %.1f", _systemState.zeroAngle);
|
||||||
|
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
float system_getZeroAngle(void)
|
||||||
|
{
|
||||||
|
float angle;
|
||||||
|
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
|
|
||||||
|
angle = _systemState.zeroAngle;
|
||||||
|
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
|
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void system_setImuData(ImuData_t imu)
|
||||||
|
{
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
|
|
||||||
|
_systemState.imu = imu;
|
||||||
|
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
|
|
||||||
|
//ESP_LOGI("g", "New IMU Data: %.2f", xy);
|
||||||
|
|
||||||
|
system_notifyAll(EM_EVENT_NEW_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImuData_t system_getImuData(void)
|
||||||
|
{
|
||||||
|
ImuData_t imu;
|
||||||
|
xSemaphoreTake(_eventManager.mutex, portMAX_DELAY);
|
||||||
|
|
||||||
|
imu = _systemState.imu;
|
||||||
|
|
||||||
|
xSemaphoreGive(_eventManager.mutex);
|
||||||
|
|
||||||
|
return imu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void system_waitForEvent(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemState_t *system_getState(void)
|
||||||
|
{
|
||||||
|
return &_systemState;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BaseType_t system_subscribe(TaskHandle_t task) {
|
||||||
|
|
||||||
|
EventManager_t *em = &_eventManager;
|
||||||
|
|
||||||
|
ESP_LOGI("g", "Subscribe: %p", task);
|
||||||
|
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdFALSE) {
|
||||||
|
return pdFAIL;
|
||||||
|
}
|
||||||
|
if (em->count < EM_MAX_SUBSCRIBERS) {
|
||||||
|
// avoid duplicates?
|
||||||
|
ESP_LOGI("g", "PASS");
|
||||||
|
em->subscribers[em->count++] = task;
|
||||||
|
xSemaphoreGive(em->mutex);
|
||||||
|
return pdPASS;
|
||||||
|
}
|
||||||
|
xSemaphoreGive(em->mutex);
|
||||||
|
return pdFAIL; // full
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseType_t system_unsubscribe(TaskHandle_t task) {
|
||||||
|
|
||||||
|
EventManager_t *em = &_eventManager;
|
||||||
|
|
||||||
|
BaseType_t removed = pdFAIL;
|
||||||
|
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdTRUE) {
|
||||||
|
for (size_t i = 0; i < em->count; ++i) {
|
||||||
|
if (em->subscribers[i] == task) {
|
||||||
|
// shift down
|
||||||
|
for (size_t j = i; j + 1 < em->count; ++j)
|
||||||
|
em->subscribers[j] = em->subscribers[j+1];
|
||||||
|
em->count--;
|
||||||
|
removed = pdPASS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xSemaphoreGive(em->mutex);
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void system_notifyAll(uint32_t eventBits) {
|
||||||
|
EventManager_t *em = &_eventManager;
|
||||||
|
if (xSemaphoreTake(em->mutex, portMAX_DELAY) == pdTRUE) {
|
||||||
|
for (size_t i = 0; i < em->count; ++i) {
|
||||||
|
// set the bits in each task's notification value
|
||||||
|
//ESP_LOGI("g", "Notify: %p", em->subscribers[i]);
|
||||||
|
xTaskNotify(em->subscribers[i],
|
||||||
|
eventBits,
|
||||||
|
eSetBits);
|
||||||
|
}
|
||||||
|
xSemaphoreGive(em->mutex);
|
||||||
|
}
|
||||||
|
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||||
}
|
}
|
||||||
225
main/system.h
225
main/system.h
@@ -1,75 +1,152 @@
|
|||||||
#ifndef SYSTEM_H
|
<<<<<<< HEAD
|
||||||
#define SYSTEM_H
|
#ifndef SYSTEM_H
|
||||||
|
#define SYSTEM_H
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
#define DISABLE_GUI
|
|
||||||
|
#define DISABLE_GUI
|
||||||
enum
|
|
||||||
{
|
enum
|
||||||
ANGLE_XY = 0,
|
{
|
||||||
ANGLE_XZ,
|
ANGLE_XY = 0,
|
||||||
ANGLE_YZ,
|
ANGLE_XZ,
|
||||||
};
|
ANGLE_YZ,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
typedef struct
|
||||||
float raw[3];
|
{
|
||||||
float filtered[3];
|
float raw[3];
|
||||||
float angle;
|
float filtered[3];
|
||||||
} ImuData_t;
|
float angle;
|
||||||
|
} ImuData_t;
|
||||||
typedef struct SystemState_s
|
|
||||||
{
|
typedef struct SystemState_s
|
||||||
ImuData_t imu;
|
{
|
||||||
|
ImuData_t imu;
|
||||||
EventGroupHandle_t event;
|
|
||||||
|
EventGroupHandle_t event;
|
||||||
float zeroAngle;
|
|
||||||
int primaryAxis;
|
float zeroAngle;
|
||||||
|
int primaryAxis;
|
||||||
} SystemState_t;
|
|
||||||
|
} SystemState_t;
|
||||||
|
|
||||||
#define MAX_INDICATION_ANGLE 5.0f
|
|
||||||
#define FILTER_COEFF 0.2f // 0 to 1 Smaller number is heavier filter
|
#define MAX_INDICATION_ANGLE 5.0f
|
||||||
#define PRIMARY_AXIS ANGLE_YZ
|
#define FILTER_COEFF 0.2f // 0 to 1 Smaller number is heavier filter
|
||||||
|
#define PRIMARY_AXIS ANGLE_YZ
|
||||||
#define EM_MAX_SUBSCRIBERS 8 // tweak as needed
|
|
||||||
#define EM_EVENT_NEW_DATA (1UL<<0)
|
#define EM_MAX_SUBSCRIBERS 8 // tweak as needed
|
||||||
#define EM_EVENT_ERROR (1UL<<1)
|
#define EM_EVENT_NEW_DATA (1UL<<0)
|
||||||
// …add more event bit-masks here…
|
#define EM_EVENT_ERROR (1UL<<1)
|
||||||
|
// …add more event bit-masks here…
|
||||||
typedef struct {
|
|
||||||
TaskHandle_t subscribers[EM_MAX_SUBSCRIBERS];
|
typedef struct {
|
||||||
size_t count;
|
TaskHandle_t subscribers[EM_MAX_SUBSCRIBERS];
|
||||||
SemaphoreHandle_t mutex;
|
size_t count;
|
||||||
} EventManager_t;
|
SemaphoreHandle_t mutex;
|
||||||
|
} EventManager_t;
|
||||||
void system_init(void);
|
|
||||||
void system_setImuData(ImuData_t imu);
|
void system_init(void);
|
||||||
|
void system_setImuData(ImuData_t imu);
|
||||||
ImuData_t system_getImuData(void);
|
|
||||||
|
ImuData_t system_getImuData(void);
|
||||||
int system_getPrimaryAxis(void);
|
|
||||||
float system_getAngle(void);
|
int system_getPrimaryAxis(void);
|
||||||
|
float system_getAngle(void);
|
||||||
void system_setZeroAngle(void);
|
|
||||||
void system_clearZeroAngle(void);
|
void system_setZeroAngle(void);
|
||||||
float system_getZeroAngle(void);
|
void system_clearZeroAngle(void);
|
||||||
|
float system_getZeroAngle(void);
|
||||||
// Subscribe (register) current task to receive events
|
|
||||||
BaseType_t system_subscribe(TaskHandle_t task);
|
// Subscribe (register) current task to receive events
|
||||||
|
BaseType_t system_subscribe(TaskHandle_t task);
|
||||||
// Unsubscribe if you ever need
|
|
||||||
BaseType_t system_unsubscribe(TaskHandle_t task);
|
// Unsubscribe if you ever need
|
||||||
|
BaseType_t system_unsubscribe(TaskHandle_t task);
|
||||||
// Notify all subscribers of one or more event bits
|
|
||||||
void system_notifyAll(uint32_t eventBits);
|
// Notify all subscribers of one or more event bits
|
||||||
|
void system_notifyAll(uint32_t eventBits);
|
||||||
|
|
||||||
|
|
||||||
|
=======
|
||||||
|
#ifndef SYSTEM_H
|
||||||
|
#define SYSTEM_H
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/semphr.h"
|
||||||
|
|
||||||
|
#define DISABLE_GUI
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ANGLE_XY = 0,
|
||||||
|
ANGLE_XZ,
|
||||||
|
ANGLE_YZ,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
float raw[3];
|
||||||
|
float filtered[3];
|
||||||
|
float angle;
|
||||||
|
} ImuData_t;
|
||||||
|
|
||||||
|
typedef struct SystemState_s
|
||||||
|
{
|
||||||
|
ImuData_t imu;
|
||||||
|
|
||||||
|
EventGroupHandle_t event;
|
||||||
|
|
||||||
|
float zeroAngle;
|
||||||
|
int primaryAxis;
|
||||||
|
|
||||||
|
} SystemState_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_INDICATION_ANGLE 5.0f
|
||||||
|
#define FILTER_COEFF 0.2f // 0 to 1 Smaller number is heavier filter
|
||||||
|
#define PRIMARY_AXIS ANGLE_YZ
|
||||||
|
|
||||||
|
#define EM_MAX_SUBSCRIBERS 8 // tweak as needed
|
||||||
|
#define EM_EVENT_NEW_DATA (1UL<<0)
|
||||||
|
#define EM_EVENT_ERROR (1UL<<1)
|
||||||
|
// …add more event bit-masks here…
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TaskHandle_t subscribers[EM_MAX_SUBSCRIBERS];
|
||||||
|
size_t count;
|
||||||
|
SemaphoreHandle_t mutex;
|
||||||
|
} EventManager_t;
|
||||||
|
|
||||||
|
void system_init(void);
|
||||||
|
void system_setImuData(ImuData_t imu);
|
||||||
|
|
||||||
|
ImuData_t system_getImuData(void);
|
||||||
|
|
||||||
|
int system_getPrimaryAxis(void);
|
||||||
|
float system_getAngle(void);
|
||||||
|
|
||||||
|
void system_setZeroAngle(void);
|
||||||
|
void system_clearZeroAngle(void);
|
||||||
|
float system_getZeroAngle(void);
|
||||||
|
|
||||||
|
// Subscribe (register) current task to receive events
|
||||||
|
BaseType_t system_subscribe(TaskHandle_t task);
|
||||||
|
|
||||||
|
// Unsubscribe if you ever need
|
||||||
|
BaseType_t system_unsubscribe(TaskHandle_t task);
|
||||||
|
|
||||||
|
// Notify all subscribers of one or more event bits
|
||||||
|
void system_notifyAll(uint32_t eventBits);
|
||||||
|
|
||||||
|
|
||||||
|
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||||
#endif
|
#endif
|
||||||
13
monitor.bat
Normal file
13
monitor.bat
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
@echo off
|
||||||
|
REM =============================================
|
||||||
|
REM ESP32 Serial Monitor using settings.json
|
||||||
|
REM =============================================
|
||||||
|
|
||||||
|
IF NOT EXIST .venv\Scripts\python.exe (
|
||||||
|
echo [ERROR] .venv not found. Run setup-env.bat first.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
call .venv\Scripts\activate.bat
|
||||||
|
python flash_tool\monitor.py
|
||||||
10
prepare_config.py
Normal file
10
prepare_config.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
with open("settings.json") as f:
|
||||||
|
cfg = json.load(f)
|
||||||
|
|
||||||
|
with open("project_settings.cmake", "w") as out:
|
||||||
|
out.write(f'set(PROJECT_NAME "{cfg["project_name"]}")\n')
|
||||||
|
out.write(f'set(CHIP "{cfg["chip"]}")\n')
|
||||||
|
out.write(f'set(PORT "{cfg["port"]}")\n')
|
||||||
|
out.write(f'set(BAUD "{cfg["baud"]}")\n')
|
||||||
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
esptool
|
||||||
|
pyserial
|
||||||
|
|
||||||
@@ -1,9 +1,21 @@
|
|||||||
# Override some defaults so BT stack is enabled and
|
<<<<<<< HEAD
|
||||||
# Classic BT is enabled
|
# Override some defaults so BT stack is enabled and
|
||||||
CONFIG_BT_ENABLED=y
|
# Classic BT is enabled
|
||||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=n
|
CONFIG_BT_ENABLED=y
|
||||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y
|
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=n
|
||||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y
|
||||||
CONFIG_BT_BLUEDROID_ENABLED=y
|
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||||
CONFIG_BT_CLASSIC_ENABLED=y
|
CONFIG_BT_BLUEDROID_ENABLED=y
|
||||||
CONFIG_BT_A2DP_ENABLE=y
|
CONFIG_BT_CLASSIC_ENABLED=y
|
||||||
|
CONFIG_BT_A2DP_ENABLE=y
|
||||||
|
=======
|
||||||
|
# Override some defaults so BT stack is enabled and
|
||||||
|
# Classic BT is enabled
|
||||||
|
CONFIG_BT_ENABLED=y
|
||||||
|
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=n
|
||||||
|
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y
|
||||||
|
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||||
|
CONFIG_BT_BLUEDROID_ENABLED=y
|
||||||
|
CONFIG_BT_CLASSIC_ENABLED=y
|
||||||
|
CONFIG_BT_A2DP_ENABLE=y
|
||||||
|
>>>>>>> 4feb4c0a98bddb1f2a172ea4b195ce31ba18d442
|
||||||
|
|||||||
8667
sdkconfig.old
8667
sdkconfig.old
File diff suppressed because it is too large
Load Diff
12
settings.json
Normal file
12
settings.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"project_name": "soundshot",
|
||||||
|
"chip": "esp32h2",
|
||||||
|
"port": "COM8",
|
||||||
|
"monitor_baud": 115200,
|
||||||
|
"flash_baud": 460800,
|
||||||
|
"flash_mode": "dio",
|
||||||
|
"flash_freq": "48m",
|
||||||
|
"flash_size": "2MB",
|
||||||
|
"before": "default-reset",
|
||||||
|
"after": "hard-reset"
|
||||||
|
}
|
||||||
17
setup-env.bat
Normal file
17
setup-env.bat
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
echo [ESP32 Setup] Creating Python virtual environment...
|
||||||
|
python -m venv .venv
|
||||||
|
|
||||||
|
echo [ESP32 Setup] Activating environment...
|
||||||
|
call .venv\Scripts\activate.bat
|
||||||
|
|
||||||
|
echo [ESP32 Setup] Installing dependencies...
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
echo [ESP32 Setup] Done!
|
||||||
|
echo To activate environment later: call .venv\Scripts\activate.bat
|
||||||
|
|
||||||
|
endlocal
|
||||||
|
pause
|
||||||
Reference in New Issue
Block a user