diff --git a/examples/ruvLLM/esp32-flash/README.md b/examples/ruvLLM/esp32-flash/README.md index f4d43959..ef10366e 100644 --- a/examples/ruvLLM/esp32-flash/README.md +++ b/examples/ruvLLM/esp32-flash/README.md @@ -77,11 +77,29 @@ cd ruvector/examples/ruvLLM/esp32-flash ```powershell git clone https://github.com/ruvnet/ruvector cd ruvector\examples\ruvLLM\esp32-flash -.\install.ps1 # Install deps (restart PowerShell after) -.\install.ps1 build # Build -.\install.ps1 flash COM6 # Flash + +# One-time setup (installs espup, espflash, toolchain) +.\scripts\windows\setup.ps1 + +# Load environment (run in each new terminal) +. .\scripts\windows\env.ps1 + +# Build (auto-detects toolchain paths) +.\scripts\windows\build.ps1 + +# Flash (auto-detects COM port) +.\scripts\windows\flash.ps1 + +# Or specify port manually +.\scripts\windows\flash.ps1 -Port COM6 ``` +**Windows Features:** +- ✅ Auto-detects ESP toolchain paths (no hardcoding) +- ✅ Auto-detects COM ports +- ✅ Dynamic libclang/Python path resolution +- ✅ Single setup script for first-time users + ### Option 3: Manual Build ```bash diff --git a/examples/ruvLLM/esp32-flash/npm/bin/cli.js b/examples/ruvLLM/esp32-flash/npm/bin/cli.js index a74a5967..9d657b10 100644 --- a/examples/ruvLLM/esp32-flash/npm/bin/cli.js +++ b/examples/ruvLLM/esp32-flash/npm/bin/cli.js @@ -94,13 +94,31 @@ function detectPort() { try { if (platform === 'win32') { - // Windows: Look for COM ports - const result = execSync('wmic path Win32_SerialPort get DeviceID', { encoding: 'utf8' }); - const ports = result.split('\n').filter(line => line.includes('COM')).map(line => line.trim()); - return ports[0] || 'COM3'; + // Windows: Use PowerShell for better COM port detection + try { + const result = execSync( + 'powershell -Command "[System.IO.Ports.SerialPort]::GetPortNames() | Sort-Object { [int]($_ -replace \'COM\', \'\') }"', + { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] } + ); + const ports = result.trim().split('\n').filter(p => p.match(/COM\d+/)); + if (ports.length > 0) { + return ports[0].trim(); + } + } catch { + // Fallback to wmic + const result = execSync('wmic path Win32_SerialPort get DeviceID 2>nul', { encoding: 'utf8' }); + const ports = result.split('\n').filter(line => line.includes('COM')).map(line => line.trim()); + if (ports.length > 0) return ports[0]; + } + return 'COM3'; } else if (platform === 'darwin') { // macOS - const files = fs.readdirSync('/dev').filter(f => f.startsWith('cu.usbserial') || f.startsWith('cu.SLAB')); + const files = fs.readdirSync('/dev').filter(f => + f.startsWith('cu.usbserial') || + f.startsWith('cu.SLAB') || + f.startsWith('cu.wchusbserial') || + f.startsWith('cu.usbmodem') + ); return files[0] ? `/dev/${files[0]}` : '/dev/cu.usbserial-0001'; } else { // Linux @@ -127,27 +145,52 @@ async function installToolchain() { const { platform } = detectPlatform(); try { - // Install espup - logStep('Installing espup...'); if (platform === 'win32') { - execSync('cargo install espup', { stdio: 'inherit' }); + // Windows: Check if we have the PowerShell setup script + const scriptsDir = path.join(__dirname, '..', 'scripts', 'windows'); + const setupScript = path.join(scriptsDir, 'setup.ps1'); + + if (fs.existsSync(setupScript)) { + logStep('Running Windows setup script...'); + execSync(`powershell -ExecutionPolicy Bypass -File "${setupScript}"`, { stdio: 'inherit' }); + } else { + // Fallback: manual installation + logStep('Installing espup...'); + + // Download espup for Windows + const espupUrl = 'https://github.com/esp-rs/espup/releases/latest/download/espup-x86_64-pc-windows-msvc.exe'; + const espupPath = path.join(os.tmpdir(), 'espup.exe'); + + execSync(`powershell -Command "Invoke-WebRequest -Uri '${espupUrl}' -OutFile '${espupPath}'"`, { stdio: 'inherit' }); + + logStep('Running espup install...'); + execSync(`"${espupPath}" install`, { stdio: 'inherit' }); + + // Install espflash + logStep('Installing espflash...'); + execSync('cargo install espflash ldproxy', { stdio: 'inherit' }); + } + + logSuccess('Toolchain installed successfully!'); + log('\nTo use the toolchain, run:', 'yellow'); + log(' . .\\scripts\\windows\\env.ps1', 'cyan'); + } else { - execSync('curl -L https://github.com/esp-rs/espup/releases/latest/download/espup-x86_64-unknown-linux-gnu -o /tmp/espup && chmod +x /tmp/espup && /tmp/espup install', { stdio: 'inherit' }); - } + // Linux/macOS + logStep('Installing espup...'); + const arch = os.arch() === 'arm64' ? 'aarch64' : 'x86_64'; + const binary = platform === 'darwin' + ? `espup-${arch}-apple-darwin` + : `espup-${arch}-unknown-linux-gnu`; - // Install espflash - logStep('Installing espflash...'); - execSync('cargo install espflash ldproxy', { stdio: 'inherit' }); + execSync(`curl -L https://github.com/esp-rs/espup/releases/latest/download/${binary} -o /tmp/espup && chmod +x /tmp/espup && /tmp/espup install`, { stdio: 'inherit' }); - // Run espup install - logStep('Setting up ESP32 toolchain...'); - execSync('espup install', { stdio: 'inherit' }); + // Install espflash + logStep('Installing espflash...'); + execSync('cargo install espflash ldproxy', { stdio: 'inherit' }); - logSuccess('Toolchain installed successfully!'); - log('\nPlease restart your terminal or run:', 'yellow'); - if (platform === 'win32') { - log(' $env:PATH = [System.Environment]::GetEnvironmentVariable("Path","User")', 'cyan'); - } else { + logSuccess('Toolchain installed successfully!'); + log('\nPlease restart your terminal or run:', 'yellow'); log(' source $HOME/export-esp.sh', 'cyan'); } @@ -160,8 +203,9 @@ async function installToolchain() { async function build(options = {}) { const target = options.target || 'esp32'; - const release = options.release || false; + const release = options.release !== false; // Default to release const features = options.features || ''; + const { platform } = detectPlatform(); logStep(`Building for ${target}${release ? ' (release)' : ''}...`); @@ -175,12 +219,33 @@ async function build(options = {}) { const rustTarget = targetMap[target] || targetMap['esp32']; - let cmd = `cargo build --target ${rustTarget}`; - if (release) cmd += ' --release'; - if (features) cmd += ` --features ${features}`; - try { - execSync(cmd, { stdio: 'inherit', cwd: process.cwd() }); + if (platform === 'win32') { + // Windows: Use PowerShell build script if available + const scriptsDir = path.join(__dirname, '..', 'scripts', 'windows'); + const buildScript = path.join(scriptsDir, 'build.ps1'); + + if (fs.existsSync(buildScript)) { + let psArgs = `-ExecutionPolicy Bypass -File "${buildScript}" -Target "${rustTarget}"`; + if (release) psArgs += ' -Release'; + if (features) psArgs += ` -Features "${features}"`; + + execSync(`powershell ${psArgs}`, { stdio: 'inherit', cwd: process.cwd() }); + } else { + // Fallback to direct cargo + let cmd = `cargo build --target ${rustTarget}`; + if (release) cmd += ' --release'; + if (features) cmd += ` --features ${features}`; + execSync(cmd, { stdio: 'inherit', cwd: process.cwd() }); + } + } else { + // Linux/macOS + let cmd = `cargo build --target ${rustTarget}`; + if (release) cmd += ' --release'; + if (features) cmd += ` --features ${features}`; + execSync(cmd, { stdio: 'inherit', cwd: process.cwd() }); + } + logSuccess('Build completed!'); return true; } catch (e) { @@ -192,12 +257,39 @@ async function build(options = {}) { async function flash(port, options = {}) { const actualPort = port || detectPort(); const target = options.target || 'esp32'; + const { platform } = detectPlatform(); logStep(`Flashing to ${actualPort}...`); + const targetMap = { + 'esp32': 'xtensa-esp32-espidf', + 'esp32s2': 'xtensa-esp32s2-espidf', + 'esp32s3': 'xtensa-esp32s3-espidf', + 'esp32c3': 'riscv32imc-esp-espidf', + 'esp32c6': 'riscv32imac-esp-espidf' + }; + const rustTarget = targetMap[target] || targetMap['esp32']; + try { - const cmd = `espflash flash --monitor --port ${actualPort} target/xtensa-${target}-espidf/release/ruvllm-esp32`; - execSync(cmd, { stdio: 'inherit' }); + if (platform === 'win32') { + // Windows: Use PowerShell flash script if available + const scriptsDir = path.join(__dirname, '..', 'scripts', 'windows'); + const flashScript = path.join(scriptsDir, 'flash.ps1'); + + if (fs.existsSync(flashScript)) { + const psArgs = `-ExecutionPolicy Bypass -File "${flashScript}" -Port "${actualPort}" -Target "${rustTarget}"`; + execSync(`powershell ${psArgs}`, { stdio: 'inherit', cwd: process.cwd() }); + } else { + // Fallback + const binary = `target\\${rustTarget}\\release\\ruvllm-esp32`; + execSync(`espflash flash --monitor --port ${actualPort} ${binary}`, { stdio: 'inherit' }); + } + } else { + // Linux/macOS + const binary = `target/${rustTarget}/release/ruvllm-esp32`; + execSync(`espflash flash --monitor --port ${actualPort} ${binary}`, { stdio: 'inherit' }); + } + logSuccess('Flash completed!'); return true; } catch (e) { diff --git a/examples/ruvLLM/esp32-flash/npm/scripts/windows/build.ps1 b/examples/ruvLLM/esp32-flash/npm/scripts/windows/build.ps1 new file mode 100644 index 00000000..f0e706ff --- /dev/null +++ b/examples/ruvLLM/esp32-flash/npm/scripts/windows/build.ps1 @@ -0,0 +1,124 @@ +# build.ps1 - Auto-configure and build RuvLLM ESP32 +# Automatically detects toolchain paths - no manual configuration needed + +param( + [string]$Target = "xtensa-esp32-espidf", + [switch]$Release = $true, + [string]$Features = "" +) + +$ErrorActionPreference = "Stop" + +Write-Host "`n=== RuvLLM ESP32 Build ===" -ForegroundColor Cyan +Write-Host "" + +# Auto-detect paths +$rustupHome = if ($env:RUSTUP_HOME) { $env:RUSTUP_HOME } else { "$env:USERPROFILE\.rustup" } +$cargoHome = if ($env:CARGO_HOME) { $env:CARGO_HOME } else { "$env:USERPROFILE\.cargo" } + +# Find ESP toolchain +$espToolchain = (Get-ChildItem "$rustupHome\toolchains" -Directory -ErrorAction SilentlyContinue | + Where-Object { $_.Name -like "esp*" } | + Select-Object -First 1) + +if (-not $espToolchain) { + Write-Error "ESP toolchain not found. Run .\setup.ps1 first" +} + +$espToolchainPath = $espToolchain.FullName + +# Find libclang dynamically +$libclang = Get-ChildItem "$espToolchainPath" -Recurse -Filter "libclang.dll" -ErrorAction SilentlyContinue | + Select-Object -First 1 + +if (-not $libclang) { + Write-Error "libclang.dll not found in $espToolchainPath" +} + +# Find Python +$python = Get-Command python -ErrorAction SilentlyContinue +if (-not $python) { + $python = Get-Command python3 -ErrorAction SilentlyContinue +} +if (-not $python) { + Write-Error "Python not found. Please install Python 3.8+" +} +$pythonPath = Split-Path $python.Source + +# Find clang and xtensa-esp-elf paths +$clangBin = Get-ChildItem "$espToolchainPath" -Recurse -Directory -Filter "esp-clang" -ErrorAction SilentlyContinue | + Select-Object -First 1 +$clangBinPath = if ($clangBin) { "$($clangBin.FullName)\bin" } else { "" } + +$xtensaBin = Get-ChildItem "$espToolchainPath" -Recurse -Directory -Filter "xtensa-esp-elf" -ErrorAction SilentlyContinue | + Select-Object -First 1 +$xtensaBinPath = if ($xtensaBin) { "$($xtensaBin.FullName)\bin" } else { "" } + +# Set environment variables +$env:LIBCLANG_PATH = Split-Path $libclang.FullName +$env:RUSTUP_TOOLCHAIN = "esp" +$env:ESP_IDF_VERSION = "v5.1.2" + +# Build PATH with all required directories +$pathParts = @( + $pythonPath, + "$pythonPath\Scripts", + $clangBinPath, + $xtensaBinPath, + "$cargoHome\bin" +) | Where-Object { $_ -ne "" } + +$env:PATH = ($pathParts -join ";") + ";" + $env:PATH + +Write-Host "Build Configuration:" -ForegroundColor Gray +Write-Host " Target: $Target" +Write-Host " Release: $Release" +Write-Host " Toolchain: $($espToolchain.Name)" +Write-Host " LIBCLANG_PATH: $($env:LIBCLANG_PATH)" +Write-Host "" + +# Navigate to project directory +$projectDir = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) +Push-Location $projectDir + +try { + # Build cargo command + $cargoArgs = @("build") + + if ($Release) { + $cargoArgs += "--release" + } + + if ($Features) { + $cargoArgs += "--features" + $cargoArgs += $Features + } + + Write-Host "Running: cargo $($cargoArgs -join ' ')" -ForegroundColor Gray + Write-Host "" + + & cargo @cargoArgs + + if ($LASTEXITCODE -ne 0) { + throw "Build failed with exit code $LASTEXITCODE" + } + + Write-Host "" + Write-Host "Build successful!" -ForegroundColor Green + + # Find the built binary + $buildDir = if ($Release) { "release" } else { "debug" } + $binary = Get-ChildItem "$projectDir\target\$Target\$buildDir" -Filter "*.elf" -ErrorAction SilentlyContinue | + Where-Object { $_.Name -notmatch "deps" } | + Select-Object -First 1 + + if ($binary) { + Write-Host "Binary: $($binary.FullName)" -ForegroundColor Cyan + } + + Write-Host "" + Write-Host "Next: Run .\flash.ps1 to flash to device" -ForegroundColor Yellow + +} finally { + Pop-Location +} diff --git a/examples/ruvLLM/esp32-flash/npm/scripts/windows/env.ps1 b/examples/ruvLLM/esp32-flash/npm/scripts/windows/env.ps1 new file mode 100644 index 00000000..943be3c4 --- /dev/null +++ b/examples/ruvLLM/esp32-flash/npm/scripts/windows/env.ps1 @@ -0,0 +1,60 @@ +# env.ps1 - Set up ESP32 Rust environment for the current session +# Source this script: . .\env.ps1 + +$ErrorActionPreference = "SilentlyContinue" + +# Find paths +$rustupHome = if ($env:RUSTUP_HOME) { $env:RUSTUP_HOME } else { "$env:USERPROFILE\.rustup" } +$cargoHome = if ($env:CARGO_HOME) { $env:CARGO_HOME } else { "$env:USERPROFILE\.cargo" } + +# Find ESP toolchain +$espToolchain = (Get-ChildItem "$rustupHome\toolchains" -Directory | + Where-Object { $_.Name -like "esp*" } | + Select-Object -First 1) + +if (-not $espToolchain) { + Write-Host "ESP toolchain not found. Run setup.ps1 first." -ForegroundColor Red + return +} + +$espToolchainPath = $espToolchain.FullName + +# Find libclang +$libclang = Get-ChildItem "$espToolchainPath" -Recurse -Filter "libclang.dll" | + Select-Object -First 1 + +# Find clang bin +$clangBin = Get-ChildItem "$espToolchainPath" -Recurse -Directory -Filter "esp-clang" | + Select-Object -First 1 + +# Find xtensa-esp-elf bin +$xtensaBin = Get-ChildItem "$espToolchainPath" -Recurse -Directory -Filter "xtensa-esp-elf" | + Select-Object -First 1 + +# Find Python +$python = Get-Command python -ErrorAction SilentlyContinue +$pythonPath = if ($python) { Split-Path $python.Source } else { "" } + +# Set environment variables +$env:LIBCLANG_PATH = if ($libclang) { Split-Path $libclang.FullName } else { "" } +$env:RUSTUP_TOOLCHAIN = "esp" +$env:ESP_IDF_VERSION = "v5.1.2" + +# Build PATH +$pathAdditions = @() +if ($pythonPath) { $pathAdditions += $pythonPath; $pathAdditions += "$pythonPath\Scripts" } +if ($clangBin) { $pathAdditions += "$($clangBin.FullName)\bin" } +if ($xtensaBin) { $pathAdditions += "$($xtensaBin.FullName)\bin" } +$pathAdditions += "$cargoHome\bin" + +$env:PATH = ($pathAdditions -join ";") + ";" + $env:PATH + +# Display status +Write-Host "" +Write-Host "ESP32 Rust environment loaded" -ForegroundColor Green +Write-Host "" +Write-Host " RUSTUP_TOOLCHAIN: $($env:RUSTUP_TOOLCHAIN)" -ForegroundColor Gray +Write-Host " LIBCLANG_PATH: $($env:LIBCLANG_PATH)" -ForegroundColor Gray +Write-Host " ESP_IDF_VERSION: $($env:ESP_IDF_VERSION)" -ForegroundColor Gray +Write-Host "" +Write-Host "Ready to build! Run: .\build.ps1" -ForegroundColor Cyan diff --git a/examples/ruvLLM/esp32-flash/npm/scripts/windows/flash.ps1 b/examples/ruvLLM/esp32-flash/npm/scripts/windows/flash.ps1 new file mode 100644 index 00000000..35b3fe70 --- /dev/null +++ b/examples/ruvLLM/esp32-flash/npm/scripts/windows/flash.ps1 @@ -0,0 +1,99 @@ +# flash.ps1 - Auto-detect COM port and flash RuvLLM ESP32 +# Automatically finds connected ESP32 devices + +param( + [string]$Port = "", + [switch]$Monitor = $true, + [string]$Target = "xtensa-esp32-espidf", + [switch]$Release = $true +) + +$ErrorActionPreference = "Stop" + +Write-Host "`n=== RuvLLM ESP32 Flash ===" -ForegroundColor Cyan +Write-Host "" + +# Auto-detect COM port if not specified +if (-not $Port) { + # Get available COM ports + Add-Type -AssemblyName System.IO.Ports + $ports = [System.IO.Ports.SerialPort]::GetPortNames() | + Where-Object { $_ -match "COM\d+" } | + Sort-Object { [int]($_ -replace "COM", "") } + + if ($ports.Count -eq 0) { + Write-Error "No COM ports found. Is the ESP32 connected via USB?" + } elseif ($ports.Count -eq 1) { + $Port = $ports[0] + Write-Host "Auto-detected port: $Port" -ForegroundColor Green + } else { + Write-Host "Multiple COM ports found:" -ForegroundColor Yellow + Write-Host "" + for ($i = 0; $i -lt $ports.Count; $i++) { + Write-Host " [$i] $($ports[$i])" + } + Write-Host "" + $selection = Read-Host "Select port (0-$($ports.Count - 1))" + + if ($selection -match "^\d+$" -and [int]$selection -lt $ports.Count) { + $Port = $ports[[int]$selection] + } else { + Write-Error "Invalid selection" + } + } +} + +Write-Host "Using port: $Port" -ForegroundColor Cyan +Write-Host "" + +# Find binary +$projectDir = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) +$buildDir = if ($Release) { "release" } else { "debug" } +$targetDir = "$projectDir\target\$Target\$buildDir" + +# Look for ELF or binary file +$binary = Get-ChildItem $targetDir -Filter "*.elf" -ErrorAction SilentlyContinue | + Where-Object { $_.Name -notmatch "deps" } | + Select-Object -First 1 + +if (-not $binary) { + $binary = Get-ChildItem $targetDir -Filter "ruvllm-esp32*" -ErrorAction SilentlyContinue | + Where-Object { $_.Name -notmatch "\." -or $_.Name -match "\.elf$" } | + Select-Object -First 1 +} + +if (-not $binary) { + Write-Host "Available files in $targetDir`:" -ForegroundColor Yellow + Get-ChildItem $targetDir -ErrorAction SilentlyContinue | ForEach-Object { Write-Host " $($_.Name)" } + Write-Error "No binary found. Run .\build.ps1 first" +} + +Write-Host "Binary: $($binary.Name)" -ForegroundColor Gray +Write-Host "" + +# Check for espflash +$espflash = Get-Command espflash -ErrorAction SilentlyContinue +if (-not $espflash) { + Write-Error "espflash not found. Run .\setup.ps1 first" +} + +# Build espflash command +$espflashArgs = @("flash", "--port", $Port, $binary.FullName) + +if ($Monitor) { + $espflashArgs += "--monitor" +} + +Write-Host "Flashing..." -ForegroundColor Cyan +Write-Host "Command: espflash $($espflashArgs -join ' ')" -ForegroundColor Gray +Write-Host "" + +# Flash the device +& espflash @espflashArgs + +if ($LASTEXITCODE -ne 0) { + Write-Error "Flash failed with exit code $LASTEXITCODE" +} + +Write-Host "" +Write-Host "Flash complete!" -ForegroundColor Green diff --git a/examples/ruvLLM/esp32-flash/npm/scripts/windows/monitor.ps1 b/examples/ruvLLM/esp32-flash/npm/scripts/windows/monitor.ps1 new file mode 100644 index 00000000..26ae895f --- /dev/null +++ b/examples/ruvLLM/esp32-flash/npm/scripts/windows/monitor.ps1 @@ -0,0 +1,41 @@ +# monitor.ps1 - Open serial monitor for ESP32 +# Auto-detects COM port + +param( + [string]$Port = "", + [int]$Baud = 115200 +) + +$ErrorActionPreference = "Stop" + +Write-Host "`n=== RuvLLM ESP32 Serial Monitor ===" -ForegroundColor Cyan +Write-Host "" + +# Auto-detect COM port if not specified +if (-not $Port) { + Add-Type -AssemblyName System.IO.Ports + $ports = [System.IO.Ports.SerialPort]::GetPortNames() | + Where-Object { $_ -match "COM\d+" } | + Sort-Object { [int]($_ -replace "COM", "") } + + if ($ports.Count -eq 0) { + Write-Error "No COM ports found. Is the ESP32 connected?" + } elseif ($ports.Count -eq 1) { + $Port = $ports[0] + Write-Host "Auto-detected port: $Port" -ForegroundColor Green + } else { + Write-Host "Multiple COM ports found:" -ForegroundColor Yellow + for ($i = 0; $i -lt $ports.Count; $i++) { + Write-Host " [$i] $($ports[$i])" + } + $selection = Read-Host "Select port (0-$($ports.Count - 1))" + $Port = $ports[[int]$selection] + } +} + +Write-Host "Opening monitor on $Port at $Baud baud..." -ForegroundColor Cyan +Write-Host "Press Ctrl+C to exit" -ForegroundColor Gray +Write-Host "" + +# Use espflash monitor +& espflash monitor --port $Port --baud $Baud diff --git a/examples/ruvLLM/esp32-flash/npm/scripts/windows/setup.ps1 b/examples/ruvLLM/esp32-flash/npm/scripts/windows/setup.ps1 new file mode 100644 index 00000000..d3736bfd --- /dev/null +++ b/examples/ruvLLM/esp32-flash/npm/scripts/windows/setup.ps1 @@ -0,0 +1,118 @@ +# setup.ps1 - One-time Windows setup for RuvLLM ESP32 +# Run this once to install/configure the ESP32 Rust toolchain + +$ErrorActionPreference = "Stop" + +Write-Host "`n=== RuvLLM ESP32 Windows Setup ===" -ForegroundColor Cyan +Write-Host "" + +# Find Rust ESP toolchain dynamically +$rustupHome = if ($env:RUSTUP_HOME) { $env:RUSTUP_HOME } else { "$env:USERPROFILE\.rustup" } +$cargoHome = if ($env:CARGO_HOME) { $env:CARGO_HOME } else { "$env:USERPROFILE\.cargo" } + +# Check if Rust is installed +$rustc = Get-Command rustc -ErrorAction SilentlyContinue +if (-not $rustc) { + Write-Host "Rust not found. Installing rustup..." -ForegroundColor Yellow + Invoke-WebRequest -Uri "https://win.rustup.rs/x86_64" -OutFile rustup-init.exe + .\rustup-init.exe -y --default-toolchain stable + Remove-Item rustup-init.exe + $env:PATH = "$cargoHome\bin;" + $env:PATH + Write-Host "Rust installed successfully" -ForegroundColor Green +} + +# Find or install ESP toolchain +$espToolchain = Get-ChildItem "$rustupHome\toolchains" -Directory -ErrorAction SilentlyContinue | + Where-Object { $_.Name -like "esp*" } | + Select-Object -First 1 + +if (-not $espToolchain) { + Write-Host "ESP toolchain not found. Installing espup..." -ForegroundColor Yellow + + # Download espup + $espupUrl = "https://github.com/esp-rs/espup/releases/latest/download/espup-x86_64-pc-windows-msvc.exe" + $espupPath = "$env:TEMP\espup.exe" + + Write-Host "Downloading espup..." -ForegroundColor Gray + Invoke-WebRequest -Uri $espupUrl -OutFile $espupPath + + Write-Host "Running espup install (this may take several minutes)..." -ForegroundColor Gray + & $espupPath install + + if ($LASTEXITCODE -ne 0) { + Write-Error "espup install failed with exit code $LASTEXITCODE" + } + + Remove-Item $espupPath -ErrorAction SilentlyContinue + + # Re-check for toolchain + $espToolchain = Get-ChildItem "$rustupHome\toolchains" -Directory | + Where-Object { $_.Name -like "esp*" } | + Select-Object -First 1 +} + +if (-not $espToolchain) { + Write-Error "ESP toolchain installation failed. Please install manually: https://esp-rs.github.io/book/" +} + +Write-Host "Found ESP toolchain: $($espToolchain.Name)" -ForegroundColor Green + +# Find Python +$python = Get-Command python -ErrorAction SilentlyContinue +if (-not $python) { + $python = Get-Command python3 -ErrorAction SilentlyContinue +} +if (-not $python) { + Write-Error "Python not found. Please install Python 3.8+ from https://python.org" +} +Write-Host "Found Python: $($python.Source)" -ForegroundColor Green + +# Find libclang +$libclang = Get-ChildItem "$($espToolchain.FullName)" -Recurse -Filter "libclang.dll" -ErrorAction SilentlyContinue | + Select-Object -First 1 + +if ($libclang) { + Write-Host "Found libclang: $($libclang.FullName)" -ForegroundColor Green +} else { + Write-Host "Warning: libclang.dll not found in toolchain" -ForegroundColor Yellow +} + +# Install espflash if not present +$espflash = Get-Command espflash -ErrorAction SilentlyContinue +if (-not $espflash) { + Write-Host "Installing espflash..." -ForegroundColor Yellow + cargo install espflash + if ($LASTEXITCODE -ne 0) { + Write-Error "espflash installation failed" + } + Write-Host "espflash installed successfully" -ForegroundColor Green +} else { + Write-Host "Found espflash: $($espflash.Source)" -ForegroundColor Green +} + +# Install ldproxy if not present +$ldproxy = Get-Command ldproxy -ErrorAction SilentlyContinue +if (-not $ldproxy) { + Write-Host "Installing ldproxy..." -ForegroundColor Yellow + cargo install ldproxy + if ($LASTEXITCODE -ne 0) { + Write-Error "ldproxy installation failed" + } + Write-Host "ldproxy installed successfully" -ForegroundColor Green +} + +Write-Host "" +Write-Host "=== Setup Complete ===" -ForegroundColor Green +Write-Host "" +Write-Host "Summary:" -ForegroundColor Cyan +Write-Host " Toolchain: $($espToolchain.Name)" +Write-Host " Python: $($python.Source)" +if ($libclang) { + Write-Host " Libclang: $($libclang.FullName)" +} +Write-Host "" +Write-Host "Next steps:" -ForegroundColor Yellow +Write-Host " 1. Run: .\build.ps1" +Write-Host " 2. Connect ESP32 via USB" +Write-Host " 3. Run: .\flash.ps1" +Write-Host "" diff --git a/examples/ruvLLM/esp32-flash/scripts/windows/build.ps1 b/examples/ruvLLM/esp32-flash/scripts/windows/build.ps1 new file mode 100644 index 00000000..f0e706ff --- /dev/null +++ b/examples/ruvLLM/esp32-flash/scripts/windows/build.ps1 @@ -0,0 +1,124 @@ +# build.ps1 - Auto-configure and build RuvLLM ESP32 +# Automatically detects toolchain paths - no manual configuration needed + +param( + [string]$Target = "xtensa-esp32-espidf", + [switch]$Release = $true, + [string]$Features = "" +) + +$ErrorActionPreference = "Stop" + +Write-Host "`n=== RuvLLM ESP32 Build ===" -ForegroundColor Cyan +Write-Host "" + +# Auto-detect paths +$rustupHome = if ($env:RUSTUP_HOME) { $env:RUSTUP_HOME } else { "$env:USERPROFILE\.rustup" } +$cargoHome = if ($env:CARGO_HOME) { $env:CARGO_HOME } else { "$env:USERPROFILE\.cargo" } + +# Find ESP toolchain +$espToolchain = (Get-ChildItem "$rustupHome\toolchains" -Directory -ErrorAction SilentlyContinue | + Where-Object { $_.Name -like "esp*" } | + Select-Object -First 1) + +if (-not $espToolchain) { + Write-Error "ESP toolchain not found. Run .\setup.ps1 first" +} + +$espToolchainPath = $espToolchain.FullName + +# Find libclang dynamically +$libclang = Get-ChildItem "$espToolchainPath" -Recurse -Filter "libclang.dll" -ErrorAction SilentlyContinue | + Select-Object -First 1 + +if (-not $libclang) { + Write-Error "libclang.dll not found in $espToolchainPath" +} + +# Find Python +$python = Get-Command python -ErrorAction SilentlyContinue +if (-not $python) { + $python = Get-Command python3 -ErrorAction SilentlyContinue +} +if (-not $python) { + Write-Error "Python not found. Please install Python 3.8+" +} +$pythonPath = Split-Path $python.Source + +# Find clang and xtensa-esp-elf paths +$clangBin = Get-ChildItem "$espToolchainPath" -Recurse -Directory -Filter "esp-clang" -ErrorAction SilentlyContinue | + Select-Object -First 1 +$clangBinPath = if ($clangBin) { "$($clangBin.FullName)\bin" } else { "" } + +$xtensaBin = Get-ChildItem "$espToolchainPath" -Recurse -Directory -Filter "xtensa-esp-elf" -ErrorAction SilentlyContinue | + Select-Object -First 1 +$xtensaBinPath = if ($xtensaBin) { "$($xtensaBin.FullName)\bin" } else { "" } + +# Set environment variables +$env:LIBCLANG_PATH = Split-Path $libclang.FullName +$env:RUSTUP_TOOLCHAIN = "esp" +$env:ESP_IDF_VERSION = "v5.1.2" + +# Build PATH with all required directories +$pathParts = @( + $pythonPath, + "$pythonPath\Scripts", + $clangBinPath, + $xtensaBinPath, + "$cargoHome\bin" +) | Where-Object { $_ -ne "" } + +$env:PATH = ($pathParts -join ";") + ";" + $env:PATH + +Write-Host "Build Configuration:" -ForegroundColor Gray +Write-Host " Target: $Target" +Write-Host " Release: $Release" +Write-Host " Toolchain: $($espToolchain.Name)" +Write-Host " LIBCLANG_PATH: $($env:LIBCLANG_PATH)" +Write-Host "" + +# Navigate to project directory +$projectDir = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) +Push-Location $projectDir + +try { + # Build cargo command + $cargoArgs = @("build") + + if ($Release) { + $cargoArgs += "--release" + } + + if ($Features) { + $cargoArgs += "--features" + $cargoArgs += $Features + } + + Write-Host "Running: cargo $($cargoArgs -join ' ')" -ForegroundColor Gray + Write-Host "" + + & cargo @cargoArgs + + if ($LASTEXITCODE -ne 0) { + throw "Build failed with exit code $LASTEXITCODE" + } + + Write-Host "" + Write-Host "Build successful!" -ForegroundColor Green + + # Find the built binary + $buildDir = if ($Release) { "release" } else { "debug" } + $binary = Get-ChildItem "$projectDir\target\$Target\$buildDir" -Filter "*.elf" -ErrorAction SilentlyContinue | + Where-Object { $_.Name -notmatch "deps" } | + Select-Object -First 1 + + if ($binary) { + Write-Host "Binary: $($binary.FullName)" -ForegroundColor Cyan + } + + Write-Host "" + Write-Host "Next: Run .\flash.ps1 to flash to device" -ForegroundColor Yellow + +} finally { + Pop-Location +} diff --git a/examples/ruvLLM/esp32-flash/scripts/windows/env.ps1 b/examples/ruvLLM/esp32-flash/scripts/windows/env.ps1 new file mode 100644 index 00000000..943be3c4 --- /dev/null +++ b/examples/ruvLLM/esp32-flash/scripts/windows/env.ps1 @@ -0,0 +1,60 @@ +# env.ps1 - Set up ESP32 Rust environment for the current session +# Source this script: . .\env.ps1 + +$ErrorActionPreference = "SilentlyContinue" + +# Find paths +$rustupHome = if ($env:RUSTUP_HOME) { $env:RUSTUP_HOME } else { "$env:USERPROFILE\.rustup" } +$cargoHome = if ($env:CARGO_HOME) { $env:CARGO_HOME } else { "$env:USERPROFILE\.cargo" } + +# Find ESP toolchain +$espToolchain = (Get-ChildItem "$rustupHome\toolchains" -Directory | + Where-Object { $_.Name -like "esp*" } | + Select-Object -First 1) + +if (-not $espToolchain) { + Write-Host "ESP toolchain not found. Run setup.ps1 first." -ForegroundColor Red + return +} + +$espToolchainPath = $espToolchain.FullName + +# Find libclang +$libclang = Get-ChildItem "$espToolchainPath" -Recurse -Filter "libclang.dll" | + Select-Object -First 1 + +# Find clang bin +$clangBin = Get-ChildItem "$espToolchainPath" -Recurse -Directory -Filter "esp-clang" | + Select-Object -First 1 + +# Find xtensa-esp-elf bin +$xtensaBin = Get-ChildItem "$espToolchainPath" -Recurse -Directory -Filter "xtensa-esp-elf" | + Select-Object -First 1 + +# Find Python +$python = Get-Command python -ErrorAction SilentlyContinue +$pythonPath = if ($python) { Split-Path $python.Source } else { "" } + +# Set environment variables +$env:LIBCLANG_PATH = if ($libclang) { Split-Path $libclang.FullName } else { "" } +$env:RUSTUP_TOOLCHAIN = "esp" +$env:ESP_IDF_VERSION = "v5.1.2" + +# Build PATH +$pathAdditions = @() +if ($pythonPath) { $pathAdditions += $pythonPath; $pathAdditions += "$pythonPath\Scripts" } +if ($clangBin) { $pathAdditions += "$($clangBin.FullName)\bin" } +if ($xtensaBin) { $pathAdditions += "$($xtensaBin.FullName)\bin" } +$pathAdditions += "$cargoHome\bin" + +$env:PATH = ($pathAdditions -join ";") + ";" + $env:PATH + +# Display status +Write-Host "" +Write-Host "ESP32 Rust environment loaded" -ForegroundColor Green +Write-Host "" +Write-Host " RUSTUP_TOOLCHAIN: $($env:RUSTUP_TOOLCHAIN)" -ForegroundColor Gray +Write-Host " LIBCLANG_PATH: $($env:LIBCLANG_PATH)" -ForegroundColor Gray +Write-Host " ESP_IDF_VERSION: $($env:ESP_IDF_VERSION)" -ForegroundColor Gray +Write-Host "" +Write-Host "Ready to build! Run: .\build.ps1" -ForegroundColor Cyan diff --git a/examples/ruvLLM/esp32-flash/scripts/windows/flash.ps1 b/examples/ruvLLM/esp32-flash/scripts/windows/flash.ps1 new file mode 100644 index 00000000..35b3fe70 --- /dev/null +++ b/examples/ruvLLM/esp32-flash/scripts/windows/flash.ps1 @@ -0,0 +1,99 @@ +# flash.ps1 - Auto-detect COM port and flash RuvLLM ESP32 +# Automatically finds connected ESP32 devices + +param( + [string]$Port = "", + [switch]$Monitor = $true, + [string]$Target = "xtensa-esp32-espidf", + [switch]$Release = $true +) + +$ErrorActionPreference = "Stop" + +Write-Host "`n=== RuvLLM ESP32 Flash ===" -ForegroundColor Cyan +Write-Host "" + +# Auto-detect COM port if not specified +if (-not $Port) { + # Get available COM ports + Add-Type -AssemblyName System.IO.Ports + $ports = [System.IO.Ports.SerialPort]::GetPortNames() | + Where-Object { $_ -match "COM\d+" } | + Sort-Object { [int]($_ -replace "COM", "") } + + if ($ports.Count -eq 0) { + Write-Error "No COM ports found. Is the ESP32 connected via USB?" + } elseif ($ports.Count -eq 1) { + $Port = $ports[0] + Write-Host "Auto-detected port: $Port" -ForegroundColor Green + } else { + Write-Host "Multiple COM ports found:" -ForegroundColor Yellow + Write-Host "" + for ($i = 0; $i -lt $ports.Count; $i++) { + Write-Host " [$i] $($ports[$i])" + } + Write-Host "" + $selection = Read-Host "Select port (0-$($ports.Count - 1))" + + if ($selection -match "^\d+$" -and [int]$selection -lt $ports.Count) { + $Port = $ports[[int]$selection] + } else { + Write-Error "Invalid selection" + } + } +} + +Write-Host "Using port: $Port" -ForegroundColor Cyan +Write-Host "" + +# Find binary +$projectDir = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) +$buildDir = if ($Release) { "release" } else { "debug" } +$targetDir = "$projectDir\target\$Target\$buildDir" + +# Look for ELF or binary file +$binary = Get-ChildItem $targetDir -Filter "*.elf" -ErrorAction SilentlyContinue | + Where-Object { $_.Name -notmatch "deps" } | + Select-Object -First 1 + +if (-not $binary) { + $binary = Get-ChildItem $targetDir -Filter "ruvllm-esp32*" -ErrorAction SilentlyContinue | + Where-Object { $_.Name -notmatch "\." -or $_.Name -match "\.elf$" } | + Select-Object -First 1 +} + +if (-not $binary) { + Write-Host "Available files in $targetDir`:" -ForegroundColor Yellow + Get-ChildItem $targetDir -ErrorAction SilentlyContinue | ForEach-Object { Write-Host " $($_.Name)" } + Write-Error "No binary found. Run .\build.ps1 first" +} + +Write-Host "Binary: $($binary.Name)" -ForegroundColor Gray +Write-Host "" + +# Check for espflash +$espflash = Get-Command espflash -ErrorAction SilentlyContinue +if (-not $espflash) { + Write-Error "espflash not found. Run .\setup.ps1 first" +} + +# Build espflash command +$espflashArgs = @("flash", "--port", $Port, $binary.FullName) + +if ($Monitor) { + $espflashArgs += "--monitor" +} + +Write-Host "Flashing..." -ForegroundColor Cyan +Write-Host "Command: espflash $($espflashArgs -join ' ')" -ForegroundColor Gray +Write-Host "" + +# Flash the device +& espflash @espflashArgs + +if ($LASTEXITCODE -ne 0) { + Write-Error "Flash failed with exit code $LASTEXITCODE" +} + +Write-Host "" +Write-Host "Flash complete!" -ForegroundColor Green diff --git a/examples/ruvLLM/esp32-flash/scripts/windows/monitor.ps1 b/examples/ruvLLM/esp32-flash/scripts/windows/monitor.ps1 new file mode 100644 index 00000000..26ae895f --- /dev/null +++ b/examples/ruvLLM/esp32-flash/scripts/windows/monitor.ps1 @@ -0,0 +1,41 @@ +# monitor.ps1 - Open serial monitor for ESP32 +# Auto-detects COM port + +param( + [string]$Port = "", + [int]$Baud = 115200 +) + +$ErrorActionPreference = "Stop" + +Write-Host "`n=== RuvLLM ESP32 Serial Monitor ===" -ForegroundColor Cyan +Write-Host "" + +# Auto-detect COM port if not specified +if (-not $Port) { + Add-Type -AssemblyName System.IO.Ports + $ports = [System.IO.Ports.SerialPort]::GetPortNames() | + Where-Object { $_ -match "COM\d+" } | + Sort-Object { [int]($_ -replace "COM", "") } + + if ($ports.Count -eq 0) { + Write-Error "No COM ports found. Is the ESP32 connected?" + } elseif ($ports.Count -eq 1) { + $Port = $ports[0] + Write-Host "Auto-detected port: $Port" -ForegroundColor Green + } else { + Write-Host "Multiple COM ports found:" -ForegroundColor Yellow + for ($i = 0; $i -lt $ports.Count; $i++) { + Write-Host " [$i] $($ports[$i])" + } + $selection = Read-Host "Select port (0-$($ports.Count - 1))" + $Port = $ports[[int]$selection] + } +} + +Write-Host "Opening monitor on $Port at $Baud baud..." -ForegroundColor Cyan +Write-Host "Press Ctrl+C to exit" -ForegroundColor Gray +Write-Host "" + +# Use espflash monitor +& espflash monitor --port $Port --baud $Baud diff --git a/examples/ruvLLM/esp32-flash/scripts/windows/setup.ps1 b/examples/ruvLLM/esp32-flash/scripts/windows/setup.ps1 new file mode 100644 index 00000000..d3736bfd --- /dev/null +++ b/examples/ruvLLM/esp32-flash/scripts/windows/setup.ps1 @@ -0,0 +1,118 @@ +# setup.ps1 - One-time Windows setup for RuvLLM ESP32 +# Run this once to install/configure the ESP32 Rust toolchain + +$ErrorActionPreference = "Stop" + +Write-Host "`n=== RuvLLM ESP32 Windows Setup ===" -ForegroundColor Cyan +Write-Host "" + +# Find Rust ESP toolchain dynamically +$rustupHome = if ($env:RUSTUP_HOME) { $env:RUSTUP_HOME } else { "$env:USERPROFILE\.rustup" } +$cargoHome = if ($env:CARGO_HOME) { $env:CARGO_HOME } else { "$env:USERPROFILE\.cargo" } + +# Check if Rust is installed +$rustc = Get-Command rustc -ErrorAction SilentlyContinue +if (-not $rustc) { + Write-Host "Rust not found. Installing rustup..." -ForegroundColor Yellow + Invoke-WebRequest -Uri "https://win.rustup.rs/x86_64" -OutFile rustup-init.exe + .\rustup-init.exe -y --default-toolchain stable + Remove-Item rustup-init.exe + $env:PATH = "$cargoHome\bin;" + $env:PATH + Write-Host "Rust installed successfully" -ForegroundColor Green +} + +# Find or install ESP toolchain +$espToolchain = Get-ChildItem "$rustupHome\toolchains" -Directory -ErrorAction SilentlyContinue | + Where-Object { $_.Name -like "esp*" } | + Select-Object -First 1 + +if (-not $espToolchain) { + Write-Host "ESP toolchain not found. Installing espup..." -ForegroundColor Yellow + + # Download espup + $espupUrl = "https://github.com/esp-rs/espup/releases/latest/download/espup-x86_64-pc-windows-msvc.exe" + $espupPath = "$env:TEMP\espup.exe" + + Write-Host "Downloading espup..." -ForegroundColor Gray + Invoke-WebRequest -Uri $espupUrl -OutFile $espupPath + + Write-Host "Running espup install (this may take several minutes)..." -ForegroundColor Gray + & $espupPath install + + if ($LASTEXITCODE -ne 0) { + Write-Error "espup install failed with exit code $LASTEXITCODE" + } + + Remove-Item $espupPath -ErrorAction SilentlyContinue + + # Re-check for toolchain + $espToolchain = Get-ChildItem "$rustupHome\toolchains" -Directory | + Where-Object { $_.Name -like "esp*" } | + Select-Object -First 1 +} + +if (-not $espToolchain) { + Write-Error "ESP toolchain installation failed. Please install manually: https://esp-rs.github.io/book/" +} + +Write-Host "Found ESP toolchain: $($espToolchain.Name)" -ForegroundColor Green + +# Find Python +$python = Get-Command python -ErrorAction SilentlyContinue +if (-not $python) { + $python = Get-Command python3 -ErrorAction SilentlyContinue +} +if (-not $python) { + Write-Error "Python not found. Please install Python 3.8+ from https://python.org" +} +Write-Host "Found Python: $($python.Source)" -ForegroundColor Green + +# Find libclang +$libclang = Get-ChildItem "$($espToolchain.FullName)" -Recurse -Filter "libclang.dll" -ErrorAction SilentlyContinue | + Select-Object -First 1 + +if ($libclang) { + Write-Host "Found libclang: $($libclang.FullName)" -ForegroundColor Green +} else { + Write-Host "Warning: libclang.dll not found in toolchain" -ForegroundColor Yellow +} + +# Install espflash if not present +$espflash = Get-Command espflash -ErrorAction SilentlyContinue +if (-not $espflash) { + Write-Host "Installing espflash..." -ForegroundColor Yellow + cargo install espflash + if ($LASTEXITCODE -ne 0) { + Write-Error "espflash installation failed" + } + Write-Host "espflash installed successfully" -ForegroundColor Green +} else { + Write-Host "Found espflash: $($espflash.Source)" -ForegroundColor Green +} + +# Install ldproxy if not present +$ldproxy = Get-Command ldproxy -ErrorAction SilentlyContinue +if (-not $ldproxy) { + Write-Host "Installing ldproxy..." -ForegroundColor Yellow + cargo install ldproxy + if ($LASTEXITCODE -ne 0) { + Write-Error "ldproxy installation failed" + } + Write-Host "ldproxy installed successfully" -ForegroundColor Green +} + +Write-Host "" +Write-Host "=== Setup Complete ===" -ForegroundColor Green +Write-Host "" +Write-Host "Summary:" -ForegroundColor Cyan +Write-Host " Toolchain: $($espToolchain.Name)" +Write-Host " Python: $($python.Source)" +if ($libclang) { + Write-Host " Libclang: $($libclang.FullName)" +} +Write-Host "" +Write-Host "Next steps:" -ForegroundColor Yellow +Write-Host " 1. Run: .\build.ps1" +Write-Host " 2. Connect ESP32 via USB" +Write-Host " 3. Run: .\flash.ps1" +Write-Host ""