From b2c0d352a5564ff1219f17b21f06fe48494985ed Mon Sep 17 00:00:00 2001 From: Corey Thompson Date: Sat, 3 Jan 2026 09:09:23 -0600 Subject: [PATCH] precompile binaries during release pipeline, included bundled tool to flash and automate the upload --- .github/workflows/release.yml | 32 +++ Flash Firmware (Windows).bat | 52 ---- Flash Firmware.bat | 51 ++++ UPLOAD_GUIDE.md | 124 ++++++++- arduino/README.md | 2 +- build_release.sh | 84 ++++-- flash_firmware.ps1 | 468 ++++++++++++++++++---------------- flash_firmware.sh | 269 ------------------- 8 files changed, 508 insertions(+), 574 deletions(-) delete mode 100644 Flash Firmware (Windows).bat create mode 100644 Flash Firmware.bat delete mode 100644 flash_firmware.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c3a22ee..38fc2db 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,6 +45,38 @@ jobs: ${{ github.workspace }}/bin/arduino-cli core install esp32:esp32 ${{ github.workspace }}/bin/arduino-cli lib install "LiquidCrystal" + - name: Compile and export firmware binaries + run: | + echo "Compiling SledController..." + ${{ github.workspace }}/bin/arduino-cli compile \ + --fqbn esp32:esp32:esp32 \ + --export-binaries \ + --output-dir ${{ github.workspace }}/firmware_binaries/SledController \ + ${{ github.workspace }}/arduino/SledController + + echo "Compiling JudgeController..." + ${{ github.workspace }}/bin/arduino-cli compile \ + --fqbn esp32:esp32:esp32 \ + --export-binaries \ + --output-dir ${{ github.workspace }}/firmware_binaries/JudgeController \ + ${{ github.workspace }}/arduino/JudgeController + + echo "Compiled firmware files:" + find ${{ github.workspace }}/firmware_binaries -name "*.bin" -ls + + - name: Extract esptool for Windows + run: | + ESPTOOL_DIR=$(find ~/.arduino15/packages/esp32/tools/esptool_py -type d -maxdepth 2 | head -1) + mkdir -p ${{ github.workspace }}/bundled_tools + + if [ -f "$ESPTOOL_DIR/esptool.exe" ]; then + cp "$ESPTOOL_DIR/esptool.exe" ${{ github.workspace }}/bundled_tools/ + echo "esptool.exe bundled successfully" + ls -lh ${{ github.workspace }}/bundled_tools/esptool.exe + else + echo "Warning: esptool.exe not found in $ESPTOOL_DIR" + fi + - name: Build release package run: | chmod +x build_release.sh diff --git a/Flash Firmware (Windows).bat b/Flash Firmware (Windows).bat deleted file mode 100644 index 2ff109f..0000000 --- a/Flash Firmware (Windows).bat +++ /dev/null @@ -1,52 +0,0 @@ -@echo off -REM ===================================================== -REM SledLink Firmware Flash Tool - Windows Launcher -REM Double-click this file to flash pre-compiled firmware -REM ===================================================== - -echo. -echo ============================================ -echo SledLink Firmware Flash Tool -echo (Pre-compiled firmware) -echo ============================================ -echo. -echo Starting the firmware flash wizard... -echo. - -REM Change to the directory where this script is located -cd /d "%~dp0" - -REM Check if we're in the release folder (firmware subfolder exists) -if exist "%~dp0firmware" ( - REM We're in the release package - PowerShell -ExecutionPolicy Bypass -File "%~dp0flash_firmware.ps1" -) else if exist "%~dp0tools\flash_firmware.ps1" ( - REM Try tools subfolder - PowerShell -ExecutionPolicy Bypass -File "%~dp0tools\flash_firmware.ps1" -) else ( - echo. - echo ERROR: flash_firmware.ps1 not found! - echo. - echo This script should be run from a SledLink release package - echo that contains the firmware folder with pre-compiled binaries. - echo. - echo If you want to compile from source instead, use: - echo "Upload Firmware (Windows).bat" - echo. - pause - exit /b 1 -) - -REM If PowerShell failed, show error -if %ERRORLEVEL% NEQ 0 ( - echo. - echo ============================================ - echo There was a problem running the script - echo ============================================ - echo. - echo If you see a security error, try: - echo 1. Right-click this file - echo 2. Select "Run as administrator" - echo. - pause -) diff --git a/Flash Firmware.bat b/Flash Firmware.bat new file mode 100644 index 0000000..5ae3ab6 --- /dev/null +++ b/Flash Firmware.bat @@ -0,0 +1,51 @@ +@echo off +REM ===================================================== +REM SledLink Quick Flash Tool - Windows Launcher +REM Flash pre-compiled firmware - no compilation! +REM ===================================================== + +setlocal enabledelayedexpansion + +echo. +echo ============================================ +echo SledLink Quick Flash Tool +echo Pre-compiled firmware ready to flash +echo ============================================ +echo. + +REM Change to the script directory +cd /d "%~dp0" + +REM Check for flash script +if exist "%~dp0flash_firmware.ps1" ( + echo Launching flash tool... + echo. + PowerShell -ExecutionPolicy Bypass -File "%~dp0flash_firmware.ps1" +) else if exist "%~dp0tools\flash_firmware.ps1" ( + echo Launching flash tool... + echo. + PowerShell -ExecutionPolicy Bypass -File "%~dp0tools\flash_firmware.ps1" +) else ( + echo. + echo ERROR: flash_firmware.ps1 not found! + echo. + echo Make sure you extracted the entire release ZIP file with + echo all directories and files intact. + echo. + echo The flash script should be at: + echo - flash_firmware.ps1 (in release root), or + echo - tools\flash_firmware.ps1 (in release tools folder) + echo. + pause + exit /b 1 +) + +if %ERRORLEVEL% NEQ 0 ( + echo. + echo ============================================ + echo Flash tool exited with an error + echo ============================================ + echo. +) + +endlocal diff --git a/UPLOAD_GUIDE.md b/UPLOAD_GUIDE.md index a202b73..d3de1b1 100644 --- a/UPLOAD_GUIDE.md +++ b/UPLOAD_GUIDE.md @@ -9,8 +9,9 @@ The latest SledLink release package is available on GitHub: **[Download Latest Release](https://github.com/thompcd/SledLink/releases/latest)** Each release includes: +- Pre-compiled firmware binaries (ready to flash instantly) - Arduino source code for both controllers -- Upload scripts for Windows, Mac, and Linux +- Upload/flash scripts for Windows - This guide --- @@ -19,24 +20,64 @@ Each release includes: 1. **Your SledLink controller** (either the Sled or Judge unit) 2. **A USB cable** (micro-USB, the same type used for many Android phones) -3. **A computer** (Windows, Mac, or Linux) -4. **An internet connection** (needed to download tools on first use) +3. **A Windows computer** +4. **No internet connection needed** for flashing! --- -## Upload Firmware +## Upload Firmware - Two Methods -The firmware is compiled fresh from source code during the upload process. +There are two ways to update your controller's firmware: + +### **Method 1: Quick Flash (RECOMMENDED - 10 seconds)** + +Pre-compiled firmware flashes instantly. **This is the easiest method.** + +### **Method 2: Compile from Source (Advanced - 60+ seconds)** + +Compile the Arduino source code on your computer. For developers or customization. + +--- + +## Method 1: Quick Flash (RECOMMENDED) + +Pre-compiled firmware is ready to flash instantly - no compilation needed! + +### Windows - Quick Flash + +1. **Download the SledLink folder** to your computer from GitHub +2. **Extract the ZIP file** to a convenient location +3. **Connect your controller** via USB cable to your computer +4. **Double-click** `Flash Firmware.bat` in the main folder +5. **Select your controller type:** + - Type `1` if flashing a SLED Controller (with encoder) + - Type `2` if flashing a JUDGE Controller (display only) +6. **Flash happens automatically** - takes about 10 seconds +7. **Done!** Your controller restarts automatically + +That's it! Your system is now ready to use. + +### What is "Flashing"? + +Flashing writes the firmware directly to your controller's memory using pre-compiled binaries. It's much faster than compiling (10 seconds vs 60+ seconds) and requires no additional software beyond Windows. + +--- + +## Method 2: Compile from Source (Advanced) + +For developers who want to modify the firmware or use the full development environment. + +This method compiles the Arduino code fresh each time, taking 30-60 seconds longer than flashing. --- -### Windows +### Windows - Compile from Source 1. **Download the SledLink folder** to your computer 2. **Double-click** `Upload Firmware (Windows).bat` 3. **Follow the prompts** on screen -### Mac +### Mac - Compile from Source 1. **Download the SledLink folder** to your computer 2. **Open Terminal** (press Cmd+Space, type "Terminal", press Enter) @@ -55,7 +96,7 @@ The firmware is compiled fresh from source code during the upload process. ``` 6. **Follow the prompts** on screen -### Linux +### Linux - Compile from Source 1. **Download the SledLink folder** to your computer 2. **Open a terminal** in that folder @@ -71,16 +112,72 @@ The firmware is compiled fresh from source code during the upload process. --- -## What the Upload Script Does +## What the Compile-from-Source Script Does 1. **Checks for Arduino CLI** - The build tool. Installs it if needed. -2. **Sets up ESP32 support** - Downloads ESP32 tools (first time only) +2. **Sets up ESP32 support** - Downloads ESP32 tools (first time only, ~500MB) 3. **Asks which controller** - Sled or Judge 4. **Finds your controller** - Detects the connected USB device 5. **Compiles and uploads** - Builds fresh firmware from source and writes to your controller +--- + ## Troubleshooting +### Flash Method Issues + +#### "Flash Firmware.bat won't run" or Windows Defender blocks it + +- **Windows Defender SmartScreen:** Click **"More info"** then **"Run anyway"** +- **Right-click** the `.bat` file and select **"Run as administrator"** +- **Temporary solution:** Run from Command Prompt: `Flash Firmware.bat` + +#### "esptool.exe not found" + +- Make sure you **extracted the entire release ZIP** with all directories +- The file `firmware/tools/esptool.exe` must be present +- Try **re-downloading the release** if files seem to be missing + +#### "No device found" during flash + +Try these in order: + +1. **Different USB cable** - Some cables are "charge-only" and don't carry data +2. **Different USB port** - Try another port on your computer +3. **Wait a few seconds** after plugging in for Windows to recognize the device +4. **Check Device Manager:** + - Press `Win+X`, select "Device Manager" + - Look for your device under "Ports (COM & LPT)" + - If it shows a warning icon, you need USB drivers + +#### "Flash failed" or timeout error + +1. **Hold the BOOT button** on the ESP32 board during the first 5 seconds of flash + - The flash tool will tell you when it's starting + - You can release BOOT after it begins +2. **Try a different USB cable** (charge-only cables won't work) +3. **Try a different USB port** +4. **Close other programs** that might be using the serial port (Arduino IDE, PuTTY, etc.) +5. **Try restarting your computer** + +#### USB Driver Issues + +If Windows doesn't recognize your device: + +**CP210x drivers** (for some ESP32 boards): +- Download: [CP210x USB to UART Bridge VCP Drivers](https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers) +- Install and restart your computer + +**CH340 drivers** (for other ESP32 boards): +- Download: CH340 drivers (search "CH340 driver Windows") +- Install and restart your computer + +If you're not sure which driver you need, try one - it won't hurt to have both installed. + +--- + +### Method 2: Compile from Source - Troubleshooting + ### "No serial devices found" - **Try a different USB cable.** Some cables are "charge only" and don't have data wires. @@ -133,13 +230,14 @@ Then **log out and back in** for the change to take effect. - **Receives** and displays distance - No encoder connected -## After Uploading +## After Flashing or Uploading Firmware -After firmware is uploaded: +After your controller has been updated (whether using flash or compile method): 1. The controller will **restart automatically** 2. The LCD should show "SledLink" and then the startup screen -3. You can use the **serial monitor** option in the script to see diagnostic output +3. Your system is ready to use! +4. For compile-from-source method: You can use the **serial monitor** option in the script to see diagnostic output ## Need Help? diff --git a/arduino/README.md b/arduino/README.md index cb01b55..c9c8aaf 100644 --- a/arduino/README.md +++ b/arduino/README.md @@ -8,7 +8,7 @@ SledLink consists of two ESP32 units communicating wirelessly via ESP-NOW: ``` ┌─────────────────────┐ ESP-NOW ┌─────────────────────┐ -│ SLED CONTROLLER │ ───────────► │ JUDGE CONTROLLER │ +│ SLED CONTROLLER │ ───────────► │ JUDGE CONTROLLER │ │ (on the sled) │ │ (at judge's table) │ │ │ │ │ │ - Rotary encoder │ │ - LCD display │ diff --git a/build_release.sh b/build_release.sh index 3f9f004..547c7e5 100644 --- a/build_release.sh +++ b/build_release.sh @@ -64,7 +64,9 @@ fi echo "" echo "Creating release directory..." rm -rf "$OUTPUT_DIR" -mkdir -p "$OUTPUT_DIR/firmware" +mkdir -p "$OUTPUT_DIR/firmware/SledController" +mkdir -p "$OUTPUT_DIR/firmware/JudgeController" +mkdir -p "$OUTPUT_DIR/firmware/tools" mkdir -p "$OUTPUT_DIR/tools" mkdir -p "$OUTPUT_DIR/source" @@ -79,6 +81,45 @@ chmod +x "$OUTPUT_DIR/tools/upload_firmware.sh" echo "Copying source code..." cp -r "$SCRIPT_DIR/arduino" "$OUTPUT_DIR/source/" +# Compile firmware binaries +echo "" +echo "Compiling firmware binaries..." +echo " SledController..." +arduino-cli compile --fqbn esp32:esp32:esp32 --export-binaries \ + --output-dir "$SCRIPT_DIR/firmware_binaries/SledController" \ + "$SCRIPT_DIR/arduino/SledController" 2>&1 | grep -E "(Compiling|Archiving|Sketch uses|Global variables)" || true + +echo " JudgeController..." +arduino-cli compile --fqbn esp32:esp32:esp32 --export-binaries \ + --output-dir "$SCRIPT_DIR/firmware_binaries/JudgeController" \ + "$SCRIPT_DIR/arduino/JudgeController" 2>&1 | grep -E "(Compiling|Archiving|Sketch uses|Global variables)" || true + +# Package binaries into release +echo "Packaging firmware binaries..." +for controller in SledController JudgeController; do + BIN_DIR="$SCRIPT_DIR/firmware_binaries/$controller" + OUT_DIR="$OUTPUT_DIR/firmware/$controller" + + if [ -f "$BIN_DIR/${controller}.ino.bin" ]; then + cp "$BIN_DIR/${controller}.ino.bin" "$OUT_DIR/firmware.bin" + cp "$BIN_DIR/${controller}.ino.bootloader.bin" "$OUT_DIR/bootloader.bin" + cp "$BIN_DIR/${controller}.ino.partitions.bin" "$OUT_DIR/partitions.bin" + echo " ✓ $controller" + else + echo " ✗ $controller - binaries not found!" + fi +done + +# Extract and copy esptool +echo "Extracting esptool for Windows..." +ESPTOOL_DIR=$(find ~/.arduino15/packages/esp32/tools/esptool_py -type d -maxdepth 2 2>/dev/null | head -1) +if [ -f "$ESPTOOL_DIR/esptool.exe" ]; then + cp "$ESPTOOL_DIR/esptool.exe" "$OUTPUT_DIR/firmware/tools/" + echo " ✓ esptool.exe bundled" +else + echo " ⚠ esptool.exe not found - Windows flashing may not work" +fi + # Copy documentation echo "Copying documentation..." cp "$SCRIPT_DIR/UPLOAD_GUIDE.md" "$OUTPUT_DIR/" @@ -98,35 +139,38 @@ RELEASE INFORMATION Build Date: $(date +%Y-%m-%d) Download: https://github.com/thompcd/SledLink/releases/tag/$VERSION -This release contains source code and tools to compile and upload firmware to the SledLink system. +This release contains PRE-COMPILED firmware ready to flash instantly! CONTENTS -------- - source/ - Arduino source code + firmware/ - Pre-compiled firmware binaries (ready to flash) + SledController/ - Sled controller binaries + JudgeController/ - Judge controller binaries + tools/ - esptool.exe for Windows + + Flash Firmware.bat - EASIEST METHOD: Double-click to flash firmware + + source/ - Arduino source code (for advanced users) arduino/SledController/ - Sled controller source arduino/JudgeController/ - Judge controller source - tools/ - Upload utilities - upload_firmware.sh - Mac/Linux upload script - upload_firmware.ps1 - Windows PowerShell upload script + tools/ - Upload utilities (for compiling from source) + upload_firmware.sh - Mac/Linux upload script (compile-on-upload) + upload_firmware.ps1 - Windows PowerShell upload script (compile-on-upload) - Upload Firmware (Windows).bat - Double-click to upload firmware + Upload Firmware (Windows).bat - Legacy: Compile and upload (slow, ~60 seconds) -QUICK START - UPLOAD FIRMWARE ------------------------------ -The firmware is compiled fresh from source code during upload. +QUICK START - FLASH FIRMWARE (RECOMMENDED) +------------------------------------------- +Pre-compiled firmware flashes in ~10 seconds - no compilation needed! Windows: 1. Connect the controller via USB - 2. Double-click "Upload Firmware (Windows).bat" - 3. Follow the prompts - -Mac/Linux: - 1. Connect the controller via USB - 2. Open Terminal in this folder - 3. Run: ./tools/upload_firmware.sh - 4. Follow the prompts + 2. Double-click "Flash Firmware.bat" + 3. Select controller type (1=Sled, 2=Judge) + 4. Firmware flashes automatically! + 5. Controller restarts automatically WHICH CONTROLLER IS WHICH? @@ -148,13 +192,13 @@ See UPLOAD_GUIDE.md for detailed troubleshooting steps. Common issues: - "No device found" - Try a different USB cable (some are charge-only) - - "Upload failed" - Hold BOOT button on ESP32 during upload + - "Flash failed" - Hold BOOT button on ESP32 during flash - Driver issues - Install CP210x or CH340 USB driver for your OS SUPPORT ------- -For issues, visit: https://github.com/tulsasoftware/SledLink/issues +For issues, visit: https://github.com/thompcd/SledLink/issues ================================================================================ HEREDOC diff --git a/flash_firmware.ps1 b/flash_firmware.ps1 index 2d3f81d..b75f8d3 100644 --- a/flash_firmware.ps1 +++ b/flash_firmware.ps1 @@ -1,152 +1,147 @@ # -# SledLink Firmware Flash Script for Windows -# Flashes pre-compiled firmware using esptool +# SledLink Quick Flash Script for Windows +# Flashes pre-compiled firmware - no compilation required! # $ErrorActionPreference = "Stop" +# Get the directory where this script is located $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path -$FirmwareDir = Join-Path $ScriptDir "firmware" -$script:Esptool = "" -$script:SelectedPort = "" -$script:SelectedController = "" +# Detect firmware directory location +# Release package root: firmware/ directory at same level as script +# Release package tools/: firmware/ directory at parent level +# Repo: firmware_binaries/ directory at root + +if (Test-Path (Join-Path $ScriptDir "firmware")) { + # Script is at release root + $FirmwareDir = Join-Path $ScriptDir "firmware" +} elseif (Test-Path (Join-Path $ScriptDir ".." "firmware")) { + # Script is in tools/ subdirectory + $FirmwareDir = Join-Path (Split-Path -Parent $ScriptDir) "firmware" +} elseif (Test-Path (Join-Path $ScriptDir "firmware_binaries")) { + # Development mode - use compiled binaries directly + $FirmwareDir = Join-Path $ScriptDir "firmware_binaries" +} else { + Write-Host "" + Write-Host "ERROR: Firmware directory not found!" -ForegroundColor Red + Write-Host "" + Write-Host "This script should be run from the SledLink release package." -ForegroundColor Yellow + Write-Host "Make sure you extracted the entire ZIP file with all directories." -ForegroundColor Yellow + Write-Host "" + Write-Host "Press any key to exit..." -ForegroundColor Gray + $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") + exit 1 +} + +# Find esptool.exe +$EsptoolPath = Join-Path $FirmwareDir "tools" "esptool.exe" +if (-not (Test-Path $EsptoolPath)) { + # Try alternative location in release package + $EsptoolPath = Join-Path (Split-Path -Parent $FirmwareDir) "firmware" "tools" "esptool.exe" +} + +############################################################################# +# Helper Functions +############################################################################# function Write-Header { Clear-Host Write-Host "" Write-Host "================================================================" -ForegroundColor Cyan - Write-Host " SledLink Firmware Flash Tool for Windows" -ForegroundColor White - Write-Host " Flash Pre-Compiled Firmware" -ForegroundColor Gray + Write-Host " SledLink Quick Flash Tool" -ForegroundColor White + Write-Host " Pre-Compiled Firmware (No Compilation Required)" -ForegroundColor Gray Write-Host "================================================================" -ForegroundColor Cyan Write-Host "" } -function Test-Esptool { - # Check if esptool is in PATH - $esptoolExe = Get-Command "esptool" -ErrorAction SilentlyContinue - if ($esptoolExe) { - $script:Esptool = "esptool" - return $true - } - - $esptoolPy = Get-Command "esptool.py" -ErrorAction SilentlyContinue - if ($esptoolPy) { - $script:Esptool = "esptool.py" - return $true - } - - # Try Python module - try { - $result = & python -m esptool version 2>&1 - if ($LASTEXITCODE -eq 0) { - $script:Esptool = "python -m esptool" - return $true - } - } catch {} - - try { - $result = & python3 -m esptool version 2>&1 - if ($LASTEXITCODE -eq 0) { - $script:Esptool = "python3 -m esptool" - return $true - } - } catch {} - - return $false +function Write-Success { + param([string]$Message) + Write-Host $Message -ForegroundColor Green } -function Install-Esptool { - Write-Host "esptool is not installed." -ForegroundColor Yellow - Write-Host "" - Write-Host "esptool is required to flash pre-compiled firmware." - Write-Host "" - - $hasPip = Get-Command "pip" -ErrorAction SilentlyContinue - if (-not $hasPip) { - $hasPip = Get-Command "pip3" -ErrorAction SilentlyContinue - } - - if ($hasPip) { - $response = Read-Host "Install esptool now? (yes/no)" - if ($response -match "^[Yy]") { - Write-Host "" - Write-Host "Installing esptool..." -ForegroundColor Cyan - & pip install esptool - if ($LASTEXITCODE -eq 0) { - return $true - } - } - } else { - Write-Host "Python is required to install esptool." -ForegroundColor Yellow - Write-Host "" - Write-Host "Install Python from: https://www.python.org/downloads/" -ForegroundColor Cyan - Write-Host "Make sure to check 'Add Python to PATH' during installation!" - Write-Host "" - Write-Host "After installing Python, run: pip install esptool" - } - return $false +function Write-Error-Custom { + param([string]$Message) + Write-Host $Message -ForegroundColor Red } function Get-SerialPorts { + # Get COM ports using .NET which is most reliable $ports = @() + try { - $usbPorts = Get-WmiObject Win32_PnPEntity | Where-Object { - $_.Name -match "COM\d+" -and ( - $_.Name -match "USB" -or - $_.Name -match "Serial" -or - $_.Name -match "CH340" -or - $_.Name -match "CP210" -or - $_.Name -match "FTDI" -or - $_.Name -match "Silicon Labs" - ) - } - foreach ($port in $usbPorts) { - if ($port.Name -match "(COM\d+)") { + # Get all available COM ports + $comPorts = [System.IO.Ports.SerialPort]::GetPortNames() + + if ($comPorts -and $comPorts.Count -gt 0) { + # Try to get friendly names from WMI + try { + $devices = Get-WmiObject Win32_PnPEntity | Where-Object { $_.Name -match "COM\d+" } + $deviceMap = @{} + foreach ($device in $devices) { + if ($device.Name -match "(COM\d+)") { + $deviceMap[$Matches[1]] = $device.Name + } + } + } catch { + $deviceMap = @{} + } + + # Create port objects with both Port and Name + foreach ($comPort in $comPorts) { + $displayName = if ($deviceMap.ContainsKey($comPort)) { + $deviceMap[$comPort] + } else { + $comPort + } + $ports += @{ - Port = $Matches[1] - Name = $port.Name + Port = $comPort + Name = $displayName } } } } catch {} + # If no ports found, try WMI as fallback if ($ports.Count -eq 0) { try { - $comPorts = [System.IO.Ports.SerialPort]::GetPortNames() - foreach ($port in $comPorts) { - $ports += @{ - Port = $port - Name = $port + $devices = Get-WmiObject Win32_PnPEntity | Where-Object { $_.Name -match "COM\d+" } + foreach ($device in $devices) { + if ($device.Name -match "(COM\d+)") { + $ports += @{ + Port = $Matches[1] + Name = $device.Name + } } } } catch {} } - return $ports + + return , $ports } function Select-Controller { - Write-Host "Which controller do you want to flash?" -ForegroundColor White + Write-Host "Which controller do you want to flash?" -ForegroundColor Cyan + Write-Host "" + Write-Host " 1) SLED Controller" -ForegroundColor White + Write-Host " - Goes on the sled with the measuring wheel" -ForegroundColor Gray + Write-Host " - Has the encoder connected" -ForegroundColor Gray Write-Host "" - Write-Host " 1) SLED Controller - goes on the sled, has encoder" -ForegroundColor Gray - Write-Host " 2) JUDGE Controller - judge's table display" -ForegroundColor Gray + Write-Host " 2) JUDGE Controller" -ForegroundColor White + Write-Host " - Stays at the judge's table" -ForegroundColor Gray + Write-Host " - Displays distance measurements" -ForegroundColor Gray Write-Host "" while ($true) { - $choice = Read-Host "Enter 1 or 2" + $choice = Read-Host "Select controller (1 or 2)" + switch ($choice) { - "1" { - $script:SelectedController = "SledController" - Write-Host "[OK] Selected: SLED Controller" -ForegroundColor Green - return - } - "2" { - $script:SelectedController = "JudgeController" - Write-Host "[OK] Selected: JUDGE Controller" -ForegroundColor Green - return - } + "1" { return "SledController" } + "2" { return "JudgeController" } default { - Write-Host "Please enter 1 or 2" -ForegroundColor Red + Write-Host "Please enter 1 or 2" -ForegroundColor Yellow + Write-Host "" } } } @@ -154,167 +149,202 @@ function Select-Controller { function Select-Port { Write-Host "" - Write-Host "Connect the controller via USB, then press ENTER" -ForegroundColor Yellow - Read-Host + Write-Host "Connecting to device..." -ForegroundColor Cyan + Write-Host "Make sure your controller is connected via USB." -ForegroundColor Yellow + Write-Host "" + Write-Host "Press ENTER to scan for devices..." + $null = Read-Host + + Write-Host "Scanning for USB devices..." -ForegroundColor Cyan - Write-Host "Scanning for devices..." -ForegroundColor Cyan $ports = Get-SerialPorts if ($ports.Count -eq 0) { - Write-Host "[X] No serial devices found!" -ForegroundColor Red Write-Host "" - Write-Host "Try:" -ForegroundColor Yellow - Write-Host " - Different USB cable (some are charge-only)" - Write-Host " - Different USB port" - Write-Host " - Install USB driver (CP210x or CH340)" - return $false + Write-Error-Custom "ERROR: No USB devices found!" + Write-Host "" + Write-Host "Troubleshooting:" -ForegroundColor Yellow + Write-Host " 1. Try a different USB cable (some are charge-only)" -ForegroundColor Yellow + Write-Host " 2. Try a different USB port on your computer" -ForegroundColor Yellow + Write-Host " 3. Wait a few seconds and try again" -ForegroundColor Yellow + Write-Host " 4. Install USB drivers (CP210x or CH340)" -ForegroundColor Yellow + Write-Host "" + Write-Host "For more help, see UPLOAD_GUIDE.md in the release package." -ForegroundColor Yellow + Write-Host "" + Write-Host "Press any key to exit..." -ForegroundColor Gray + $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") + exit 1 } if ($ports.Count -eq 1) { - $script:SelectedPort = $ports[0].Port - Write-Host "[OK] Found: $($ports[0].Name)" -ForegroundColor Green - } else { - Write-Host "Multiple devices found:" -ForegroundColor White - for ($i = 0; $i -lt $ports.Count; $i++) { - Write-Host " $($i + 1)) $($ports[$i].Name)" - } - while ($true) { - $choice = Read-Host "Select device (1-$($ports.Count))" - $choiceNum = 0 - if ([int]::TryParse($choice, [ref]$choiceNum) -and $choiceNum -ge 1 -and $choiceNum -le $ports.Count) { - $script:SelectedPort = $ports[$choiceNum - 1].Port - Write-Host "[OK] Selected: $($ports[$choiceNum - 1].Name)" -ForegroundColor Green - break - } else { - Write-Host "Please enter a number between 1 and $($ports.Count)" -ForegroundColor Red - } + $port = $ports[0].Port + Write-Success "✓ Found device on $port" + return $port + } + + # Multiple ports - let user choose + Write-Host "" + Write-Host "Multiple devices found:" -ForegroundColor Cyan + for ($i = 0; $i -lt $ports.Count; $i++) { + Write-Host " $($i+1)) $($ports[$i].Port) - $($ports[$i].Name)" -ForegroundColor White + } + Write-Host "" + + while ($true) { + $choice = Read-Host "Select device (1-$($ports.Count))" + + if ($choice -ge 1 -and $choice -le $ports.Count) { + $port = $ports[$choice - 1].Port + Write-Success "✓ Selected $port" + return $port + } else { + Write-Host "Please enter a number between 1 and $($ports.Count)" -ForegroundColor Yellow } } - return $true } function Flash-Firmware { - $firmwarePath = Join-Path $FirmwareDir "$($script:SelectedController).bin" - $bootloaderPath = Join-Path $FirmwareDir "$($script:SelectedController).bootloader.bin" - $partitionsPath = Join-Path $FirmwareDir "$($script:SelectedController).partitions.bin" + param( + [string]$Controller, + [string]$Port + ) + + $controllerDir = Join-Path $FirmwareDir $Controller + $appBin = Join-Path $controllerDir "firmware.bin" + $bootBin = Join-Path $controllerDir "bootloader.bin" + $partBin = Join-Path $controllerDir "partitions.bin" + + # Verify firmware files exist + if (-not (Test-Path $appBin)) { + Write-Host "" + Write-Error-Custom "ERROR: Firmware file not found!" + Write-Host "Expected: $appBin" -ForegroundColor Yellow + Write-Host "" + Write-Host "The release package may be incomplete. Re-download from:" -ForegroundColor Yellow + Write-Host "https://github.com/thompcd/SledLink/releases" -ForegroundColor Yellow + Write-Host "" + Write-Host "Press any key to exit..." -ForegroundColor Gray + $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") + exit 1 + } - if (-not (Test-Path $firmwarePath)) { - Write-Host "[X] Firmware file not found: $firmwarePath" -ForegroundColor Red - return $false + if (-not (Test-Path $EsptoolPath)) { + Write-Host "" + Write-Error-Custom "ERROR: esptool.exe not found!" + Write-Host "Expected: $EsptoolPath" -ForegroundColor Yellow + Write-Host "" + Write-Host "The release package may be incomplete. Make sure you extracted" -ForegroundColor Yellow + Write-Host "the entire ZIP file with all directories." -ForegroundColor Yellow + Write-Host "" + Write-Host "Press any key to exit..." -ForegroundColor Gray + $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") + exit 1 } + # Show confirmation Write-Host "" - Write-Host "Ready to flash:" -ForegroundColor White - Write-Host " Controller: $($script:SelectedController)" - Write-Host " Port: $($script:SelectedPort)" - Write-Host " Firmware: $firmwarePath" + Write-Host "Ready to flash:" -ForegroundColor Cyan + Write-Host " Controller: $Controller" -ForegroundColor White + Write-Host " Port: $Port" -ForegroundColor White + Write-Host " Firmware: $appBin" -ForegroundColor Gray Write-Host "" - Write-Host "Do NOT disconnect during flash!" -ForegroundColor Yellow + Write-Host "DO NOT disconnect the USB cable during flashing!" -ForegroundColor Yellow Write-Host "" - $confirm = Read-Host "Start flash? (yes/no)" - if ($confirm -notmatch "^[Yy]") { - Write-Host "Cancelled." -ForegroundColor Yellow - return $false + $confirm = Read-Host "Continue? (yes/no)" + if ($confirm -ne "yes" -and $confirm -ne "y") { + Write-Host "" + Write-Host "Flash cancelled." -ForegroundColor Yellow + Write-Host "" + Write-Host "Press any key to exit..." -ForegroundColor Gray + $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") + exit 0 } + # Flash the firmware Write-Host "" Write-Host "Flashing firmware..." -ForegroundColor Cyan + Write-Host "This may take 10-30 seconds..." -ForegroundColor Gray Write-Host "" try { - # Build the esptool command + # Build esptool command $esptoolArgs = @( "--chip", "esp32", - "--port", $script:SelectedPort, + "--port", $Port, "--baud", "460800", "--before", "default_reset", "--after", "hard_reset", - "write_flash", "-z", + "write_flash", + "-z", "--flash_mode", "dio", "--flash_freq", "40m", "--flash_size", "detect", - "0x1000", $bootloaderPath, - "0x8000", $partitionsPath, - "0x10000", $firmwarePath + "0x1000", $bootBin, + "0x8000", $partBin, + "0x10000", $appBin ) - if ($script:Esptool -match "python") { - # It's a Python module call - $parts = $script:Esptool -split " " - $python = $parts[0] - & $python -m esptool @esptoolArgs - } else { - & $script:Esptool @esptoolArgs - } + # Execute esptool + & $EsptoolPath $esptoolArgs + $exitCode = $LASTEXITCODE - if ($LASTEXITCODE -ne 0) { - throw "esptool returned error code $LASTEXITCODE" + if ($exitCode -eq 0) { + Write-Host "" + Write-Host "========================================" -ForegroundColor Green + Write-Host " FLASH SUCCESSFUL!" -ForegroundColor Green + Write-Host "========================================" -ForegroundColor Green + Write-Host "" + Write-Host "Your controller will restart automatically." -ForegroundColor White + Write-Host "" + Write-Host "Next steps:" -ForegroundColor Cyan + Write-Host " 1. The controller should boot up in a few seconds" -ForegroundColor White + Write-Host " 2. The LCD display should show SledLink" -ForegroundColor White + Write-Host " 3. Your system is ready to use!" -ForegroundColor White + Write-Host "" + Write-Host "Press any key to exit..." -ForegroundColor Gray + $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") + } else { + Write-Host "" + Write-Error-Custom "Flash failed! (Exit code: $exitCode)" + Write-Host "" + Write-Host "Troubleshooting:" -ForegroundColor Yellow + Write-Host " 1. Hold the BOOT button on the ESP32 while flashing" -ForegroundColor Yellow + Write-Host " 2. Try a different USB cable (charge-only cables won't work)" -ForegroundColor Yellow + Write-Host " 3. Try a different USB port" -ForegroundColor Yellow + Write-Host " 4. Close other programs using the serial port" -ForegroundColor Yellow + Write-Host "" + Write-Host "For more help, see UPLOAD_GUIDE.md in the release package." -ForegroundColor Yellow + Write-Host "" + Write-Host "Press any key to exit..." -ForegroundColor Gray + $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") + exit 1 } - - Write-Host "" - Write-Host "========================================================" -ForegroundColor Green - Write-Host " FIRMWARE FLASH COMPLETE!" -ForegroundColor Green - Write-Host "========================================================" -ForegroundColor Green - Write-Host "" - Write-Host "The controller will restart automatically." - return $true - } - catch { - Write-Host "[X] Flash failed: $_" -ForegroundColor Red - Write-Host "" - Write-Host "Try:" -ForegroundColor Yellow - Write-Host " - Hold the BOOT button on the ESP32 while flashing" - Write-Host " - Unplug and replug the USB cable" - Write-Host " - Use a different USB port" - return $false - } -} - -# Main -Write-Header - -Write-Host "This tool flashes pre-compiled firmware to your SledLink controller." -Write-Host "No compilation needed - just select your controller type and port." -Write-Host "" -Write-Host "Press ENTER to continue..." -ForegroundColor Yellow -Read-Host - -# Check for esptool -if (-not (Test-Esptool)) { - if (-not (Install-Esptool)) { - Write-Host "[X] Cannot continue without esptool." -ForegroundColor Red + } catch { Write-Host "" - Write-Host "Press any key to exit..." -ForegroundColor Yellow - $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") - exit 1 - } - if (-not (Test-Esptool)) { - Write-Host "[X] esptool installation failed." -ForegroundColor Red + Write-Error-Custom "Error during flashing: $_" Write-Host "" - Write-Host "Press any key to exit..." -ForegroundColor Yellow + Write-Host "Press any key to exit..." -ForegroundColor Gray $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") exit 1 } } -Write-Host "[OK] esptool found" -ForegroundColor Green -Write-Host "" +############################################################################# +# Main Script +############################################################################# + +Write-Header -# Select controller -Select-Controller +Write-Host "This tool flashes pre-compiled firmware to your SledLink controller." -ForegroundColor White +Write-Host "Flashing takes about 10 seconds - no compilation needed!" -ForegroundColor White +Write-Host "" -# Select port -if (-not (Select-Port)) { - Write-Host "" - Write-Host "Press any key to exit..." -ForegroundColor Yellow - $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") - exit 1 -} +# Step 1: Select controller +$controller = Select-Controller -# Flash -Flash-Firmware +# Step 2: Select port +$port = Select-Port -Write-Host "" -Write-Host "Press any key to exit..." -ForegroundColor Yellow -$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") +# Step 3: Flash firmware +Flash-Firmware -Controller $controller -Port $port diff --git a/flash_firmware.sh b/flash_firmware.sh deleted file mode 100644 index 443c4a0..0000000 --- a/flash_firmware.sh +++ /dev/null @@ -1,269 +0,0 @@ -#!/bin/bash -# -# SledLink Firmware Flash Script -# Flashes pre-compiled firmware using esptool -# -# This script is for use with the release package containing -# pre-compiled .bin files. For compiling from source, use upload_firmware.sh -# - -set -e - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -FIRMWARE_DIR="$SCRIPT_DIR/firmware" - -# Colors -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -CYAN='\033[0;36m' -BOLD='\033[1m' -NC='\033[0m' - -if [ ! -t 1 ]; then - RED='' GREEN='' YELLOW='' CYAN='' BOLD='' NC='' -fi - -ESPTOOL="" -SELECTED_PORT="" -SELECTED_CONTROLLER="" - -print_header() { - clear - echo "" - echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}" - echo -e "${CYAN}║${NC}${BOLD} SledLink Firmware Flash Tool ${NC}${CYAN}║${NC}" - echo -e "${CYAN}║${NC} Flash Pre-Compiled Firmware ${CYAN}║${NC}" - echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}" - echo "" -} - -check_esptool() { - if command -v esptool.py &> /dev/null; then - ESPTOOL="esptool.py" - return 0 - elif command -v esptool &> /dev/null; then - ESPTOOL="esptool" - return 0 - elif python3 -m esptool version &> /dev/null 2>&1; then - ESPTOOL="python3 -m esptool" - return 0 - elif python -m esptool version &> /dev/null 2>&1; then - ESPTOOL="python -m esptool" - return 0 - fi - return 1 -} - -install_esptool() { - echo -e "${YELLOW}esptool is not installed.${NC}" - echo "" - echo "esptool is required to flash pre-compiled firmware." - echo "" - - local pip_cmd="" - if command -v pip3 &> /dev/null; then - pip_cmd="pip3" - elif command -v pip &> /dev/null; then - pip_cmd="pip" - fi - - if [ -n "$pip_cmd" ]; then - echo -e "${BOLD}Install esptool now?${NC} (yes/no): " - read -r response - if [[ "$response" =~ ^[Yy] ]]; then - echo "" - echo "Installing esptool..." - $pip_cmd install esptool - return 0 - fi - else - echo "Python pip is required to install esptool." - echo "" - echo "Install Python from: https://www.python.org/downloads/" - echo "Then run: pip install esptool" - fi - return 1 -} - -get_serial_ports() { - case "$(uname -s)" in - Darwin*) - for port in /dev/cu.usbserial* /dev/cu.wchusbserial* /dev/cu.SLAB* /dev/cu.usbmodem*; do - [ -e "$port" ] && echo "$port" - done - ;; - *) - for port in /dev/ttyUSB* /dev/ttyACM*; do - [ -e "$port" ] && echo "$port" - done - ;; - esac -} - -select_controller() { - echo -e "${BOLD}Which controller do you want to flash?${NC}" - echo "" - echo " 1) SLED Controller - goes on the sled, has encoder" - echo " 2) JUDGE Controller - judge's table display" - echo "" - - while true; do - echo -n "Enter 1 or 2: " - read -r choice - case "$choice" in - 1) - SELECTED_CONTROLLER="SledController" - echo -e "${GREEN}✓ Selected: SLED Controller${NC}" - return - ;; - 2) - SELECTED_CONTROLLER="JudgeController" - echo -e "${GREEN}✓ Selected: JUDGE Controller${NC}" - return - ;; - *) - echo -e "${RED}Please enter 1 or 2${NC}" - ;; - esac - done -} - -select_port() { - echo "" - echo -e "${YELLOW}Connect the controller via USB, then press ENTER${NC}" - read -r - - echo "Scanning for devices..." - local ports=($(get_serial_ports)) - - if [ ${#ports[@]} -eq 0 ]; then - echo -e "${RED}✗ No serial devices found!${NC}" - echo "" - echo "Try:" - echo " - Different USB cable (some are charge-only)" - echo " - Different USB port" - echo " - Install USB driver (CP210x or CH340)" - - if [ "$(uname -s)" = "Linux" ]; then - echo "" - echo "Linux users: You may need to add yourself to the dialout group:" - echo " sudo usermod -a -G dialout \$USER" - echo "Then log out and back in." - fi - return 1 - fi - - if [ ${#ports[@]} -eq 1 ]; then - SELECTED_PORT="${ports[0]}" - echo -e "${GREEN}✓ Found: $SELECTED_PORT${NC}" - else - echo "Multiple devices found:" - for i in "${!ports[@]}"; do - echo " $((i+1))) ${ports[$i]}" - done - while true; do - echo -n "Select device (1-${#ports[@]}): " - read -r choice - if [ "$choice" -ge 1 ] 2>/dev/null && [ "$choice" -le ${#ports[@]} ]; then - SELECTED_PORT="${ports[$((choice-1))]}" - echo -e "${GREEN}✓ Selected: $SELECTED_PORT${NC}" - break - else - echo -e "${RED}Please enter a number between 1 and ${#ports[@]}${NC}" - fi - done - fi - return 0 -} - -flash_firmware() { - local firmware_path="$FIRMWARE_DIR/$SELECTED_CONTROLLER.bin" - local bootloader_path="$FIRMWARE_DIR/$SELECTED_CONTROLLER.bootloader.bin" - local partitions_path="$FIRMWARE_DIR/$SELECTED_CONTROLLER.partitions.bin" - - # Check if firmware directory exists - if [ ! -d "$FIRMWARE_DIR" ]; then - echo -e "${RED}✗ Firmware directory not found: $FIRMWARE_DIR${NC}" - echo "" - echo "This script expects pre-compiled firmware in a 'firmware' folder." - echo "If you want to compile from source, use upload_firmware.sh instead." - return 1 - fi - - if [ ! -f "$firmware_path" ]; then - echo -e "${RED}✗ Firmware file not found: $firmware_path${NC}" - return 1 - fi - - echo "" - echo -e "${BOLD}Ready to flash:${NC}" - echo " Controller: $SELECTED_CONTROLLER" - echo " Port: $SELECTED_PORT" - echo " Firmware: $firmware_path" - echo "" - echo -e "${YELLOW}Do NOT disconnect during flash!${NC}" - echo "" - echo -n "Start flash? (yes/no): " - read -r confirm - if [[ ! "$confirm" =~ ^[Yy] ]]; then - echo "Cancelled." - return 1 - fi - - echo "" - echo "Flashing firmware..." - echo "" - - # Flash the firmware - $ESPTOOL --chip esp32 --port "$SELECTED_PORT" --baud 460800 \ - --before default_reset --after hard_reset \ - write_flash -z \ - --flash_mode dio --flash_freq 40m --flash_size detect \ - 0x1000 "$bootloader_path" \ - 0x8000 "$partitions_path" \ - 0x10000 "$firmware_path" - - echo "" - echo -e "${GREEN}════════════════════════════════════════════════════${NC}" - echo -e "${GREEN} FIRMWARE FLASH COMPLETE!${NC}" - echo -e "${GREEN}════════════════════════════════════════════════════${NC}" - echo "" - echo "The controller will restart automatically." - return 0 -} - -# Main -print_header - -echo "This tool flashes pre-compiled firmware to your SledLink controller." -echo "No compilation needed - just select your controller type and port." -echo "" -echo -e "${YELLOW}Press ENTER to continue...${NC}" -read -r - -# Check for esptool -if ! check_esptool; then - if ! install_esptool; then - echo -e "${RED}Cannot continue without esptool.${NC}" - exit 1 - fi - if ! check_esptool; then - echo -e "${RED}esptool installation failed.${NC}" - exit 1 - fi -fi - -echo -e "${GREEN}✓ esptool found${NC}" -echo "" - -# Select controller -select_controller - -# Select port -if ! select_port; then - exit 1 -fi - -# Flash -flash_firmware