Adding environment setup and instructions
This commit is contained in:
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -35,7 +35,8 @@
|
||||
"semphr.h": "c",
|
||||
"lv_spinbox.h": "c",
|
||||
"lv_slider.h": "c",
|
||||
"lv_menu.h": "c"
|
||||
"lv_menu.h": "c",
|
||||
"stream_buffer.h": "c"
|
||||
},
|
||||
"git.ignoreLimitWarning": true
|
||||
}
|
||||
|
||||
211
README.md
Normal file
211
README.md
Normal file
@@ -0,0 +1,211 @@
|
||||
## 🐳 ESP-IDF Dockerized Development Environment (Windows)
|
||||
|
||||
This project includes a fully containerized [ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/index.html) development environment using **Docker** and **Visual Studio Code**.
|
||||
|
||||
Follow these instructions to set up, build, and flash the firmware inside a VS Code **Dev Container** on **Windows**.
|
||||
|
||||
---
|
||||
|
||||
### ✅ Prerequisites
|
||||
Ensure the following are installed on your system:
|
||||
|
||||
1. [**Docker Desktop for Windows**](https://www.docker.com/products/docker-desktop)
|
||||
|
||||
* Enable **WSL 2 backend** during installation.
|
||||
2. [**Visual Studio Code**](https://code.visualstudio.com/)
|
||||
3. [**Dev Containers Extension**](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
|
||||
|
||||
* In VS Code: `Extensions → Search "Dev Containers" → Install`
|
||||
4. [**Espressif IDF Extension** for VS Code](https://marketplace.visualstudio.com/items?itemName=espressif.esp-idf-extension)
|
||||
|
||||
* In VS Code: `Extensions → Search "ESP-IDF" → Install`
|
||||
|
||||
> 💡 **Optional (recommended):** Install [WSL 2 with Ubuntu](https://learn.microsoft.com/en-us/windows/wsl/install) for improved Linux compatibility inside Docker.
|
||||
|
||||
---
|
||||
|
||||
### 🚀 Getting Started
|
||||
|
||||
#### 1. Clone this repository
|
||||
|
||||
```bash
|
||||
git clone https://git.sparksoftdesign.com/firstpass/soundshot.git
|
||||
cd soundshot
|
||||
```
|
||||
---
|
||||
You can also clone with TortoiseGit or VS Code directly.
|
||||
#### 2. Open in Visual Studio Code
|
||||
|
||||
From the project root:
|
||||
|
||||
```bash
|
||||
code .
|
||||
```
|
||||
|
||||
> Ensure you're opening the folder that contains `.devcontainer/`.
|
||||
|
||||
---
|
||||
|
||||
#### 3. Reopen in Dev Container
|
||||
|
||||
In VS Code:
|
||||
|
||||
* Press `F1` or `Ctrl+Shift+P`
|
||||
* Run: **Dev Containers: Reopen in Container**
|
||||
|
||||
VS Code will:
|
||||
|
||||
* Build the Docker image (based on the provided `Dockerfile`)
|
||||
* Set up the ESP-IDF environment
|
||||
* Install extensions automatically
|
||||
|
||||
---
|
||||
|
||||
#### 4. Verify Environment
|
||||
|
||||
Once setup is complete:
|
||||
|
||||
* A terminal should launch inside the container
|
||||
* Run:
|
||||
|
||||
```bash
|
||||
idf.py --version
|
||||
```
|
||||
|
||||
to confirm ESP-IDF is active and available.
|
||||
|
||||
---
|
||||
|
||||
#### 5. Build the Firmware
|
||||
|
||||
Inside the container’s terminal:
|
||||
|
||||
```bash
|
||||
idf.py build
|
||||
```
|
||||
|
||||
You should see standard ESP-IDF build output and a `.bin` firmware file in the `build/` directory.
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 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`
|
||||
|
||||
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,5 +1,5 @@
|
||||
idf_component_register(SRCS "system.c" "bubble.c" "keypad.c" "main.c"
|
||||
"bt_app_core.c"
|
||||
idf_component_register(SRCS "bt_app.c" "system.c" "bubble.c" "keypad.c" "main.c"
|
||||
|
||||
"gui.c"
|
||||
"lsm6dsv.c"
|
||||
INCLUDE_DIRS "."
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/stream_buffer.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "bt_app_core.h"
|
||||
#include "bt_app.h"
|
||||
#include "system.h"
|
||||
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
@@ -368,18 +370,215 @@ static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
|
||||
bt_app_work_dispatch(bt_app_av_sm_hdlr, event, param, sizeof(esp_a2d_cb_param_t), NULL);
|
||||
}
|
||||
|
||||
static uint8_t btData[512];
|
||||
|
||||
static void fillBuffer(uint8_t *data, int32_t len)
|
||||
{
|
||||
|
||||
|
||||
#define SAMPLE_RATE 44100
|
||||
#define TONE_FREQ 440.0f // A4
|
||||
#define FADE_FREQ 1.0f // 1 Hz fade L->R
|
||||
#define STREAM_BUF_SIZE (8192)
|
||||
#define CHUNK_SIZE (512)
|
||||
|
||||
StreamBufferHandle_t audio_stream_buf;
|
||||
|
||||
void generate_synth_pcm(uint8_t *buf, int len) {
|
||||
static float phase = 0.0f;
|
||||
static float fade_phase = 0.0f;
|
||||
|
||||
int16_t *samples = (int16_t *)buf;
|
||||
int samples_needed = len / 4; // 4 bytes per stereo frame (2 bytes L, 2 bytes R)
|
||||
|
||||
for (int i = 0; i < samples_needed; i++) {
|
||||
// Fade L/R amplitude: 0..1 for L, inverted for R
|
||||
float fade = (sinf(2 * M_PI * fade_phase) + 1.0f) * 0.5f;
|
||||
|
||||
// Sine wave sample
|
||||
float sample = sinf(2 * M_PI * phase);
|
||||
|
||||
int16_t left = (int16_t)(sample * fade * 32767);
|
||||
int16_t right = (int16_t)(sample * (1.0f - fade) * 32767);
|
||||
|
||||
samples[i * 2 + 0] = left;
|
||||
samples[i * 2 + 1] = right;
|
||||
|
||||
// Advance phases
|
||||
phase += TONE_FREQ / SAMPLE_RATE;
|
||||
if (phase >= 1.0f) phase -= 1.0f;
|
||||
|
||||
fade_phase += FADE_FREQ / SAMPLE_RATE;
|
||||
if (fade_phase >= 1.0f) fade_phase -= 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
#define MIN_RATE_HZ 1.0f
|
||||
#define MAX_RATE_HZ 440.0f
|
||||
#define CLICK_AMPLITUDE 32000 // 16-bit
|
||||
|
||||
static float click_timer = 0.0f;
|
||||
|
||||
void generate_synth_clicks(uint8_t *buf, int len, float balance) {
|
||||
|
||||
int16_t *samples = (int16_t *)buf;
|
||||
int samples_needed = len / 4;
|
||||
|
||||
float abs_balance = fabsf(balance);
|
||||
float rate_hz = MIN_RATE_HZ * powf(MAX_RATE_HZ / MIN_RATE_HZ, abs_balance);
|
||||
float samples_per_click = SAMPLE_RATE / rate_hz;
|
||||
|
||||
for (int i = 0; i < samples_needed; i++) {
|
||||
int16_t left = 0;
|
||||
int16_t right = 0;
|
||||
|
||||
if (click_timer <= 0.0f) {
|
||||
// Insert a short pulse: single sample spike
|
||||
if (balance < 0) {
|
||||
left = CLICK_AMPLITUDE;
|
||||
} else if (balance > 0) {
|
||||
right = CLICK_AMPLITUDE;
|
||||
}
|
||||
click_timer += samples_per_click;
|
||||
}
|
||||
|
||||
click_timer -= 1.0f;
|
||||
|
||||
samples[i * 2 + 0] = left;
|
||||
samples[i * 2 + 1] = right;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void audio_producer_task(void *pvParameters) {
|
||||
uint8_t chunk[CHUNK_SIZE];
|
||||
|
||||
int core_id = xPortGetCoreID();
|
||||
|
||||
ESP_LOGI("Producer", "Running on core %d", core_id);
|
||||
|
||||
system_subscribe(xTaskGetCurrentTaskHandle());
|
||||
#if 0
|
||||
|
||||
|
||||
while (1) {
|
||||
generate_synth_pcm(chunk, sizeof(chunk));
|
||||
|
||||
size_t sent = xStreamBufferSend(audio_stream_buf, chunk, sizeof(chunk), portMAX_DELAY);
|
||||
|
||||
if (sent < sizeof(chunk)) {
|
||||
ESP_LOGW(BT_APP_CORE_TAG, "Dropped %d bytes", sizeof(chunk) - sent);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static float phase = 0.0f;
|
||||
|
||||
float balance = 0.0f; // -1.0 = left, +1.0 = right
|
||||
|
||||
uint32_t raw_value;
|
||||
uint32_t notifiedBits = 0;
|
||||
|
||||
while (1) {
|
||||
// Non-blocking check for new notification:
|
||||
|
||||
// clear on entry (first param), wait for any bit, block forever
|
||||
xTaskNotifyWait(
|
||||
0, // clear any old bits on entry
|
||||
0, // clear bits on exit
|
||||
¬ifiedBits,
|
||||
0);
|
||||
|
||||
if (notifiedBits & EM_EVENT_NEW_DATA)
|
||||
{
|
||||
ImuData_t d = system_getImuData();
|
||||
|
||||
if (fabs(d.raw[system_getPrimaryAxis()]) > 45.0f)
|
||||
{
|
||||
balance = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
balance = -d.angle / MAX_INDICATION_ANGLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (balance > 1.0f)
|
||||
{
|
||||
balance = 1.0f;
|
||||
}
|
||||
else
|
||||
if (balance < -1.0f)
|
||||
{
|
||||
balance = -1.0f;
|
||||
}
|
||||
generate_synth_clicks(chunk, sizeof(chunk), balance);
|
||||
|
||||
#if 0
|
||||
// Synthesize audio using latest balance
|
||||
int16_t *samples = (int16_t *)chunk;
|
||||
int samples_needed = CHUNK_SIZE / 4;
|
||||
|
||||
for (int i = 0; i < samples_needed; i++) {
|
||||
float sample = sinf(2 * M_PI * phase);
|
||||
|
||||
float left_gain = 0.5f * (1.0f - balance);
|
||||
float right_gain = 0.5f * (1.0f + balance);
|
||||
|
||||
int16_t left = (int16_t)(sample * left_gain * 32767);
|
||||
int16_t right = (int16_t)(sample * right_gain * 32767);
|
||||
|
||||
samples[i * 2 + 0] = left;
|
||||
samples[i * 2 + 1] = right;
|
||||
|
||||
phase += TONE_FREQ / SAMPLE_RATE;
|
||||
if (phase >= 1.0f) phase -= 1.0f;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Push chunk to FIFO
|
||||
xStreamBufferSend(audio_stream_buf, chunk, sizeof(chunk), portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
/* generate some random noise to simulate source audio */
|
||||
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
|
||||
{
|
||||
size_t bytes_read = xStreamBufferReceive(audio_stream_buf, data, len, 0);
|
||||
|
||||
if (bytes_read < len) {
|
||||
memset(data + bytes_read, 0, len - bytes_read); // fill silence
|
||||
}
|
||||
|
||||
return len;
|
||||
#if 0
|
||||
if (data == NULL || len < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t *p_buf = (int16_t *)data;
|
||||
for (int i = 0; i < (len >> 1); i++) {
|
||||
p_buf[i] = rand() % (1 << 16);
|
||||
}
|
||||
|
||||
return len;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/* Generate a continuous 440Hz sine wave */
|
||||
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
|
||||
{
|
||||
static double phase = 0.0;
|
||||
|
||||
if (data == NULL || len < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t *p_buf = (int16_t *)data;
|
||||
for (int i = 0; i < (len >> 1); i++) {
|
||||
p_buf[i] = rand() % (1 << 16);
|
||||
}
|
||||
|
||||
return len;
|
||||
#if 0
|
||||
static double phase = 0.0;
|
||||
const double frequency = 440.0; // A4 tone (440 Hz)
|
||||
const double sample_rate = 44100.0; // 44.1 kHz sample rate
|
||||
const double phase_increment = 2.0 * M_PI * frequency / sample_rate;
|
||||
@@ -406,7 +605,9 @@ static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
|
||||
}
|
||||
}
|
||||
return len;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static void bt_app_a2d_heart_beat(TimerHandle_t arg)
|
||||
{
|
||||
@@ -551,6 +752,7 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
|
||||
}
|
||||
case APP_AV_MEDIA_STATE_STARTED: {
|
||||
if (event == BT_APP_HEART_BEAT_EVT) {
|
||||
#if 0
|
||||
/* stop media after 10 heart beat intervals */
|
||||
if (++s_intv_cnt >= 10) {
|
||||
ESP_LOGI(BT_AV_TAG, "a2dp media suspending...");
|
||||
@@ -558,6 +760,7 @@ static void bt_app_av_media_proc(uint16_t event, void *param)
|
||||
s_media_state = APP_AV_MEDIA_STATE_STOPPING;
|
||||
s_intv_cnt = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -791,6 +994,10 @@ static void bt_app_task_handler(void *arg)
|
||||
{
|
||||
bt_app_msg_t msg;
|
||||
|
||||
int core_id = xPortGetCoreID();
|
||||
|
||||
ESP_LOGI("MY_TASK", "Running on core %d", core_id);
|
||||
|
||||
for (;;) {
|
||||
/* receive message from work queue and handle it */
|
||||
if (pdTRUE == xQueueReceive(s_bt_app_task_queue, &msg, (TickType_t)portMAX_DELAY)) {
|
||||
@@ -846,7 +1053,9 @@ bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, i
|
||||
void bt_app_task_start_up(void)
|
||||
{
|
||||
s_bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
|
||||
xTaskCreate(bt_app_task_handler, "BtAppTask", 4096, NULL, 10, &s_bt_app_task_handle);
|
||||
//xTaskCreate(bt_app_task_handler, "BtAppTask", 8192, NULL, 10, &s_bt_app_task_handle);
|
||||
|
||||
xTaskCreatePinnedToCore(bt_app_task_handler, "BtAppTask", 8192, NULL, 10, NULL, 1);
|
||||
}
|
||||
|
||||
void bt_app_task_shut_down(void)
|
||||
@@ -867,7 +1076,27 @@ void bt_app_init(void)
|
||||
esp_err_t ret;
|
||||
char bda_str[18] = {0};
|
||||
|
||||
fillBuffer(btData, 512);
|
||||
|
||||
//esp_err_t esp_bredr_tx_power_get(esp_power_level_t *min_power_level, esp_power_level_t *max_power_level)
|
||||
esp_power_level_t pmin;
|
||||
esp_power_level_t pmax;
|
||||
esp_bredr_tx_power_get(&pmin, &pmax);
|
||||
|
||||
ESP_LOGI(BT_APP_CORE_TAG, "BT Power min = %d\nBT Power max = %d", pmin, pmax);
|
||||
|
||||
//pmin = ESP_PWR_LVL_P6;
|
||||
//pmax = ESP_PWR_LVL_P7;
|
||||
pmin = ESP_PWR_LVL_N12;
|
||||
pmax = ESP_PWR_LVL_N9;
|
||||
|
||||
esp_err_t err = esp_bredr_tx_power_set(pmin, pmax);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(BT_APP_CORE_TAG, "Failed to set TX power: %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
esp_bredr_tx_power_get(&pmin, &pmax);
|
||||
|
||||
ESP_LOGI(BT_APP_CORE_TAG, "BT Power min = %d\nBT Power max = %d", pmin, pmax);
|
||||
|
||||
/*
|
||||
* This example only uses the functions of Classical Bluetooth.
|
||||
@@ -885,6 +1114,10 @@ void bt_app_init(void)
|
||||
return;
|
||||
}
|
||||
|
||||
err = esp_bredr_tx_power_set(pmin, pmax);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(BT_APP_CORE_TAG, "Failed to set TX power: %s", esp_err_to_name(err));
|
||||
}
|
||||
esp_bluedroid_config_t bluedroid_cfg = BT_BLUEDROID_INIT_CONFIG_DEFAULT();
|
||||
#if (CONFIG_EXAMPLE_SSP_ENABLED == false)
|
||||
bluedroid_cfg.ssp_en = false;
|
||||
@@ -918,4 +1151,19 @@ void bt_app_init(void)
|
||||
bt_app_task_start_up();
|
||||
/* Bluetooth device name, connection mode and profile set up */
|
||||
bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_STACK_UP_EVT, NULL, 0, NULL);
|
||||
|
||||
|
||||
|
||||
audio_stream_buf = xStreamBufferCreate(STREAM_BUF_SIZE, 1);
|
||||
assert(audio_stream_buf != NULL);
|
||||
|
||||
//xTaskCreate(audio_producer_task, "audio_producer", 4096, NULL, 5, NULL);
|
||||
xTaskCreatePinnedToCore(audio_producer_task, "audio_producer", 4096, NULL, 5, NULL, 1);
|
||||
|
||||
ESP_LOGI(BT_APP_CORE_TAG, "Audio synth producer started");
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
#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
|
||||
|
||||
|
||||
|
||||
92
main/gui.c
92
main/gui.c
@@ -105,9 +105,9 @@ static void create_lvgl_demo(void)
|
||||
lvgl_port_lock(0);
|
||||
// Create a screen with black background
|
||||
lv_obj_t *scr = lv_scr_act();
|
||||
//create_menu(scr);
|
||||
|
||||
createBubble(scr);
|
||||
build_scrollable_menu();
|
||||
//build_scrollable_menu();
|
||||
|
||||
lvgl_port_unlock();
|
||||
|
||||
@@ -167,8 +167,8 @@ static void lvgl_init(void)
|
||||
#if 1
|
||||
const lvgl_port_cfg_t lvgl_cfg = {
|
||||
.task_priority = 4, // LVGL task priority
|
||||
.task_stack = 32768, // LVGL task stack size
|
||||
.task_affinity = -1, // LVGL task can run on any core
|
||||
.task_stack = 16384, // LVGL task stack size
|
||||
.task_affinity = 0, // LVGL task can run on any core
|
||||
.task_max_sleep_ms = 500, // Maximum sleep in LVGL task
|
||||
.timer_period_ms = 5 // LVGL timer period
|
||||
};
|
||||
@@ -180,7 +180,7 @@ static void lvgl_init(void)
|
||||
.io_handle = io_handle,
|
||||
.panel_handle = panel_handle,
|
||||
.buffer_size = LCD_H_RES * LCD_V_RES * 2,
|
||||
.double_buffer = true,
|
||||
.double_buffer = false,
|
||||
.hres = LCD_H_RES,
|
||||
.vres = LCD_V_RES,
|
||||
.monochrome = false,
|
||||
@@ -219,15 +219,10 @@ static void createBubble(lv_obj_t * scr)
|
||||
_bubble = level;
|
||||
}
|
||||
|
||||
void ui_test()
|
||||
{
|
||||
lv_obj_t *label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(label, "Hello, LVGL 9.2!");
|
||||
lv_obj_center(label);
|
||||
}
|
||||
|
||||
void gui_start(void)
|
||||
{
|
||||
|
||||
// Initialize LCD
|
||||
lcd_init();
|
||||
|
||||
@@ -236,7 +231,6 @@ void gui_start(void)
|
||||
|
||||
// Create UI
|
||||
create_lvgl_demo();
|
||||
|
||||
|
||||
keypad_start();
|
||||
|
||||
@@ -333,21 +327,9 @@ static void refresh_highlight(void) {
|
||||
next = lv_obj_get_child(page, index);
|
||||
}
|
||||
|
||||
// for(int i = 0; i < ITEM_COUNT; i++) {
|
||||
// if(i == selected_idx) {
|
||||
// lv_obj_set_style_bg_color(btn_array[i], lv_color_hex(0xFF8800), 0);
|
||||
// lv_obj_set_style_text_color(lv_obj_get_child(btn_array[i],0),
|
||||
// lv_color_white(), 0);
|
||||
// } else {
|
||||
// lv_obj_set_style_bg_color(btn_array[i], lv_color_white(), 0);
|
||||
// lv_obj_set_style_text_color(lv_obj_get_child(btn_array[i],0),
|
||||
// lv_color_black(), 0);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (selected)
|
||||
{
|
||||
lv_obj_scroll_to_view(selected, LV_ANIM_ON);
|
||||
lv_obj_scroll_to_view(selected, LV_ANIM_ON);
|
||||
}
|
||||
|
||||
lvgl_port_unlock();
|
||||
@@ -521,40 +503,7 @@ static void build_scrollable_menu(void) {
|
||||
addMenuItem(calMenu, "Exit");
|
||||
|
||||
_currentPage = main;
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
for(int i = 0; i < ITEM_COUNT; i++) {
|
||||
// create a full-width button in that section
|
||||
lv_obj_t * btn = lv_btn_create(main);
|
||||
lv_obj_set_size(btn, LV_PCT(100), ROW_H);
|
||||
|
||||
// style it just like your old list
|
||||
lv_obj_set_style_bg_color(btn, lv_color_white(), 0);
|
||||
lv_obj_set_style_radius(btn, 0, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(btn, 0, LV_PART_MAIN);
|
||||
lv_obj_clear_flag(btn, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
|
||||
// label & center
|
||||
lv_obj_t * lbl = lv_label_create(btn);
|
||||
lv_label_set_text(lbl, items[i]);
|
||||
lv_obj_set_style_radius(lbl, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||
lv_obj_set_style_border_width(lbl, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||
//lv_obj_center(lbl);
|
||||
|
||||
// click callback
|
||||
lv_obj_add_event_cb(btn, btn_click_cb, LV_EVENT_CLICKED, NULL);
|
||||
|
||||
// save for highlight/scroll
|
||||
btn_array[i] = btn;
|
||||
}
|
||||
|
||||
// lv_obj_t * content = lv_obj_get_child(page, 0);
|
||||
// lv_obj_set_style_radius(content, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||
// lv_obj_set_style_border_width(content, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||
#endif
|
||||
// 6) Initial highlight
|
||||
selected_idx = 0;
|
||||
refresh_highlight();
|
||||
@@ -563,6 +512,7 @@ static void build_scrollable_menu(void) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void gui_task(void)
|
||||
{
|
||||
system_subscribe(xTaskGetCurrentTaskHandle());
|
||||
@@ -571,8 +521,12 @@ static void gui_task(void)
|
||||
QueueHandle_t q = keypad_getQueue();
|
||||
uint32_t ev = 0;
|
||||
|
||||
LOCK();
|
||||
// _mode = GUI_MENU;
|
||||
// lv_obj_remove_flag(_menu, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_remove_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(_menu, LV_OBJ_FLAG_HIDDEN);
|
||||
//lv_obj_add_flag(_menu, LV_OBJ_FLAG_HIDDEN);
|
||||
UNLOCK();
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -581,6 +535,19 @@ static void gui_task(void)
|
||||
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;
|
||||
}
|
||||
#if 0
|
||||
case (KEY0 << KEY_SHORT_PRESS):
|
||||
|
||||
if (_mode == GUI_MENU)
|
||||
@@ -590,7 +557,9 @@ static void gui_task(void)
|
||||
ESP_LOGI(TAG, "MAIN: Button 1 SHORT");
|
||||
break;
|
||||
case (KEY0 << KEY_LONG_PRESS):
|
||||
{
|
||||
|
||||
|
||||
if (_mode != GUI_MENU)
|
||||
{
|
||||
_mode = GUI_MENU;
|
||||
@@ -605,8 +574,8 @@ static void gui_task(void)
|
||||
// lv_obj_remove_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
|
||||
// lv_obj_add_flag(_menu, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case (KEY1 << KEY_SHORT_PRESS):
|
||||
{
|
||||
if (_mode == GUI_MENU)
|
||||
@@ -619,6 +588,7 @@ static void gui_task(void)
|
||||
ESP_LOGI(TAG, "MAIN: Button 2 LONG");
|
||||
gpio_set_level(PIN_NUM_nON, 0);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -633,7 +603,7 @@ static void gui_task(void)
|
||||
0xFFFFFFFF, // clear any old bits on entry
|
||||
0xFFFFFFFF, // clear bits on exit
|
||||
¬ifiedBits,
|
||||
pdMS_TO_TICKS(10));
|
||||
pdMS_TO_TICKS(100));
|
||||
|
||||
if (notifiedBits & EM_EVENT_NEW_DATA)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,8 @@ typedef enum
|
||||
#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);
|
||||
|
||||
81
main/main.c
81
main/main.c
@@ -21,7 +21,7 @@
|
||||
#include "nvs_flash.h"
|
||||
|
||||
|
||||
#include "bt_app_core.h"
|
||||
#include "bt_app.h"
|
||||
#include "lsm6dsv.h"
|
||||
#include "gui.h"
|
||||
#include "gpio.h"
|
||||
@@ -71,8 +71,9 @@ static void init_gpio(void)
|
||||
|
||||
|
||||
// Configure output GPIO
|
||||
io_conf.pin_bit_mask = (1ULL << PIN_NUM_LED_1);
|
||||
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);
|
||||
@@ -86,7 +87,8 @@ static void init_gpio(void)
|
||||
|
||||
io_conf.pin_bit_mask = (1ULL << PIN_NUM_nON);
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
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
|
||||
@@ -95,8 +97,8 @@ static void init_gpio(void)
|
||||
|
||||
// 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);
|
||||
@@ -116,7 +118,7 @@ static void imu_task(void *pvParameters) {
|
||||
ImuData_t imu;
|
||||
|
||||
LowPassFilter lpf;
|
||||
LPF_Init(&lpf, 0.2, 0);
|
||||
LPF_Init(&lpf, FILTER_COEFF, 0);
|
||||
|
||||
while (1) {
|
||||
|
||||
@@ -170,20 +172,20 @@ static void imu_task(void *pvParameters) {
|
||||
|
||||
float angle;
|
||||
|
||||
if (imu.raw[ANGLE_XY] > MAX_INDICATION_ANGLE)
|
||||
|
||||
angle = system_getAngle();
|
||||
|
||||
if (angle > MAX_INDICATION_ANGLE)
|
||||
{
|
||||
angle = MAX_INDICATION_ANGLE;
|
||||
}
|
||||
else
|
||||
if (imu.raw[ANGLE_XY] > MAX_INDICATION_ANGLE)
|
||||
if (angle < -MAX_INDICATION_ANGLE)
|
||||
{
|
||||
angle = -MAX_INDICATION_ANGLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = imu.raw[ANGLE_XY];
|
||||
}
|
||||
|
||||
// low pass filter the angle measurement
|
||||
imu.angle = LPF_Update(&lpf, angle);
|
||||
|
||||
//imu.filtered[ANGLE_XY] = LPF_Update(&lpf, imu.raw[ANGLE_XY]);
|
||||
@@ -197,7 +199,7 @@ static void imu_task(void *pvParameters) {
|
||||
#if 0
|
||||
snprintf(data_str, sizeof(data_str),
|
||||
"(%.1f, %.1f, %.1f) (%.2f, %.2f, %.2f)",
|
||||
xz, yz, xy,
|
||||
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
|
||||
@@ -218,12 +220,12 @@ 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);
|
||||
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();
|
||||
|
||||
@@ -241,26 +243,49 @@ void app_main(void)
|
||||
|
||||
|
||||
|
||||
bt_app_init();
|
||||
|
||||
|
||||
gui_start();
|
||||
|
||||
gpio_set_level(PIN_NUM_LED_2, 1);
|
||||
|
||||
|
||||
//bt_app_init();
|
||||
|
||||
#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) {
|
||||
|
||||
// int level = gpio_get_level(PIN_NUM_BUTTON_1); // Read input GPIO
|
||||
// gpio_set_level(PIN_NUM_LED_1, level);
|
||||
if (xQueueReceive(q, &ev, pdMS_TO_TICKS(10)) == pdTRUE)
|
||||
{
|
||||
switch (ev)
|
||||
{
|
||||
case (KEY_UP << KEY_LONG_PRESS):
|
||||
{
|
||||
system_setZeroAngle();
|
||||
break;
|
||||
}
|
||||
|
||||
//gpio_set_level(PIN_NUM_nON, (level ? 0 : 1));
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
//gui_service();
|
||||
case (KEY_DOWN << KEY_LONG_PRESS):
|
||||
{
|
||||
system_clearZeroAngle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#else
|
||||
while (1)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -8,12 +8,77 @@ 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);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#define DISABLE_GUI
|
||||
|
||||
enum
|
||||
{
|
||||
ANGLE_XY = 0,
|
||||
@@ -27,11 +29,15 @@ typedef struct SystemState_s
|
||||
|
||||
EventGroupHandle_t event;
|
||||
|
||||
float zeroAngle;
|
||||
int primaryAxis;
|
||||
|
||||
} SystemState_t;
|
||||
|
||||
|
||||
#define MAX_INDICATION_ANGLE 10.0f
|
||||
#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)
|
||||
@@ -49,6 +55,13 @@ 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);
|
||||
|
||||
|
||||
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
|
||||
|
||||
23
sdkconfig
23
sdkconfig
@@ -353,14 +353,14 @@ CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
|
||||
# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ="40m"
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set
|
||||
# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="2MB"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
|
||||
# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set
|
||||
CONFIG_ESPTOOLPY_BEFORE_RESET=y
|
||||
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
|
||||
@@ -393,8 +393,8 @@ CONFIG_EXAMPLE_SSP_ENABLED=y
|
||||
#
|
||||
# Compiler options
|
||||
#
|
||||
CONFIG_COMPILER_OPTIMIZATION_DEBUG=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set
|
||||
# CONFIG_COMPILER_OPTIMIZATION_DEBUG is not set
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
# CONFIG_COMPILER_OPTIMIZATION_PERF is not set
|
||||
# CONFIG_COMPILER_OPTIMIZATION_NONE is not set
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
|
||||
@@ -1448,7 +1448,6 @@ CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1
|
||||
#
|
||||
# Port
|
||||
#
|
||||
CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y
|
||||
# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
|
||||
CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS=y
|
||||
# CONFIG_FREERTOS_TASK_PRE_DELETION_HOOK is not set
|
||||
@@ -1497,7 +1496,7 @@ CONFIG_HEAP_TRACING_OFF=y
|
||||
# CONFIG_HEAP_TRACING_TOHOST is not set
|
||||
# CONFIG_HEAP_USE_HOOKS is not set
|
||||
# CONFIG_HEAP_TASK_TRACKING is not set
|
||||
# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set
|
||||
CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS=y
|
||||
# CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH is not set
|
||||
# end of Heap memory debugging
|
||||
|
||||
@@ -2496,11 +2495,11 @@ CONFIG_LOG_BOOTLOADER_LEVEL=3
|
||||
CONFIG_FLASHMODE_DIO=y
|
||||
# CONFIG_FLASHMODE_DOUT is not set
|
||||
CONFIG_MONITOR_BAUD=115200
|
||||
CONFIG_OPTIMIZATION_LEVEL_DEBUG=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y
|
||||
# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set
|
||||
# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set
|
||||
# CONFIG_OPTIMIZATION_LEVEL_DEBUG is not set
|
||||
# CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set
|
||||
# CONFIG_COMPILER_OPTIMIZATION_DEFAULT is not set
|
||||
CONFIG_OPTIMIZATION_LEVEL_RELEASE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
|
||||
CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y
|
||||
# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set
|
||||
# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set
|
||||
|
||||
9
sdkconfig.defaults
Normal file
9
sdkconfig.defaults
Normal file
@@ -0,0 +1,9 @@
|
||||
# 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
|
||||
2888
sdkconfig.old
Normal file
2888
sdkconfig.old
Normal file
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