From 7ceaf1e4d2e407725113fa1e227525dfd34435ff Mon Sep 17 00:00:00 2001 From: Zach Whitehead Date: Sat, 16 Aug 2025 11:36:15 -0500 Subject: [PATCH 1/8] Update for Arduino-ESP32 3.x API and improve ESC init Refactor buzzer and vibration motor initialization to use the new ledcAttach API from Arduino-ESP32 3.x. Update BLE characteristic callbacks to use String instead of std::string for compatibility. Improve ESC initialization by deferring throttle setup until after the first CAN process and add a readiness check. Update watchdog initialization to use the new esp_task_wdt_init config structure. Minor fix to pin initialization order in setup. --- platformio.ini | 3 ++- src/sp140/buzzer.cpp | 12 ++++++------ src/sp140/esc.cpp | 14 +++++++++----- src/sp140/sp140.ino | 12 ++++++++++-- src/sp140/vibration_pwm.cpp | 4 ++-- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/platformio.ini b/platformio.ini index 7ed8fb2..534291a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -21,7 +21,7 @@ lib_ignore = [env:OpenPPG-CESP32S3-CAN-SP140] -platform = espressif32@6.12.0 +platform = https://github.com/pioarduino/platform-espressif32.git#develop board = m5stack-stamps3 framework = arduino src_folder = sp140 @@ -38,6 +38,7 @@ build_flags = -D LV_LVGL_H_INCLUDE_SIMPLE ; Disable legacy individual BLE characteristics (use packed binary only) -D DISABLE_LEGACY_BLE_TELEMETRY + -D USBSerial=Serial build_type = debug debug_speed = 12000 diff --git a/src/sp140/buzzer.cpp b/src/sp140/buzzer.cpp index de65343..28a2447 100644 --- a/src/sp140/buzzer.cpp +++ b/src/sp140/buzzer.cpp @@ -29,9 +29,9 @@ static bool buzzerInitialized = false; * @return Returns true if initialization was successful, false otherwise */ bool initBuzz() { - // Setup LEDC channel for buzzer - ledcSetup(BUZZER_PWM_CHANNEL, BUZZER_PWM_FREQUENCY, BUZZER_PWM_RESOLUTION); - ledcAttachPin(board_config.buzzer_pin, BUZZER_PWM_CHANNEL); + // Setup LEDC channel for buzzer (Arduino-ESP32 3.x API) + // Channels are implicitly allocated; attach pin to channel and set frequency/resolution + ledcAttach(board_config.buzzer_pin, BUZZER_PWM_FREQUENCY, BUZZER_PWM_RESOLUTION); buzzerInitialized = true; return true; } @@ -43,9 +43,9 @@ void startTone(uint16_t frequency) { if (!buzzerInitialized || !ENABLE_BUZZ) return; // Change the frequency for this channel - ledcChangeFrequency(BUZZER_PWM_CHANNEL, frequency, BUZZER_PWM_RESOLUTION); + ledcWriteTone(board_config.buzzer_pin, frequency); // Set 50% duty cycle (square wave) - ledcWrite(BUZZER_PWM_CHANNEL, 128); + ledcWrite(board_config.buzzer_pin, 128); } /** @@ -55,7 +55,7 @@ void stopTone() { if (!buzzerInitialized) return; // Set duty cycle to 0 to stop the tone - ledcWrite(BUZZER_PWM_CHANNEL, 0); + ledcWrite(board_config.buzzer_pin, 0); } /** diff --git a/src/sp140/esc.cpp b/src/sp140/esc.cpp index 1a435c8..9fa39f1 100644 --- a/src/sp140/esc.cpp +++ b/src/sp140/esc.cpp @@ -15,6 +15,7 @@ static CanardAdapter adapter; static uint8_t memory_pool[1024] __attribute__((aligned(8))); static SineEsc esc(adapter); static unsigned long lastSuccessfulCommTimeMs = 0; // Store millis() time of last successful ESC comm +static bool escReady = false; STR_ESC_TELEMETRY_140 escTelemetryData = { @@ -36,14 +37,13 @@ void initESC() { } adapter.begin(memory_pool, sizeof(memory_pool)); - adapter.setLocalNodeId(LOCAL_NODE_ID); esc.begin(0x20); // Default ID for the ESC + adapter.setLocalNodeId(LOCAL_NODE_ID); - // Set idle throttle only if ESC is found - const uint16_t IdleThrottle_us = 10000; // 1000us (0.1us resolution) - esc.setThrottleSettings2(IdleThrottle_us); + // Defer sending throttle until after first adapter process to avoid null pointer in CANARD adapter.processTxRxOnce(); - vTaskDelay(pdMS_TO_TICKS(20)); // Wait for ESC to process the command + vTaskDelay(pdMS_TO_TICKS(20)); // Give ESC time to be ready + escReady = true; } /** @@ -54,6 +54,10 @@ void initESC() { * Important: The ESC requires messages at least every 300ms or it will reset */ void setESCThrottle(int throttlePWM) { + // Ensure TWAI/ESC subsystem is initialized + if (!escTwaiInitialized || !escReady) { + return; + } // Input validation if (throttlePWM < 1000 || throttlePWM > 2000) { return; // Ignore invalid throttle values diff --git a/src/sp140/sp140.ino b/src/sp140/sp140.ino index 1a2b3e2..d7fe877 100644 --- a/src/sp140/sp140.ino +++ b/src/sp140/sp140.ino @@ -598,7 +598,15 @@ void setupAnalogRead() { void setupWatchdog() { #ifndef OPENPPG_DEBUG // Initialize Task Watchdog - ESP_ERROR_CHECK(esp_task_wdt_init(3000, true)); // 3 second timeout, panic on timeout + esp_task_wdt_config_t twdt_config = { + .timeout_ms = 3000, + .idle_core_mask = 0, // do not subscribe idle tasks + .trigger_panic = true, + }; + esp_err_t wdt_init_result = esp_task_wdt_init(&twdt_config); + if (wdt_init_result != ESP_OK && wdt_init_result != ESP_ERR_INVALID_STATE) { + ESP_ERROR_CHECK(wdt_init_result); + } #endif // OPENPPG_DEBUG } @@ -617,8 +625,8 @@ void setup() { // Pull CSB (pin 42) high to activate I2C mode // temporary fix TODO remove - digitalWrite(42, HIGH); pinMode(42, OUTPUT); + digitalWrite(42, HIGH); // Initialize LVGL mutex before anything else lvglMutex = xSemaphoreCreateMutex(); diff --git a/src/sp140/vibration_pwm.cpp b/src/sp140/vibration_pwm.cpp index 096385a..e285b0f 100644 --- a/src/sp140/vibration_pwm.cpp +++ b/src/sp140/vibration_pwm.cpp @@ -61,8 +61,8 @@ void vibeTask(void* parameter) { */ bool initVibeMotor() { extern HardwareConfig board_config; - ledcSetup(VIBE_PWM_CHANNEL, VIBE_PWM_FREQ, VIBE_PWM_RESOLUTION); - ledcAttachPin(board_config.vibe_pwm, VIBE_PWM_CHANNEL); + // Arduino-ESP32 3.x LEDC API: use ledcAttach(pin, freq, resolution) + ledcAttach(board_config.vibe_pwm, VIBE_PWM_FREQ, VIBE_PWM_RESOLUTION); // Create vibration queue vibeQueue = xQueueCreate(5, sizeof(VibeRequest)); From bd84e56ed62a900e1f68cae3c77210b7f15cd27a Mon Sep 17 00:00:00 2001 From: Zach Whitehead Date: Wed, 21 Jan 2026 15:18:36 -0600 Subject: [PATCH 2/8] Fix vibration # Conflicts: # src/sp140/vibration_pwm.cpp --- src/sp140/vibration_pwm.cpp | 47 +++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/sp140/vibration_pwm.cpp b/src/sp140/vibration_pwm.cpp index e285b0f..2ceeb8a 100644 --- a/src/sp140/vibration_pwm.cpp +++ b/src/sp140/vibration_pwm.cpp @@ -22,9 +22,9 @@ void criticalVibeTask(void* parameter) { for (;;) { if (criticalVibrationActive && ENABLE_VIBE) { // Pulse every 1 second for critical alerts - ledcWrite(VIBE_PWM_CHANNEL, 200); // Medium intensity for continuous + ledcWrite(board_config.vibe_pwm, 200); // Medium intensity for continuous vTaskDelay(pdMS_TO_TICKS(300)); // 300ms on - ledcWrite(VIBE_PWM_CHANNEL, 0); + ledcWrite(board_config.vibe_pwm, 0); vTaskDelay(pdMS_TO_TICKS(700)); // 700ms off (total 1 second cycle) } else { // If not active, suspend task to save resources @@ -43,13 +43,13 @@ void vibeTask(void* parameter) { if (xQueueReceive(vibeQueue, &request, portMAX_DELAY) == pdTRUE) { if (ENABLE_VIBE) { // Turn on vibration with specified intensity - ledcWrite(VIBE_PWM_CHANNEL, request.intensity); + ledcWrite(board_config.vibe_pwm, request.intensity); // Wait for specified duration vTaskDelay(pdMS_TO_TICKS(request.duration_ms)); // Turn off vibration - ledcWrite(VIBE_PWM_CHANNEL, 0); + ledcWrite(board_config.vibe_pwm, 0); } } } @@ -60,9 +60,10 @@ void vibeTask(void* parameter) { * @return Returns true if initialization was successful, false otherwise */ bool initVibeMotor() { - extern HardwareConfig board_config; // Arduino-ESP32 3.x LEDC API: use ledcAttach(pin, freq, resolution) + pinMode(board_config.vibe_pwm, OUTPUT); ledcAttach(board_config.vibe_pwm, VIBE_PWM_FREQ, VIBE_PWM_RESOLUTION); + ledcWrite(board_config.vibe_pwm, 0); // Create vibration queue vibeQueue = xQueueCreate(5, sizeof(VibeRequest)); @@ -112,7 +113,7 @@ void stopVibration() { if (vibeQueue != NULL) { xQueueReset(vibeQueue); } - ledcWrite(VIBE_PWM_CHANNEL, 0); + ledcWrite(board_config.vibe_pwm, 0); } /** @@ -125,10 +126,10 @@ bool runVibePattern(const unsigned int pattern[], int patternSize) { if (!ENABLE_VIBE) return false; for (int i = 0; i < patternSize; i++) { - ledcWrite(VIBE_PWM_CHANNEL, pattern[i]); + ledcWrite(board_config.vibe_pwm, pattern[i]); vTaskDelay(pdMS_TO_TICKS(200)); } - ledcWrite(VIBE_PWM_CHANNEL, 0); // Turn off vibration + ledcWrite(board_config.vibe_pwm, 0); // Turn off vibration return true; } @@ -141,46 +142,46 @@ void executeVibePattern(VibePattern pattern) { switch (pattern) { case VIBE_SHORT_PULSE: - ledcWrite(VIBE_PWM_CHANNEL, 255); + ledcWrite(board_config.vibe_pwm, 255); vTaskDelay(pdMS_TO_TICKS(100)); - ledcWrite(VIBE_PWM_CHANNEL, 0); + ledcWrite(board_config.vibe_pwm, 0); break; case VIBE_LONG_PULSE: - ledcWrite(VIBE_PWM_CHANNEL, 255); + ledcWrite(board_config.vibe_pwm, 255); vTaskDelay(pdMS_TO_TICKS(500)); - ledcWrite(VIBE_PWM_CHANNEL, 0); + ledcWrite(board_config.vibe_pwm, 0); break; case VIBE_DOUBLE_PULSE: for (int i = 0; i < 2; i++) { - ledcWrite(VIBE_PWM_CHANNEL, 255); + ledcWrite(board_config.vibe_pwm, 255); vTaskDelay(pdMS_TO_TICKS(150)); - ledcWrite(VIBE_PWM_CHANNEL, 0); + ledcWrite(board_config.vibe_pwm, 0); vTaskDelay(pdMS_TO_TICKS(150)); } break; case VIBE_TRIPLE_PULSE: for (int i = 0; i < 3; i++) { - ledcWrite(VIBE_PWM_CHANNEL, 255); + ledcWrite(board_config.vibe_pwm, 255); vTaskDelay(pdMS_TO_TICKS(100)); - ledcWrite(VIBE_PWM_CHANNEL, 0); + ledcWrite(board_config.vibe_pwm, 0); vTaskDelay(pdMS_TO_TICKS(100)); } break; case VIBE_RAMP_UP: for (int i = 0; i <= 255; i += 5) { - ledcWrite(VIBE_PWM_CHANNEL, i); + ledcWrite(board_config.vibe_pwm, i); vTaskDelay(pdMS_TO_TICKS(25)); } - ledcWrite(VIBE_PWM_CHANNEL, 0); + ledcWrite(board_config.vibe_pwm, 0); break; case VIBE_RAMP_DOWN: for (int i = 255; i >= 0; i -= 5) { - ledcWrite(VIBE_PWM_CHANNEL, i); + ledcWrite(board_config.vibe_pwm, i); vTaskDelay(pdMS_TO_TICKS(25)); } break; @@ -188,10 +189,10 @@ void executeVibePattern(VibePattern pattern) { case VIBE_WAVE: for (int i = 0; i <= 180; i += 5) { int intensity = (sin(i * PI / 180.0) + 1) * 127.5; - ledcWrite(VIBE_PWM_CHANNEL, intensity); + ledcWrite(board_config.vibe_pwm, intensity); vTaskDelay(pdMS_TO_TICKS(20)); } - ledcWrite(VIBE_PWM_CHANNEL, 0); + ledcWrite(board_config.vibe_pwm, 0); break; } } @@ -206,10 +207,10 @@ void customVibePattern(const uint8_t intensities[], const uint16_t durations[], if (!ENABLE_VIBE) return; for (int i = 0; i < steps; i++) { - ledcWrite(VIBE_PWM_CHANNEL, intensities[i]); + ledcWrite(board_config.vibe_pwm, intensities[i]); vTaskDelay(pdMS_TO_TICKS(durations[i])); } - ledcWrite(VIBE_PWM_CHANNEL, 0); + ledcWrite(board_config.vibe_pwm, 0); } // Service state for critical alerts From 632f966397857d0829459216202df7ab4f5dd41d Mon Sep 17 00:00:00 2001 From: Zach Whitehead Date: Sat, 16 Aug 2025 11:42:18 -0500 Subject: [PATCH 3/8] Fix vibration --- .vscode/extensions.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index b191a09..ecdd563 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,8 +1,7 @@ { - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format "recommendations": [ "ms-vscode.cpptools-extension-pack", + "pioarduino.pioarduino-ide", "platformio.platformio-ide" ], "unwantedRecommendations": [ From 8d6077ac6634399b710b52853897cc7ee4b3c46e Mon Sep 17 00:00:00 2001 From: Zach Whitehead Date: Mon, 18 Aug 2025 09:55:19 -0500 Subject: [PATCH 4/8] Update SIMPLE_MONITOR_README.md --- SIMPLE_MONITOR_README.md | 172 ++++++++++++++++++++++++++++++++------- 1 file changed, 141 insertions(+), 31 deletions(-) diff --git a/SIMPLE_MONITOR_README.md b/SIMPLE_MONITOR_README.md index ffdb627..dd0a2f7 100644 --- a/SIMPLE_MONITOR_README.md +++ b/SIMPLE_MONITOR_README.md @@ -1,50 +1,160 @@ -# Sensor Monitoring System +# Simple Sensor Monitoring System ## Overview -Real-time health monitoring for ESP32 electric ultralight sensors. Monitors ESC, BMS, altimeter, and system health with threshold-based alerting. +A lightweight, category-based monitoring system for ESP32 electric ultralight sensors. Features intelligent alert suppression when controllers disconnect and modern OOP design with device categories. -## Features -- **Comprehensive**: 50+ sensors monitored across all flight systems -- **Smart Alerting**: Hysteresis protection prevents false alerts -- **Multiple Outputs**: Serial, display, and extensible logging -- **Efficient**: Minimal overhead, change-only notifications +## Design Philosophy +- **Safety-First**: Automatically suppresses ESC alerts when ESC disconnected, BMS alerts when BMS disconnected +- **Category-Based**: Organizes sensors by device type (ESC, BMS, ALTIMETER, INTERNAL) for grouped management +- **Modern OOP**: Interface-based design with virtual methods and clean inheritance +- **Thread-Safe**: Queue-based telemetry snapshots for safe multi-task operation -## What's Monitored +## Usage -### ESC -- Temperatures (MOS, MCU, CAP, Motor) -- Error states (over-current, over-temp, voltage issues) -- Hardware faults and diagnostics +### Device Categories & Alert Suppression +```cpp +enum class SensorCategory { + ESC, // ESC temps, motor temp, ESC errors + BMS, // Battery voltage, current, temps, SOC + ALTIMETER, // Barometric sensors + INTERNAL // CPU temp, system sensors +}; -### BMS -- Cell voltages and temperature sensors -- State of charge and charge/discharge status -- Voltage differential monitoring +// When ESC disconnects: All ESC alerts automatically cleared +// When BMS disconnects: All BMS alerts automatically cleared +// ALTIMETER/INTERNAL: Always monitored (no connection dependency) +``` -### System -- CPU temperature and altimeter readings -- System health and diagnostics +### Current Monitoring Coverage +```cpp +// ESC Category (suppressed when ESC disconnected): +// - ESC MOS: Warning 90°C, Critical 110°C +// - ESC MCU: Warning 80°C, Critical 95°C +// - ESC CAP: Warning 85°C, Critical 100°C +// - Motor: Warning 90°C, Critical 110°C +// - ESC Error Conditions (overcurrent, overtemp, etc.) -## How It Works +// BMS Category (suppressed when BMS disconnected): +// - Battery voltage, current, SOC, cell voltages +// - BMS temperatures, charge/discharge MOS status +``` -System automatically monitors all sensors and alerts on threshold violations. Hysteresis prevents false alerts from sensor noise. +### Adding New Sensors +```cpp +// Example: New ESC sensor +static SensorMonitor* newEscSensor = new SensorMonitor( + SensorID::ESC_New_Sensor, // Unique ID from enum + SensorCategory::ESC, // Category determines suppression behavior + {.warnLow = 10, .warnHigh = 80, .critLow = 5, .critHigh = 90}, + []() { return escTelemetryData.new_value; }, // Data source + &multiLogger // Fan-out to multiple outputs +); +monitors.push_back(newEscSensor); -### Alert Levels -- **OK**: Normal operation -- **WARN**: Advisory thresholds exceeded -- **CRIT**: Critical thresholds requiring attention +// Example: Boolean error monitor +static BooleanMonitor* newError = new BooleanMonitor( + SensorID::ESC_New_Error, + SensorCategory::ESC, + []() { return checkErrorCondition(); }, + true, // Alert when condition is true + AlertLevel::CRIT_HIGH, + &multiLogger +); +monitors.push_back(newError); +``` ### Example Output ``` [15234] [WARN_HIGH] ESC_MOS_Temp = 92.50 [15467] [CRIT_HIGH] Motor_Temp = 112.30 [15890] [OK] ESC_MOS_Temp = 88.20 +[16123] ESC disconnected - clearing all ESC alerts +[16450] [WARN_LOW] BMS_SOC = 12.3 +``` + +## Easy Extensions + +### SD Card Logging +```cpp +struct SDLogger : ILogger { + void log(SensorID id, AlertLevel lvl, float v) override { + File logFile = SD.open("/alerts.log", FILE_APPEND); + logFile.printf("%lu,%s,%d,%.2f\n", millis(), sensorIDToString(id), (int)lvl, v); + logFile.close(); + } +}; +``` + +### Custom Alert Processing +```cpp +struct CustomLogger : ILogger { + void log(SensorID id, AlertLevel lvl, float v) override { + // Custom processing based on sensor category + SensorCategory cat = getSensorCategory(id); + if (cat == SensorCategory::ESC && lvl >= AlertLevel::CRIT_HIGH) { + triggerEmergencyShutdown(); + } + } +}; ``` -### Integration -- Runs every 40ms in FreeRTOS task -- Displays alerts on screen with haptic feedback -- Serial logging for diagnostics -- Thread-safe with minimal CPU overhead +### Multiple Outputs (Built-in) +```cpp +// MultiLogger automatically fans out to all registered sinks +multiLogger.addSink(&serialLogger); // Console output +multiLogger.addSink(&uiLogger); // LVGL alerts +multiLogger.addSink(&customLogger); // Your custom handler + +// All monitors automatically use multiLogger +``` + +## Architecture + +```cpp +IMonitor (interface) +├── virtual SensorID getSensorID() = 0 +├── virtual SensorCategory getCategory() = 0 +└── virtual void check() = 0 + +SensorMonitor : IMonitor BooleanMonitor : IMonitor +├── SensorID id ├── SensorID id +├── SensorCategory category ├── SensorCategory category +├── Thresholds thr ├── std::function read +├── std::function read ├── bool alertOnTrue +└── ILogger* logger └── AlertLevel level + +ILogger (interface) +├── SerialLogger (debug output) +├── AlertUILogger (LVGL display) +└── MultiLogger (fan-out to multiple sinks) + +Categories & Connection Logic: +├── ESC sensors → suppressed when escState != CONNECTED +├── BMS sensors → suppressed when bmsState != CONNECTED +├── ALTIMETER sensors → always active +└── INTERNAL sensors → always active +``` + +## Integration +- **Queue-Based**: Dedicated monitoring task receives telemetry snapshots via FreeRTOS queue +- **Thread-Safe**: No direct access to volatile telemetry data from monitoring task +- **Connection-Aware**: Automatically clears alerts when devices disconnect +- **Smart Suppression**: Only runs ESC monitors when ESC connected, BMS monitors when BMS connected +- **Change Detection**: Only logs when alert level changes (no spam) +- **Zero Overhead**: Minimal CPU usage when all sensors in OK state + +## Memory Usage +- **Code Size**: ~3KB total (includes OOP infrastructure, queue handling, UI integration) +- **Per Sensor**: ~150 bytes (SensorMonitor) or ~120 bytes (BooleanMonitor) +- **Static Allocation**: All monitors allocated at compile-time (embedded-friendly) +- **Queue Memory**: ~200 bytes for telemetry snapshot queue +- **Category Lookup**: O(1) via virtual methods (no external mapping tables) + +## Key Benefits +1. **Safety**: ESC alerts disappear when ESC disconnects (no false warnings during connection issues) +2. **Maintainability**: Add new sensors by category, automatic suppression behavior +3. **Robustness**: Thread-safe design prevents race conditions between telemetry and monitoring +4. **Extensibility**: Clean OOP interfaces for new monitor types and output methods +5. **Performance**: Smart suppression reduces unnecessary checks when devices offline -The system provides comprehensive flight safety monitoring while maintaining performance for electric ultralight operation. +This design balances safety, maintainability, and performance - essential for flight-critical embedded systems. From a4b96c3dec323357c823cf3d3066397c242cbc44 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 20:36:49 +0000 Subject: [PATCH 5/8] Initial plan From 7e2544f3942045a447e1479197ef0e5f29722e1d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 20:48:04 +0000 Subject: [PATCH 6/8] Update platform to v3.3.5 (tag 55.03.35) Co-authored-by: zjwhitehead <4623792+zjwhitehead@users.noreply.github.com> --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 534291a..1ab4101 100644 --- a/platformio.ini +++ b/platformio.ini @@ -21,7 +21,7 @@ lib_ignore = [env:OpenPPG-CESP32S3-CAN-SP140] -platform = https://github.com/pioarduino/platform-espressif32.git#develop +platform = https://github.com/pioarduino/platform-espressif32.git#55.03.35 board = m5stack-stamps3 framework = arduino src_folder = sp140 From 60db71dc44921b856da4e89de62bd35b2811ae08 Mon Sep 17 00:00:00 2001 From: Zach Whitehead Date: Wed, 21 Jan 2026 15:32:31 -0600 Subject: [PATCH 7/8] Add .tool-versions file and declare board_config extern Introduces a .tool-versions file specifying Python 3.11.9 for environment consistency. Also adds an extern declaration for HardwareConfig board_config in vibration_pwm.cpp to resolve linkage or visibility issues. --- .tool-versions | 1 + src/sp140/vibration_pwm.cpp | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 .tool-versions diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..8aa451a --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +python 3.11.9 diff --git a/src/sp140/vibration_pwm.cpp b/src/sp140/vibration_pwm.cpp index 2ceeb8a..865d5db 100644 --- a/src/sp140/vibration_pwm.cpp +++ b/src/sp140/vibration_pwm.cpp @@ -2,6 +2,8 @@ #include "sp140/esp32s3-config.h" #include "sp140/lvgl/lvgl_updates.h" +extern HardwareConfig board_config; + // Pin is configured via s3_config.vibe_pwm const int VIBE_PWM_FREQ = 1000; // Adjust as needed const int VIBE_PWM_RESOLUTION = 8; // 8-bit resolution From 28daf6020de5912515abd5d0021bfd92989530f5 Mon Sep 17 00:00:00 2001 From: Zach Whitehead Date: Wed, 21 Jan 2026 15:34:51 -0600 Subject: [PATCH 8/8] Update config.yml --- .github/workflows/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/config.yml b/.github/workflows/config.yml index 7f47407..c9eadce 100644 --- a/.github/workflows/config.yml +++ b/.github/workflows/config.yml @@ -20,7 +20,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.x + python-version: "3.11" - run: pip install cpplint - run: cpplint --linelength 140 --filter=-legal/copyright,-runtime/int,-build/include_subdir,-readability/casting,-readability/todo,-build/include_order,-build/include_what_you_use --recursive ./inc/ ./lib/ ./src/ @@ -40,7 +40,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.x + python-version: "3.11" - name: Cache PlatformIO uses: actions/cache@v5 with: @@ -70,7 +70,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v6 with: - python-version: 3.x + python-version: "3.11" - name: Cache PlatformIO uses: actions/cache@v5 with: