SeedStudioESP32S3 compatible only
This commit is contained in:
+6
-1
@@ -4,7 +4,12 @@ cmake_minimum_required(VERSION 3.16.0)
|
||||
set(EXTRA_COMPONENT_DIRS src)
|
||||
|
||||
# Use custom partition table with SPIFFS
|
||||
set(PARTITION_CSV_PATH "${CMAKE_SOURCE_DIR}/partitions.csv")
|
||||
# Use partitions-s3.csv for ESP32-S3 builds
|
||||
if(IDF_TARGET STREQUAL "esp32s3")
|
||||
set(PARTITION_CSV_PATH "${CMAKE_SOURCE_DIR}/partitions-s3.csv")
|
||||
else()
|
||||
set(PARTITION_CSV_PATH "${CMAKE_SOURCE_DIR}/partitions.csv")
|
||||
endif()
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(esp32-wand-gateway)
|
||||
|
||||
+17
-5
@@ -37,7 +37,12 @@ if [ -f "model.tflite" ]; then
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Set target to ESP32-S3
|
||||
# Clean previous build to ensure fresh configuration
|
||||
echo "Cleaning previous build configuration..."
|
||||
#rm -rf build/
|
||||
#rm -f sdkconfig sdkconfig.old
|
||||
|
||||
# Set target to ESP32-S3 (this will copy sdkconfig.esp32s3 to build/sdkconfig)
|
||||
echo "Setting target to ESP32-S3..."
|
||||
idf.py set-target esp32s3
|
||||
|
||||
@@ -49,7 +54,7 @@ export IDF_EXTRA_PARTITION_SUBTYPES=""
|
||||
# Build the project
|
||||
echo ""
|
||||
echo "Building firmware..."
|
||||
idf.py -D PARTITION_TABLE_FILENAME=partitions-s3.csv build
|
||||
idf.py build
|
||||
|
||||
# Check if build succeeded
|
||||
if [ $? -ne 0 ]; then
|
||||
@@ -69,12 +74,19 @@ echo ""
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo ""
|
||||
echo "Flashing firmware and SPIFFS partition..."
|
||||
echo "(Using slower speed for VMware USB compatibility)"
|
||||
echo ""
|
||||
echo "Put device in bootloader mode:"
|
||||
echo " 1. Hold BOOT button (tiny button near USB)"
|
||||
echo " 2. Press and release RESET button"
|
||||
echo " 3. Release BOOT button"
|
||||
echo ""
|
||||
read -p "Press Enter when ready to flash..."
|
||||
|
||||
echo "Waiting 3 seconds for device to enumerate..."
|
||||
sleep 3
|
||||
|
||||
# Flash everything: bootloader, partition table, app, and SPIFFS
|
||||
# Use --no-stub and slower baud for VMware USB passthrough compatibility
|
||||
idf.py -p "$PORT" -b 115200 flash --no-stub
|
||||
idf.py -p "$PORT" -b 115200 flash
|
||||
|
||||
# Flash SPIFFS partition with model if it exists
|
||||
if [ -f "data/model.tflite" ]; then
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
#include "esp_bt.h"
|
||||
#include "spell_detector.h"
|
||||
#include "wand_commands.h"
|
||||
#include "wand_protocol.h"
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
// USB HID Support - enabled for ESP32-S3 composite HID + CDC (logs)
|
||||
#define USE_USB_HID_DEVICE 1
|
||||
// USB HID Support - disabled to reduce interference with BLE/WiFi
|
||||
#define USE_USB_HID_DEVICE 0
|
||||
|
||||
// Wand BLE UUIDs
|
||||
#define WAND_SERVICE_UUID "57420001-587e-48a0-974c-544d6163c577"
|
||||
|
||||
@@ -48,6 +48,7 @@ struct IMUSample;
|
||||
|
||||
// Button state flags
|
||||
#define BUTTON_ALL_PRESSED 0x0F
|
||||
#define BUTTON_MIN_FOR_TRACKING 3 // Minimum buttons pressed to start tracking (3 out of 4)
|
||||
|
||||
// Macro system opcodes
|
||||
#define MACRO_CONTROL 0x68
|
||||
|
||||
@@ -928,17 +928,11 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
|
||||
#
|
||||
# Partition Table
|
||||
#
|
||||
# default:
|
||||
# CONFIG_PARTITION_TABLE_SINGLE_APP is not set
|
||||
# default:
|
||||
# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set
|
||||
# default:
|
||||
# CONFIG_PARTITION_TABLE_TWO_OTA is not set
|
||||
# default:
|
||||
# CONFIG_PARTITION_TABLE_TWO_OTA_LARGE is not set
|
||||
# default:
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
# default:
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-s3.csv"
|
||||
# default:
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions-s3.csv"
|
||||
@@ -1428,15 +1422,11 @@ CONFIG_BT_NIMBLE_EXTRA_ADV_FIELDS=y
|
||||
#
|
||||
# default:
|
||||
CONFIG_BT_CTRL_MODE_EFF=1
|
||||
CONFIG_BT_CTRL_BLE_MAX_ACT=4
|
||||
# default:
|
||||
CONFIG_BT_CTRL_BLE_MAX_ACT=6
|
||||
# default:
|
||||
CONFIG_BT_CTRL_BLE_MAX_ACT_EFF=6
|
||||
# default:
|
||||
CONFIG_BT_CTRL_BLE_STATIC_ACL_TX_BUF_NB=0
|
||||
# default:
|
||||
CONFIG_BT_CTRL_BLE_MAX_ACT_EFF=4
|
||||
CONFIG_BT_CTRL_BLE_STATIC_ACL_TX_BUF_NB=6
|
||||
CONFIG_BT_CTRL_PINNED_TO_CORE_0=y
|
||||
# default:
|
||||
# CONFIG_BT_CTRL_PINNED_TO_CORE_1 is not set
|
||||
# default:
|
||||
CONFIG_BT_CTRL_PINNED_TO_CORE=0
|
||||
@@ -1728,7 +1718,6 @@ CONFIG_ESP_TLS_DYN_BUF_STRATEGY_SUPPORTED=y
|
||||
#
|
||||
# default:
|
||||
CONFIG_ESP_COEX_ENABLED=y
|
||||
# default:
|
||||
CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y
|
||||
# default:
|
||||
# CONFIG_ESP_COEX_POWER_MANAGEMENT is not set
|
||||
@@ -2331,7 +2320,6 @@ CONFIG_ESP_NETIF_RECEIVE_REPORT_ERRORS=y
|
||||
#
|
||||
# default:
|
||||
CONFIG_ESP_PHY_ENABLED=y
|
||||
# default:
|
||||
CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
|
||||
# default:
|
||||
# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set
|
||||
@@ -2339,20 +2327,16 @@ CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
|
||||
CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20
|
||||
# default:
|
||||
CONFIG_ESP_PHY_MAX_TX_POWER=20
|
||||
# default:
|
||||
# CONFIG_ESP_PHY_REDUCE_TX_POWER is not set
|
||||
# default:
|
||||
CONFIG_ESP_PHY_ENABLE_USB=y
|
||||
# default:
|
||||
# CONFIG_ESP_PHY_ENABLE_CERT_TEST is not set
|
||||
# default:
|
||||
CONFIG_ESP_PHY_RF_CAL_PARTIAL=y
|
||||
# default:
|
||||
# CONFIG_ESP_PHY_RF_CAL_PARTIAL is not set
|
||||
# CONFIG_ESP_PHY_RF_CAL_NONE is not set
|
||||
CONFIG_ESP_PHY_RF_CAL_FULL=y
|
||||
# default:
|
||||
# CONFIG_ESP_PHY_RF_CAL_FULL is not set
|
||||
# default:
|
||||
CONFIG_ESP_PHY_CALIBRATION_MODE=0
|
||||
CONFIG_ESP_PHY_CALIBRATION_MODE=2
|
||||
# default:
|
||||
CONFIG_ESP_PHY_PLL_TRACK_PERIOD_MS=1000
|
||||
# default:
|
||||
@@ -2370,7 +2354,6 @@ CONFIG_ESP_PHY_IRAM_OPT=y
|
||||
#
|
||||
# default:
|
||||
# CONFIG_PM_SLEEP_FUNC_IN_IRAM is not set
|
||||
# default:
|
||||
# CONFIG_PM_ENABLE is not set
|
||||
# default:
|
||||
# CONFIG_PM_SLP_IRAM_OPT is not set
|
||||
@@ -2390,11 +2373,9 @@ CONFIG_SPIRAM=y
|
||||
#
|
||||
# SPI RAM config
|
||||
#
|
||||
CONFIG_SPIRAM_MODE_QUAD=y
|
||||
# CONFIG_SPIRAM_MODE_OCT is not set
|
||||
# CONFIG_SPIRAM_MODE_QUAD is not set
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_TYPE_AUTO=y
|
||||
# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set
|
||||
# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
|
||||
# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set
|
||||
# default:
|
||||
CONFIG_SPIRAM_CLK_IO=30
|
||||
@@ -2406,12 +2387,13 @@ CONFIG_SPIRAM_CS_IO=26
|
||||
# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set
|
||||
# default:
|
||||
# CONFIG_SPIRAM_RODATA is not set
|
||||
# CONFIG_SPIRAM_SPEED_120M is not set
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
# CONFIG_SPIRAM_SPEED_40M is not set
|
||||
# default:
|
||||
CONFIG_SPIRAM_SPEED=80
|
||||
# default:
|
||||
# CONFIG_SPIRAM_ECC_ENABLE is not set
|
||||
# default:
|
||||
CONFIG_SPIRAM_BOOT_HW_INIT=y
|
||||
CONFIG_SPIRAM_BOOT_INIT=y
|
||||
# default:
|
||||
@@ -2487,14 +2469,11 @@ CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
|
||||
#
|
||||
# ESP System Settings
|
||||
#
|
||||
# default:
|
||||
# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_80 is not set
|
||||
# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160 is not set
|
||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||
# default:
|
||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y
|
||||
# default:
|
||||
# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240 is not set
|
||||
# default:
|
||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160
|
||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=240
|
||||
|
||||
#
|
||||
# Cache config
|
||||
@@ -2691,9 +2670,7 @@ CONFIG_ESP_TRACE_TRANSPORT_NAME="none"
|
||||
#
|
||||
# default:
|
||||
CONFIG_ESP_WIFI_ENABLED=y
|
||||
# default:
|
||||
CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=10
|
||||
# default:
|
||||
CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32
|
||||
# default:
|
||||
CONFIG_ESP_WIFI_STATIC_TX_BUFFER=y
|
||||
@@ -2713,14 +2690,12 @@ CONFIG_ESP_WIFI_DYNAMIC_RX_MGMT_BUF=0
|
||||
CONFIG_ESP_WIFI_RX_MGMT_BUF_NUM_DEF=5
|
||||
# default:
|
||||
# CONFIG_ESP_WIFI_CSI_ENABLED is not set
|
||||
# default:
|
||||
CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=y
|
||||
# default:
|
||||
CONFIG_ESP_WIFI_TX_BA_WIN=6
|
||||
# default:
|
||||
CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=y
|
||||
# default:
|
||||
CONFIG_ESP_WIFI_RX_BA_WIN=6
|
||||
CONFIG_ESP_WIFI_RX_BA_WIN=16
|
||||
# default:
|
||||
# CONFIG_ESP_WIFI_AMSDU_TX_ENABLED is not set
|
||||
# default:
|
||||
@@ -2733,11 +2708,9 @@ CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_0=y
|
||||
CONFIG_ESP_WIFI_SOFTAP_BEACON_MAX_LEN=752
|
||||
# default:
|
||||
CONFIG_ESP_WIFI_MGMT_SBUF_NUM=32
|
||||
# default:
|
||||
CONFIG_ESP_WIFI_IRAM_OPT=y
|
||||
# default:
|
||||
# CONFIG_ESP_WIFI_EXTRA_IRAM_OPT is not set
|
||||
# default:
|
||||
CONFIG_ESP_WIFI_RX_IRAM_OPT=y
|
||||
# default:
|
||||
CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y
|
||||
@@ -3323,7 +3296,7 @@ CONFIG_LWIP_TCP_QUEUE_OOSEQ=y
|
||||
# default:
|
||||
CONFIG_LWIP_TCP_OOSEQ_TIMEOUT=6
|
||||
# default:
|
||||
CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=4
|
||||
CONFIG_LWIP_TCP_OOSEQ_MAX_PBUFS=0
|
||||
# default:
|
||||
# CONFIG_LWIP_TCP_SACK_OUT is not set
|
||||
# default:
|
||||
@@ -4482,9 +4455,9 @@ CONFIG_CONSOLE_UART=y
|
||||
CONFIG_CONSOLE_UART_NUM=0
|
||||
CONFIG_CONSOLE_UART_BAUDRATE=115200
|
||||
# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_80 is not set
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_160=y
|
||||
# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240 is not set
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ=160
|
||||
# CONFIG_ESP32S3_DEFAULT_CPU_FREQ_160 is not set
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
|
||||
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ=240
|
||||
CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT=y
|
||||
CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_VIA_TEE=y
|
||||
CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=y
|
||||
@@ -4517,7 +4490,7 @@ CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32
|
||||
CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
|
||||
CONFIG_ESP32_WIFI_TX_BA_WIN=6
|
||||
CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
|
||||
CONFIG_ESP32_WIFI_RX_BA_WIN=6
|
||||
CONFIG_ESP32_WIFI_RX_BA_WIN=16
|
||||
# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set
|
||||
CONFIG_ESP32_WIFI_NVS_ENABLED=y
|
||||
CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# ESP32-S3 Specific Configuration
|
||||
# This file is automatically merged when target is set to esp32s3
|
||||
|
||||
# Flash Configuration (8MB Flash)
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="8MB"
|
||||
|
||||
# PSRAM Configuration for Seeeduino XIAO ESP32S3 (8MB OCTAL PSRAM)
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_TYPE_AUTO=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_SPIRAM_BOOT_INIT=y
|
||||
CONFIG_SPIRAM_USE_MALLOC=y
|
||||
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384
|
||||
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
|
||||
|
||||
# Partition Table
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-s3.csv"
|
||||
|
||||
# External Antenna Configuration for Seeeduino XIAO ESP32S3
|
||||
# With external antenna, use full RF calibration for best performance
|
||||
CONFIG_ESP_PHY_RF_CAL_FULL=y
|
||||
CONFIG_ESP_PHY_RF_CAL_PARTIAL=n
|
||||
CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
|
||||
|
||||
# Bluetooth/WiFi Coexistence Settings
|
||||
CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y
|
||||
CONFIG_ESP_WIFI_SW_COEXIST_PREFERENCE_BALANCE=y
|
||||
CONFIG_ESP_COEX_EXTERNAL_COEXIST_ENABLE=n
|
||||
|
||||
# BLE Settings optimized for external antenna
|
||||
CONFIG_BT_BLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1
|
||||
CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=0
|
||||
CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=1
|
||||
CONFIG_BT_CTRL_BLE_MAX_ACT=4
|
||||
CONFIG_BT_CTRL_BLE_STATIC_ACL_TX_BUF_NB=6
|
||||
CONFIG_BT_CTRL_BLE_MAX_CONN=1
|
||||
CONFIG_BT_CTRL_PINNED_TO_CORE_0=y
|
||||
|
||||
# WiFi Settings optimized for BLE coexistence (balanced, not aggressive)
|
||||
CONFIG_ESP_WIFI_IRAM_OPT=y
|
||||
CONFIG_ESP_WIFI_RX_IRAM_OPT=y
|
||||
CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=6
|
||||
CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=16
|
||||
CONFIG_ESP_WIFI_TX_BUFFER_TYPE=1
|
||||
CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=16
|
||||
CONFIG_ESP_PHY_REDUCE_TX_POWER=n
|
||||
CONFIG_ESP_PHY_MAX_TX_POWER=17
|
||||
CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=n
|
||||
CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=n
|
||||
CONFIG_ESP_WIFI_NVS_ENABLED=y
|
||||
|
||||
# Prioritize BLE over WiFi for wand stability
|
||||
CONFIG_ESP_WIFI_SW_COEXIST_PREFERENCE_BT=y
|
||||
|
||||
# CPU and Power settings
|
||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=240
|
||||
|
||||
# Power Management - keep radio powered for stability
|
||||
CONFIG_PM_ENABLE=n
|
||||
+2
-1
@@ -2379,7 +2379,8 @@ CONFIG_PM_ESP_SLEEP_POWER_DOWN_CPU=y
|
||||
# ESP PSRAM
|
||||
#
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_QUAD=y
|
||||
# CONFIG_SPIRAM_MODE_QUAD is not set
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_TYPE_AUTO=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_SPIRAM_BOOT_INIT=y
|
||||
|
||||
+4580
File diff suppressed because it is too large
Load Diff
+35
-14
@@ -15,7 +15,9 @@
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
|
||||
static const char *TAG = "ble_client";
|
||||
#if USE_USB_HID_DEVICE
|
||||
extern USBHIDManager usbHID;
|
||||
#endif
|
||||
|
||||
// Global for scan callback
|
||||
static WebServer *g_web_server = nullptr;
|
||||
@@ -647,6 +649,12 @@ bool WandBLEClient::begin(const unsigned char *model_data, size_t model_size)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Boost BLE TX power for Seeeduino XIAO's weaker PCB antenna
|
||||
ESP_LOGI(TAG, "Setting BLE TX power to maximum for better range...");
|
||||
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, ESP_PWR_LVL_P9);
|
||||
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_P9);
|
||||
esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_SCAN, ESP_PWR_LVL_P9);
|
||||
|
||||
nimble_port_freertos_init(ble_host_task);
|
||||
return true;
|
||||
}
|
||||
@@ -683,17 +691,17 @@ bool WandBLEClient::connect(const char *address)
|
||||
|
||||
peer_addr = addr;
|
||||
|
||||
// Configure connection parameters for better stability with WiFi coexistence
|
||||
// These params prioritize connection stability over low latency
|
||||
// Configure connection parameters - use standard values that NimBLE accepts
|
||||
// Values must be in valid ranges per Bluetooth spec
|
||||
struct ble_gap_conn_params conn_params;
|
||||
conn_params.scan_itvl = 0x0010; // 10ms scan interval
|
||||
conn_params.scan_window = 0x0010; // 10ms scan window
|
||||
conn_params.itvl_min = 0x0018; // 30ms min connection interval (24 * 1.25ms)
|
||||
conn_params.itvl_max = 0x0028; // 50ms max connection interval (40 * 1.25ms)
|
||||
conn_params.scan_itvl = 0x0010; // 10ms (16 * 0.625ms) - standard
|
||||
conn_params.scan_window = 0x0010; // 10ms (16 * 0.625ms) - must be <= scan_itvl
|
||||
conn_params.itvl_min = 0x0018; // 30ms (24 * 1.25ms) - standard range
|
||||
conn_params.itvl_max = 0x0028; // 50ms (40 * 1.25ms) - standard range
|
||||
conn_params.latency = 0; // No slave latency
|
||||
conn_params.supervision_timeout = 0x0C80; // 32 seconds (3200 * 10ms)
|
||||
conn_params.min_ce_len = 0x0010; // 10ms
|
||||
conn_params.max_ce_len = 0x0300; // 480ms
|
||||
conn_params.min_ce_len = 0x0010; // 10ms (16 * 0.625ms)
|
||||
conn_params.max_ce_len = 0x0300; // 480ms (768 * 0.625ms)
|
||||
|
||||
ESP_LOGI(TAG, "Attempting connection to %s (random address type) with 32s supervision timeout", address);
|
||||
rc = ble_gap_connect(BLE_OWN_ADDR_PUBLIC, &addr, 30000, &conn_params,
|
||||
@@ -824,12 +832,17 @@ void WandBLEClient::processButtonPacket(const uint8_t *data, size_t length)
|
||||
return;
|
||||
}
|
||||
|
||||
// Count pressed buttons for easier tracking
|
||||
uint8_t buttonsPressed = __builtin_popcount(buttonState & 0x0F);
|
||||
bool enoughButtonsPressed = (buttonsPressed >= BUTTON_MIN_FOR_TRACKING);
|
||||
bool wasEnoughPressed = (__builtin_popcount(lastButtonState & 0x0F) >= BUTTON_MIN_FOR_TRACKING);
|
||||
|
||||
if (buttonState != lastButtonState)
|
||||
{
|
||||
bool b1 = buttonState & 0x01, b2 = buttonState & 0x02,
|
||||
b3 = buttonState & 0x04, b4 = buttonState & 0x08;
|
||||
ESP_LOGI(TAG, "🔘 Buttons: [1]=%s [2]=%s [3]=%s [4]=%s",
|
||||
b1 ? "●" : "○", b2 ? "●" : "○", b3 ? "●" : "○", b4 ? "●" : "○");
|
||||
ESP_LOGI(TAG, "🔘 Buttons: [1]=%s [2]=%s [3]=%s [4]=%s (%d/4 pressed)",
|
||||
b1 ? "●" : "○", b2 ? "●" : "○", b3 ? "●" : "○", b4 ? "●" : "○", buttonsPressed);
|
||||
|
||||
// Broadcast button state to web GUI
|
||||
if (webServer)
|
||||
@@ -838,8 +851,8 @@ void WandBLEClient::processButtonPacket(const uint8_t *data, size_t length)
|
||||
}
|
||||
}
|
||||
|
||||
// All buttons pressed - start tracking
|
||||
if (buttonState == BUTTON_ALL_PRESSED && lastButtonState != BUTTON_ALL_PRESSED)
|
||||
// 3+ buttons pressed - start tracking (was 4 buttons required)
|
||||
if (enoughButtonsPressed && !wasEnoughPressed)
|
||||
{
|
||||
// Log heap status before starting tracking
|
||||
ESP_LOGI(TAG, "Free heap before tracking: %lu bytes", esp_get_free_heap_size());
|
||||
@@ -849,10 +862,12 @@ void WandBLEClient::processButtonPacket(const uint8_t *data, size_t length)
|
||||
if (!ahrsTracker.isTracking())
|
||||
{
|
||||
ahrsTracker.startTracking();
|
||||
ESP_LOGI(TAG, "Started spell tracking");
|
||||
ESP_LOGI(TAG, "Started spell tracking (%d buttons pressed)", buttonsPressed);
|
||||
|
||||
// Disable mouse movement during spell tracking
|
||||
#if USE_USB_HID_DEVICE
|
||||
usbHID.setInSpellMode(true);
|
||||
#endif
|
||||
|
||||
// Notify web visualizer (don't broadcast position[0], wait for position[1])
|
||||
if (webServer)
|
||||
@@ -862,7 +877,7 @@ void WandBLEClient::processButtonPacket(const uint8_t *data, size_t length)
|
||||
}
|
||||
}
|
||||
// Buttons released - detect spell
|
||||
else if (buttonState != BUTTON_ALL_PRESSED && lastButtonState == BUTTON_ALL_PRESSED)
|
||||
else if (!enoughButtonsPressed && wasEnoughPressed)
|
||||
{
|
||||
// Clear wand LEDs after spell tracking
|
||||
wandCommands.clearAllLEDs();
|
||||
@@ -883,7 +898,9 @@ void WandBLEClient::processButtonPacket(const uint8_t *data, size_t length)
|
||||
spellCallback(spell_name, spellDetector.getConfidence());
|
||||
|
||||
// Send mapped keyboard key for detected spell
|
||||
#if USE_USB_HID_DEVICE
|
||||
usbHID.sendSpellKeyboardForSpell(spell_name);
|
||||
#endif
|
||||
}
|
||||
else if (!spell_name)
|
||||
{
|
||||
@@ -902,7 +919,9 @@ void WandBLEClient::processButtonPacket(const uint8_t *data, size_t length)
|
||||
}
|
||||
|
||||
// Re-enable mouse movement after spell tracking
|
||||
#if USE_USB_HID_DEVICE
|
||||
usbHID.setInSpellMode(false);
|
||||
#endif
|
||||
|
||||
// Notify web visualizer
|
||||
if (webServer)
|
||||
@@ -974,7 +993,9 @@ void WandBLEClient::updateAHRS(const IMUSample &sample)
|
||||
// Rate limit mouse updates to ~60 Hz (every 4th point)
|
||||
if (new_count == 2 || ++mouse_counter >= 4)
|
||||
{
|
||||
#if USE_USB_HID_DEVICE
|
||||
usbHID.updateMouseFromGesture(accum_dx, accum_dy);
|
||||
#endif
|
||||
accum_dx = 0.0f;
|
||||
accum_dy = 0.0f;
|
||||
mouse_counter = 0;
|
||||
|
||||
+51
-5
@@ -13,6 +13,7 @@
|
||||
#include "esp_netif.h"
|
||||
#include "lwip/ip4_addr.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "ble_client.h"
|
||||
#include "config.h"
|
||||
#include "usb_hid.h"
|
||||
@@ -21,6 +22,12 @@
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
// Seeeduino XIAO ESP32S3 antenna switch GPIO
|
||||
// Some XIAO ESP32S3 use GPIO14, others GPIO3
|
||||
// Try GPIO14 first (most common for XIAO Sense), change to GPIO3 if needed
|
||||
#define ANTENNA_SWITCH_GPIO GPIO_NUM_14
|
||||
#define USE_EXTERNAL_ANTENNA 1 // Set to 1 for external antenna, 0 for internal
|
||||
|
||||
// MAC address formatting macros (if not defined by esp_wifi)
|
||||
#ifndef MACSTR
|
||||
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
@@ -250,8 +257,35 @@ void onIMUData(float ax, float ay, float az, float gx, float gy, float gz)
|
||||
|
||||
extern "C" void app_main()
|
||||
{
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS); // Small delay to ensure logging is ready
|
||||
ESP_LOGI(TAG, "app_main() starting...");
|
||||
// Wait 3 seconds for serial monitor to connect and catch all startup logs
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
|
||||
ESP_LOGI(TAG, "");
|
||||
ESP_LOGI(TAG, "================================================");
|
||||
ESP_LOGI(TAG, " ESP32-S3 Magic Wand Gateway Starting...");
|
||||
ESP_LOGI(TAG, " Seeeduino XIAO ESP32S3");
|
||||
ESP_LOGI(TAG, "================================================");
|
||||
ESP_LOGI(TAG, "");
|
||||
|
||||
// Configure antenna switch for Seeeduino XIAO ESP32S3
|
||||
ESP_LOGI(TAG, "Configuring RF antenna...");
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << ANTENNA_SWITCH_GPIO);
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
gpio_config(&io_conf);
|
||||
|
||||
#if USE_EXTERNAL_ANTENNA
|
||||
gpio_set_level(ANTENNA_SWITCH_GPIO, 1); // HIGH = external U.FL antenna
|
||||
ESP_LOGI(TAG, "✓ Using EXTERNAL antenna (U.FL connector on GPIO3)");
|
||||
ESP_LOGI(TAG, " Make sure antenna is properly attached!");
|
||||
#else
|
||||
gpio_set_level(ANTENNA_SWITCH_GPIO, 0); // LOW = internal PCB antenna
|
||||
ESP_LOGI(TAG, "✓ Using INTERNAL PCB antenna");
|
||||
#endif
|
||||
ESP_LOGI(TAG, "");
|
||||
|
||||
// Check PSRAM status early
|
||||
ESP_LOGI(TAG, "");
|
||||
@@ -639,25 +673,37 @@ extern "C" void app_main()
|
||||
const uint32_t BATTERY_CHECK_INTERVAL = 100; // Check every 10 seconds (100 * 100ms)
|
||||
uint32_t keepalive_counter = 0;
|
||||
const uint32_t KEEPALIVE_INTERVAL = 30; // Send keep-alive every 3 seconds (30 * 100ms)
|
||||
uint32_t reconnect_attempts = 0;
|
||||
const uint32_t MAX_RECONNECT_ATTEMPTS = 3; // Try 3 times then pause
|
||||
|
||||
while (1)
|
||||
{
|
||||
// Check connection status (only try to reconnect if we have a valid configured MAC)
|
||||
if (!wandClient.isConnected() && (mac_from_nvs || strcmp(WAND_MAC_ADDRESS, "C2:BD:5D:3C:67:4E") != 0))
|
||||
{
|
||||
ESP_LOGW(TAG, "Connection lost, attempting reconnect...");
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
// After 3 failed attempts, wait much longer to give WiFi priority
|
||||
if (reconnect_attempts >= MAX_RECONNECT_ATTEMPTS)
|
||||
{
|
||||
ESP_LOGW(TAG, "Connection lost after %d attempts. Pausing reconnects for 5 minutes to prioritize WiFi...", MAX_RECONNECT_ATTEMPTS);
|
||||
vTaskDelay(300000 / portTICK_PERIOD_MS); // Wait 5 minutes
|
||||
reconnect_attempts = 0; // Reset counter
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG, "Connection lost, attempting reconnect... (attempt %d/%d)", reconnect_attempts + 1, MAX_RECONNECT_ATTEMPTS);
|
||||
vTaskDelay(30000 / portTICK_PERIOD_MS); // Wait 30 seconds before reconnect attempt
|
||||
|
||||
// Attempt to connect
|
||||
wandClient.connect(wand_mac);
|
||||
reconnect_attempts++;
|
||||
|
||||
// Wait for connection to establish
|
||||
ESP_LOGI(TAG, "Waiting for connection...");
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
vTaskDelay(10000 / portTICK_PERIOD_MS); // Wait 10 seconds for connection
|
||||
|
||||
// Check if connection succeeded
|
||||
if (wandClient.isConnected())
|
||||
{
|
||||
reconnect_attempts = 0; // Reset on successful connection
|
||||
ESP_LOGI(TAG, "Reconnected! Waiting for service discovery...");
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
|
||||
|
||||
+20
-20
@@ -51,15 +51,15 @@ size_t SpellEffects::buildEffect(const char *spell_name, uint8_t *buffer, size_t
|
||||
// Build effect based on spell name
|
||||
if (strcmp(spell_name, "Lumos") == 0)
|
||||
{
|
||||
// Buzz 150ms + White LED 2s
|
||||
len += addBuzz(buffer, len, 150);
|
||||
// Buzz 50ms + White LED 2s (reduced vibration)
|
||||
len += addBuzz(buffer, len, 50);
|
||||
len += addLEDTransition(buffer, len, (uint8_t)LedGroup::TIP,
|
||||
255, 255, 255, 2000);
|
||||
}
|
||||
else if (strcmp(spell_name, "Nox") == 0)
|
||||
{
|
||||
// Buzz 100ms + Purple flash + Clear
|
||||
len += addBuzz(buffer, len, 100);
|
||||
// Buzz 30ms + Purple flash + Clear (reduced vibration)
|
||||
len += addBuzz(buffer, len, 30);
|
||||
len += addLEDTransition(buffer, len, (uint8_t)LedGroup::TIP,
|
||||
51, 0, 51, 200);
|
||||
len += addDelay(buffer, len, 100);
|
||||
@@ -67,57 +67,57 @@ size_t SpellEffects::buildEffect(const char *spell_name, uint8_t *buffer, size_t
|
||||
}
|
||||
else if (strcmp(spell_name, "Verdimillious") == 0 || strcmp(spell_name, "Reducto") == 0)
|
||||
{
|
||||
// Green spell effect
|
||||
len += addBuzz(buffer, len, 200);
|
||||
// Green spell effect (reduced vibration)
|
||||
len += addBuzz(buffer, len, 50);
|
||||
len += addLEDTransition(buffer, len, (uint8_t)LedGroup::TIP,
|
||||
0, 255, 0, 200);
|
||||
}
|
||||
else if (strcmp(spell_name, "Incendio") == 0 || strcmp(spell_name, "Flagrate") == 0)
|
||||
{
|
||||
// Fire spell effect (orange)
|
||||
len += addBuzz(buffer, len, 150);
|
||||
// Fire spell effect (orange, reduced vibration)
|
||||
len += addBuzz(buffer, len, 50);
|
||||
len += addLEDTransition(buffer, len, (uint8_t)LedGroup::TIP,
|
||||
255, 102, 0, 400);
|
||||
}
|
||||
else if (strcmp(spell_name, "Expelliarmus") == 0)
|
||||
{
|
||||
// Red disarming spell
|
||||
len += addBuzz(buffer, len, 200);
|
||||
// Red disarming spell (reduced vibration)
|
||||
len += addBuzz(buffer, len, 50);
|
||||
len += addLEDTransition(buffer, len, (uint8_t)LedGroup::TIP,
|
||||
255, 0, 0, 300);
|
||||
}
|
||||
else if (strcmp(spell_name, "Stupefy") == 0)
|
||||
{
|
||||
// Red stunning spell with longer buzz
|
||||
len += addBuzz(buffer, len, 250);
|
||||
// Red stunning spell (reduced vibration)
|
||||
len += addBuzz(buffer, len, 60);
|
||||
len += addLEDTransition(buffer, len, (uint8_t)LedGroup::TIP,
|
||||
200, 0, 0, 400);
|
||||
}
|
||||
else if (strcmp(spell_name, "Protego") == 0)
|
||||
{
|
||||
// Blue shield spell
|
||||
len += addBuzz(buffer, len, 150);
|
||||
// Blue shield spell (reduced vibration)
|
||||
len += addBuzz(buffer, len, 50);
|
||||
len += addLEDTransition(buffer, len, (uint8_t)LedGroup::TIP,
|
||||
0, 100, 255, 500);
|
||||
}
|
||||
else if (strcmp(spell_name, "Wingardium Leviosa") == 0)
|
||||
{
|
||||
// Light blue levitation spell
|
||||
len += addBuzz(buffer, len, 100);
|
||||
// Light blue levitation spell (reduced vibration)
|
||||
len += addBuzz(buffer, len, 40);
|
||||
len += addLEDTransition(buffer, len, (uint8_t)LedGroup::TIP,
|
||||
100, 200, 255, 600);
|
||||
}
|
||||
else if (strcmp(spell_name, "Accio") == 0)
|
||||
{
|
||||
// Cyan summoning spell
|
||||
len += addBuzz(buffer, len, 120);
|
||||
// Cyan summoning spell (reduced vibration)
|
||||
len += addBuzz(buffer, len, 40);
|
||||
len += addLEDTransition(buffer, len, (uint8_t)LedGroup::TIP,
|
||||
0, 255, 255, 300);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default effect for unknown spells (blue flash)
|
||||
len += addBuzz(buffer, len, 100);
|
||||
// Default effect for unknown spells (blue flash, reduced vibration)
|
||||
len += addBuzz(buffer, len, 40);
|
||||
len += addLEDTransition(buffer, len, (uint8_t)LedGroup::TIP,
|
||||
0, 100, 255, 200);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#include <string.h>
|
||||
|
||||
// Forward declaration from main.cpp
|
||||
#if USE_USB_HID_DEVICE
|
||||
extern USBHIDManager usbHID;
|
||||
#endif
|
||||
|
||||
static const char *TAG = "web_server";
|
||||
|
||||
@@ -1979,6 +1981,7 @@ esp_err_t WebServer::settings_get_handler(httpd_req_t *req)
|
||||
ESP_LOGI(TAG, "settings_get_handler called!");
|
||||
|
||||
// Return mouse sensitivity and all 73 spell keycodes
|
||||
#if USE_USB_HID_DEVICE
|
||||
char buffer[2048];
|
||||
int offset = 0;
|
||||
|
||||
@@ -1997,6 +2000,10 @@ esp_err_t WebServer::settings_get_handler(httpd_req_t *req)
|
||||
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
httpd_resp_sendstr(req, buffer);
|
||||
#else
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
httpd_resp_sendstr(req, "{\"status\":\"disabled\",\"message\":\"USB HID not enabled\"}");
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -2025,6 +2032,7 @@ esp_err_t WebServer::settings_save_handler(httpd_req_t *req)
|
||||
ESP_LOGI(TAG, "Received settings: %s", buffer);
|
||||
|
||||
// Parse JSON - expect format: {"mouse_sensitivity": 1.5, "spells": [0, 58, 0, ...]}
|
||||
#if USE_USB_HID_DEVICE
|
||||
float mouse_sens = 1.0f;
|
||||
char *mouse_ptr = strstr(buffer, "\"mouse_sensitivity\"");
|
||||
if (mouse_ptr)
|
||||
@@ -2072,8 +2080,10 @@ esp_err_t WebServer::settings_save_handler(httpd_req_t *req)
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Save to NVS
|
||||
#if USE_USB_HID_DEVICE
|
||||
if (usbHID.saveSettings())
|
||||
{
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
@@ -2088,12 +2098,19 @@ esp_err_t WebServer::settings_save_handler(httpd_req_t *req)
|
||||
free(buffer);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#else
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
httpd_resp_sendstr(req, "{\"status\":\"disabled\",\"message\":\"USB HID not enabled\"}");
|
||||
free(buffer);
|
||||
return ESP_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_err_t WebServer::settings_reset_handler(httpd_req_t *req)
|
||||
{
|
||||
ESP_LOGI(TAG, "settings_reset_handler called!");
|
||||
|
||||
#if USE_USB_HID_DEVICE
|
||||
if (usbHID.resetSettings())
|
||||
{
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
@@ -2106,4 +2123,9 @@ esp_err_t WebServer::settings_reset_handler(httpd_req_t *req)
|
||||
httpd_resp_sendstr(req, "{\"status\":\"error\",\"message\":\"Failed to reset settings\"}");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#else
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
httpd_resp_sendstr(req, "{\"status\":\"disabled\",\"message\":\"USB HID not enabled\"}");
|
||||
return ESP_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user