ruvllm-esp32 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cli.js CHANGED
@@ -94,13 +94,31 @@ function detectPort() {
94
94
 
95
95
  try {
96
96
  if (platform === 'win32') {
97
- // Windows: Look for COM ports
98
- const result = execSync('wmic path Win32_SerialPort get DeviceID', { encoding: 'utf8' });
99
- const ports = result.split('\n').filter(line => line.includes('COM')).map(line => line.trim());
100
- return ports[0] || 'COM3';
97
+ // Windows: Use PowerShell for better COM port detection
98
+ try {
99
+ const result = execSync(
100
+ 'powershell -Command "[System.IO.Ports.SerialPort]::GetPortNames() | Sort-Object { [int]($_ -replace \'COM\', \'\') }"',
101
+ { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
102
+ );
103
+ const ports = result.trim().split('\n').filter(p => p.match(/COM\d+/));
104
+ if (ports.length > 0) {
105
+ return ports[0].trim();
106
+ }
107
+ } catch {
108
+ // Fallback to wmic
109
+ const result = execSync('wmic path Win32_SerialPort get DeviceID 2>nul', { encoding: 'utf8' });
110
+ const ports = result.split('\n').filter(line => line.includes('COM')).map(line => line.trim());
111
+ if (ports.length > 0) return ports[0];
112
+ }
113
+ return 'COM3';
101
114
  } else if (platform === 'darwin') {
102
115
  // macOS
103
- const files = fs.readdirSync('/dev').filter(f => f.startsWith('cu.usbserial') || f.startsWith('cu.SLAB'));
116
+ const files = fs.readdirSync('/dev').filter(f =>
117
+ f.startsWith('cu.usbserial') ||
118
+ f.startsWith('cu.SLAB') ||
119
+ f.startsWith('cu.wchusbserial') ||
120
+ f.startsWith('cu.usbmodem')
121
+ );
104
122
  return files[0] ? `/dev/${files[0]}` : '/dev/cu.usbserial-0001';
105
123
  } else {
106
124
  // Linux
@@ -127,27 +145,52 @@ async function installToolchain() {
127
145
  const { platform } = detectPlatform();
128
146
 
129
147
  try {
130
- // Install espup
131
- logStep('Installing espup...');
132
148
  if (platform === 'win32') {
133
- execSync('cargo install espup', { stdio: 'inherit' });
134
- } else {
135
- 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' });
136
- }
149
+ // Windows: Check if we have the PowerShell setup script
150
+ const scriptsDir = path.join(__dirname, '..', 'scripts', 'windows');
151
+ const setupScript = path.join(scriptsDir, 'setup.ps1');
137
152
 
138
- // Install espflash
139
- logStep('Installing espflash...');
140
- execSync('cargo install espflash ldproxy', { stdio: 'inherit' });
153
+ if (fs.existsSync(setupScript)) {
154
+ logStep('Running Windows setup script...');
155
+ execSync(`powershell -ExecutionPolicy Bypass -File "${setupScript}"`, { stdio: 'inherit' });
156
+ } else {
157
+ // Fallback: manual installation
158
+ logStep('Installing espup...');
141
159
 
142
- // Run espup install
143
- logStep('Setting up ESP32 toolchain...');
144
- execSync('espup install', { stdio: 'inherit' });
160
+ // Download espup for Windows
161
+ const espupUrl = 'https://github.com/esp-rs/espup/releases/latest/download/espup-x86_64-pc-windows-msvc.exe';
162
+ const espupPath = path.join(os.tmpdir(), 'espup.exe');
163
+
164
+ execSync(`powershell -Command "Invoke-WebRequest -Uri '${espupUrl}' -OutFile '${espupPath}'"`, { stdio: 'inherit' });
165
+
166
+ logStep('Running espup install...');
167
+ execSync(`"${espupPath}" install`, { stdio: 'inherit' });
168
+
169
+ // Install espflash
170
+ logStep('Installing espflash...');
171
+ execSync('cargo install espflash ldproxy', { stdio: 'inherit' });
172
+ }
173
+
174
+ logSuccess('Toolchain installed successfully!');
175
+ log('\nTo use the toolchain, run:', 'yellow');
176
+ log(' . .\\scripts\\windows\\env.ps1', 'cyan');
145
177
 
146
- logSuccess('Toolchain installed successfully!');
147
- log('\nPlease restart your terminal or run:', 'yellow');
148
- if (platform === 'win32') {
149
- log(' $env:PATH = [System.Environment]::GetEnvironmentVariable("Path","User")', 'cyan');
150
178
  } else {
179
+ // Linux/macOS
180
+ logStep('Installing espup...');
181
+ const arch = os.arch() === 'arm64' ? 'aarch64' : 'x86_64';
182
+ const binary = platform === 'darwin'
183
+ ? `espup-${arch}-apple-darwin`
184
+ : `espup-${arch}-unknown-linux-gnu`;
185
+
186
+ 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' });
187
+
188
+ // Install espflash
189
+ logStep('Installing espflash...');
190
+ execSync('cargo install espflash ldproxy', { stdio: 'inherit' });
191
+
192
+ logSuccess('Toolchain installed successfully!');
193
+ log('\nPlease restart your terminal or run:', 'yellow');
151
194
  log(' source $HOME/export-esp.sh', 'cyan');
152
195
  }
153
196
 
@@ -160,8 +203,9 @@ async function installToolchain() {
160
203
 
161
204
  async function build(options = {}) {
162
205
  const target = options.target || 'esp32';
163
- const release = options.release || false;
206
+ const release = options.release !== false; // Default to release
164
207
  const features = options.features || '';
208
+ const { platform } = detectPlatform();
165
209
 
166
210
  logStep(`Building for ${target}${release ? ' (release)' : ''}...`);
167
211
 
@@ -175,12 +219,33 @@ async function build(options = {}) {
175
219
 
176
220
  const rustTarget = targetMap[target] || targetMap['esp32'];
177
221
 
178
- let cmd = `cargo build --target ${rustTarget}`;
179
- if (release) cmd += ' --release';
180
- if (features) cmd += ` --features ${features}`;
181
-
182
222
  try {
183
- execSync(cmd, { stdio: 'inherit', cwd: process.cwd() });
223
+ if (platform === 'win32') {
224
+ // Windows: Use PowerShell build script if available
225
+ const scriptsDir = path.join(__dirname, '..', 'scripts', 'windows');
226
+ const buildScript = path.join(scriptsDir, 'build.ps1');
227
+
228
+ if (fs.existsSync(buildScript)) {
229
+ let psArgs = `-ExecutionPolicy Bypass -File "${buildScript}" -Target "${rustTarget}"`;
230
+ if (release) psArgs += ' -Release';
231
+ if (features) psArgs += ` -Features "${features}"`;
232
+
233
+ execSync(`powershell ${psArgs}`, { stdio: 'inherit', cwd: process.cwd() });
234
+ } else {
235
+ // Fallback to direct cargo
236
+ let cmd = `cargo build --target ${rustTarget}`;
237
+ if (release) cmd += ' --release';
238
+ if (features) cmd += ` --features ${features}`;
239
+ execSync(cmd, { stdio: 'inherit', cwd: process.cwd() });
240
+ }
241
+ } else {
242
+ // Linux/macOS
243
+ let cmd = `cargo build --target ${rustTarget}`;
244
+ if (release) cmd += ' --release';
245
+ if (features) cmd += ` --features ${features}`;
246
+ execSync(cmd, { stdio: 'inherit', cwd: process.cwd() });
247
+ }
248
+
184
249
  logSuccess('Build completed!');
185
250
  return true;
186
251
  } catch (e) {
@@ -192,12 +257,39 @@ async function build(options = {}) {
192
257
  async function flash(port, options = {}) {
193
258
  const actualPort = port || detectPort();
194
259
  const target = options.target || 'esp32';
260
+ const { platform } = detectPlatform();
195
261
 
196
262
  logStep(`Flashing to ${actualPort}...`);
197
263
 
264
+ const targetMap = {
265
+ 'esp32': 'xtensa-esp32-espidf',
266
+ 'esp32s2': 'xtensa-esp32s2-espidf',
267
+ 'esp32s3': 'xtensa-esp32s3-espidf',
268
+ 'esp32c3': 'riscv32imc-esp-espidf',
269
+ 'esp32c6': 'riscv32imac-esp-espidf'
270
+ };
271
+ const rustTarget = targetMap[target] || targetMap['esp32'];
272
+
198
273
  try {
199
- const cmd = `espflash flash --monitor --port ${actualPort} target/xtensa-${target}-espidf/release/ruvllm-esp32`;
200
- execSync(cmd, { stdio: 'inherit' });
274
+ if (platform === 'win32') {
275
+ // Windows: Use PowerShell flash script if available
276
+ const scriptsDir = path.join(__dirname, '..', 'scripts', 'windows');
277
+ const flashScript = path.join(scriptsDir, 'flash.ps1');
278
+
279
+ if (fs.existsSync(flashScript)) {
280
+ const psArgs = `-ExecutionPolicy Bypass -File "${flashScript}" -Port "${actualPort}" -Target "${rustTarget}"`;
281
+ execSync(`powershell ${psArgs}`, { stdio: 'inherit', cwd: process.cwd() });
282
+ } else {
283
+ // Fallback
284
+ const binary = `target\\${rustTarget}\\release\\ruvllm-esp32`;
285
+ execSync(`espflash flash --monitor --port ${actualPort} ${binary}`, { stdio: 'inherit' });
286
+ }
287
+ } else {
288
+ // Linux/macOS
289
+ const binary = `target/${rustTarget}/release/ruvllm-esp32`;
290
+ execSync(`espflash flash --monitor --port ${actualPort} ${binary}`, { stdio: 'inherit' });
291
+ }
292
+
201
293
  logSuccess('Flash completed!');
202
294
  return true;
203
295
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ruvllm-esp32",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "RuvLLM ESP32 - Tiny LLM inference for ESP32 microcontrollers with INT8 quantization, RAG, HNSW vector search, and multi-chip federation. Run AI on $4 hardware.",
5
5
  "keywords": [
6
6
  "esp32",
@@ -0,0 +1,124 @@
1
+ # build.ps1 - Auto-configure and build RuvLLM ESP32
2
+ # Automatically detects toolchain paths - no manual configuration needed
3
+
4
+ param(
5
+ [string]$Target = "xtensa-esp32-espidf",
6
+ [switch]$Release = $true,
7
+ [string]$Features = ""
8
+ )
9
+
10
+ $ErrorActionPreference = "Stop"
11
+
12
+ Write-Host "`n=== RuvLLM ESP32 Build ===" -ForegroundColor Cyan
13
+ Write-Host ""
14
+
15
+ # Auto-detect paths
16
+ $rustupHome = if ($env:RUSTUP_HOME) { $env:RUSTUP_HOME } else { "$env:USERPROFILE\.rustup" }
17
+ $cargoHome = if ($env:CARGO_HOME) { $env:CARGO_HOME } else { "$env:USERPROFILE\.cargo" }
18
+
19
+ # Find ESP toolchain
20
+ $espToolchain = (Get-ChildItem "$rustupHome\toolchains" -Directory -ErrorAction SilentlyContinue |
21
+ Where-Object { $_.Name -like "esp*" } |
22
+ Select-Object -First 1)
23
+
24
+ if (-not $espToolchain) {
25
+ Write-Error "ESP toolchain not found. Run .\setup.ps1 first"
26
+ }
27
+
28
+ $espToolchainPath = $espToolchain.FullName
29
+
30
+ # Find libclang dynamically
31
+ $libclang = Get-ChildItem "$espToolchainPath" -Recurse -Filter "libclang.dll" -ErrorAction SilentlyContinue |
32
+ Select-Object -First 1
33
+
34
+ if (-not $libclang) {
35
+ Write-Error "libclang.dll not found in $espToolchainPath"
36
+ }
37
+
38
+ # Find Python
39
+ $python = Get-Command python -ErrorAction SilentlyContinue
40
+ if (-not $python) {
41
+ $python = Get-Command python3 -ErrorAction SilentlyContinue
42
+ }
43
+ if (-not $python) {
44
+ Write-Error "Python not found. Please install Python 3.8+"
45
+ }
46
+ $pythonPath = Split-Path $python.Source
47
+
48
+ # Find clang and xtensa-esp-elf paths
49
+ $clangBin = Get-ChildItem "$espToolchainPath" -Recurse -Directory -Filter "esp-clang" -ErrorAction SilentlyContinue |
50
+ Select-Object -First 1
51
+ $clangBinPath = if ($clangBin) { "$($clangBin.FullName)\bin" } else { "" }
52
+
53
+ $xtensaBin = Get-ChildItem "$espToolchainPath" -Recurse -Directory -Filter "xtensa-esp-elf" -ErrorAction SilentlyContinue |
54
+ Select-Object -First 1
55
+ $xtensaBinPath = if ($xtensaBin) { "$($xtensaBin.FullName)\bin" } else { "" }
56
+
57
+ # Set environment variables
58
+ $env:LIBCLANG_PATH = Split-Path $libclang.FullName
59
+ $env:RUSTUP_TOOLCHAIN = "esp"
60
+ $env:ESP_IDF_VERSION = "v5.1.2"
61
+
62
+ # Build PATH with all required directories
63
+ $pathParts = @(
64
+ $pythonPath,
65
+ "$pythonPath\Scripts",
66
+ $clangBinPath,
67
+ $xtensaBinPath,
68
+ "$cargoHome\bin"
69
+ ) | Where-Object { $_ -ne "" }
70
+
71
+ $env:PATH = ($pathParts -join ";") + ";" + $env:PATH
72
+
73
+ Write-Host "Build Configuration:" -ForegroundColor Gray
74
+ Write-Host " Target: $Target"
75
+ Write-Host " Release: $Release"
76
+ Write-Host " Toolchain: $($espToolchain.Name)"
77
+ Write-Host " LIBCLANG_PATH: $($env:LIBCLANG_PATH)"
78
+ Write-Host ""
79
+
80
+ # Navigate to project directory
81
+ $projectDir = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
82
+ Push-Location $projectDir
83
+
84
+ try {
85
+ # Build cargo command
86
+ $cargoArgs = @("build")
87
+
88
+ if ($Release) {
89
+ $cargoArgs += "--release"
90
+ }
91
+
92
+ if ($Features) {
93
+ $cargoArgs += "--features"
94
+ $cargoArgs += $Features
95
+ }
96
+
97
+ Write-Host "Running: cargo $($cargoArgs -join ' ')" -ForegroundColor Gray
98
+ Write-Host ""
99
+
100
+ & cargo @cargoArgs
101
+
102
+ if ($LASTEXITCODE -ne 0) {
103
+ throw "Build failed with exit code $LASTEXITCODE"
104
+ }
105
+
106
+ Write-Host ""
107
+ Write-Host "Build successful!" -ForegroundColor Green
108
+
109
+ # Find the built binary
110
+ $buildDir = if ($Release) { "release" } else { "debug" }
111
+ $binary = Get-ChildItem "$projectDir\target\$Target\$buildDir" -Filter "*.elf" -ErrorAction SilentlyContinue |
112
+ Where-Object { $_.Name -notmatch "deps" } |
113
+ Select-Object -First 1
114
+
115
+ if ($binary) {
116
+ Write-Host "Binary: $($binary.FullName)" -ForegroundColor Cyan
117
+ }
118
+
119
+ Write-Host ""
120
+ Write-Host "Next: Run .\flash.ps1 to flash to device" -ForegroundColor Yellow
121
+
122
+ } finally {
123
+ Pop-Location
124
+ }
@@ -0,0 +1,60 @@
1
+ # env.ps1 - Set up ESP32 Rust environment for the current session
2
+ # Source this script: . .\env.ps1
3
+
4
+ $ErrorActionPreference = "SilentlyContinue"
5
+
6
+ # Find paths
7
+ $rustupHome = if ($env:RUSTUP_HOME) { $env:RUSTUP_HOME } else { "$env:USERPROFILE\.rustup" }
8
+ $cargoHome = if ($env:CARGO_HOME) { $env:CARGO_HOME } else { "$env:USERPROFILE\.cargo" }
9
+
10
+ # Find ESP toolchain
11
+ $espToolchain = (Get-ChildItem "$rustupHome\toolchains" -Directory |
12
+ Where-Object { $_.Name -like "esp*" } |
13
+ Select-Object -First 1)
14
+
15
+ if (-not $espToolchain) {
16
+ Write-Host "ESP toolchain not found. Run setup.ps1 first." -ForegroundColor Red
17
+ return
18
+ }
19
+
20
+ $espToolchainPath = $espToolchain.FullName
21
+
22
+ # Find libclang
23
+ $libclang = Get-ChildItem "$espToolchainPath" -Recurse -Filter "libclang.dll" |
24
+ Select-Object -First 1
25
+
26
+ # Find clang bin
27
+ $clangBin = Get-ChildItem "$espToolchainPath" -Recurse -Directory -Filter "esp-clang" |
28
+ Select-Object -First 1
29
+
30
+ # Find xtensa-esp-elf bin
31
+ $xtensaBin = Get-ChildItem "$espToolchainPath" -Recurse -Directory -Filter "xtensa-esp-elf" |
32
+ Select-Object -First 1
33
+
34
+ # Find Python
35
+ $python = Get-Command python -ErrorAction SilentlyContinue
36
+ $pythonPath = if ($python) { Split-Path $python.Source } else { "" }
37
+
38
+ # Set environment variables
39
+ $env:LIBCLANG_PATH = if ($libclang) { Split-Path $libclang.FullName } else { "" }
40
+ $env:RUSTUP_TOOLCHAIN = "esp"
41
+ $env:ESP_IDF_VERSION = "v5.1.2"
42
+
43
+ # Build PATH
44
+ $pathAdditions = @()
45
+ if ($pythonPath) { $pathAdditions += $pythonPath; $pathAdditions += "$pythonPath\Scripts" }
46
+ if ($clangBin) { $pathAdditions += "$($clangBin.FullName)\bin" }
47
+ if ($xtensaBin) { $pathAdditions += "$($xtensaBin.FullName)\bin" }
48
+ $pathAdditions += "$cargoHome\bin"
49
+
50
+ $env:PATH = ($pathAdditions -join ";") + ";" + $env:PATH
51
+
52
+ # Display status
53
+ Write-Host ""
54
+ Write-Host "ESP32 Rust environment loaded" -ForegroundColor Green
55
+ Write-Host ""
56
+ Write-Host " RUSTUP_TOOLCHAIN: $($env:RUSTUP_TOOLCHAIN)" -ForegroundColor Gray
57
+ Write-Host " LIBCLANG_PATH: $($env:LIBCLANG_PATH)" -ForegroundColor Gray
58
+ Write-Host " ESP_IDF_VERSION: $($env:ESP_IDF_VERSION)" -ForegroundColor Gray
59
+ Write-Host ""
60
+ Write-Host "Ready to build! Run: .\build.ps1" -ForegroundColor Cyan
@@ -0,0 +1,99 @@
1
+ # flash.ps1 - Auto-detect COM port and flash RuvLLM ESP32
2
+ # Automatically finds connected ESP32 devices
3
+
4
+ param(
5
+ [string]$Port = "",
6
+ [switch]$Monitor = $true,
7
+ [string]$Target = "xtensa-esp32-espidf",
8
+ [switch]$Release = $true
9
+ )
10
+
11
+ $ErrorActionPreference = "Stop"
12
+
13
+ Write-Host "`n=== RuvLLM ESP32 Flash ===" -ForegroundColor Cyan
14
+ Write-Host ""
15
+
16
+ # Auto-detect COM port if not specified
17
+ if (-not $Port) {
18
+ # Get available COM ports
19
+ Add-Type -AssemblyName System.IO.Ports
20
+ $ports = [System.IO.Ports.SerialPort]::GetPortNames() |
21
+ Where-Object { $_ -match "COM\d+" } |
22
+ Sort-Object { [int]($_ -replace "COM", "") }
23
+
24
+ if ($ports.Count -eq 0) {
25
+ Write-Error "No COM ports found. Is the ESP32 connected via USB?"
26
+ } elseif ($ports.Count -eq 1) {
27
+ $Port = $ports[0]
28
+ Write-Host "Auto-detected port: $Port" -ForegroundColor Green
29
+ } else {
30
+ Write-Host "Multiple COM ports found:" -ForegroundColor Yellow
31
+ Write-Host ""
32
+ for ($i = 0; $i -lt $ports.Count; $i++) {
33
+ Write-Host " [$i] $($ports[$i])"
34
+ }
35
+ Write-Host ""
36
+ $selection = Read-Host "Select port (0-$($ports.Count - 1))"
37
+
38
+ if ($selection -match "^\d+$" -and [int]$selection -lt $ports.Count) {
39
+ $Port = $ports[[int]$selection]
40
+ } else {
41
+ Write-Error "Invalid selection"
42
+ }
43
+ }
44
+ }
45
+
46
+ Write-Host "Using port: $Port" -ForegroundColor Cyan
47
+ Write-Host ""
48
+
49
+ # Find binary
50
+ $projectDir = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
51
+ $buildDir = if ($Release) { "release" } else { "debug" }
52
+ $targetDir = "$projectDir\target\$Target\$buildDir"
53
+
54
+ # Look for ELF or binary file
55
+ $binary = Get-ChildItem $targetDir -Filter "*.elf" -ErrorAction SilentlyContinue |
56
+ Where-Object { $_.Name -notmatch "deps" } |
57
+ Select-Object -First 1
58
+
59
+ if (-not $binary) {
60
+ $binary = Get-ChildItem $targetDir -Filter "ruvllm-esp32*" -ErrorAction SilentlyContinue |
61
+ Where-Object { $_.Name -notmatch "\." -or $_.Name -match "\.elf$" } |
62
+ Select-Object -First 1
63
+ }
64
+
65
+ if (-not $binary) {
66
+ Write-Host "Available files in $targetDir`:" -ForegroundColor Yellow
67
+ Get-ChildItem $targetDir -ErrorAction SilentlyContinue | ForEach-Object { Write-Host " $($_.Name)" }
68
+ Write-Error "No binary found. Run .\build.ps1 first"
69
+ }
70
+
71
+ Write-Host "Binary: $($binary.Name)" -ForegroundColor Gray
72
+ Write-Host ""
73
+
74
+ # Check for espflash
75
+ $espflash = Get-Command espflash -ErrorAction SilentlyContinue
76
+ if (-not $espflash) {
77
+ Write-Error "espflash not found. Run .\setup.ps1 first"
78
+ }
79
+
80
+ # Build espflash command
81
+ $espflashArgs = @("flash", "--port", $Port, $binary.FullName)
82
+
83
+ if ($Monitor) {
84
+ $espflashArgs += "--monitor"
85
+ }
86
+
87
+ Write-Host "Flashing..." -ForegroundColor Cyan
88
+ Write-Host "Command: espflash $($espflashArgs -join ' ')" -ForegroundColor Gray
89
+ Write-Host ""
90
+
91
+ # Flash the device
92
+ & espflash @espflashArgs
93
+
94
+ if ($LASTEXITCODE -ne 0) {
95
+ Write-Error "Flash failed with exit code $LASTEXITCODE"
96
+ }
97
+
98
+ Write-Host ""
99
+ Write-Host "Flash complete!" -ForegroundColor Green
@@ -0,0 +1,41 @@
1
+ # monitor.ps1 - Open serial monitor for ESP32
2
+ # Auto-detects COM port
3
+
4
+ param(
5
+ [string]$Port = "",
6
+ [int]$Baud = 115200
7
+ )
8
+
9
+ $ErrorActionPreference = "Stop"
10
+
11
+ Write-Host "`n=== RuvLLM ESP32 Serial Monitor ===" -ForegroundColor Cyan
12
+ Write-Host ""
13
+
14
+ # Auto-detect COM port if not specified
15
+ if (-not $Port) {
16
+ Add-Type -AssemblyName System.IO.Ports
17
+ $ports = [System.IO.Ports.SerialPort]::GetPortNames() |
18
+ Where-Object { $_ -match "COM\d+" } |
19
+ Sort-Object { [int]($_ -replace "COM", "") }
20
+
21
+ if ($ports.Count -eq 0) {
22
+ Write-Error "No COM ports found. Is the ESP32 connected?"
23
+ } elseif ($ports.Count -eq 1) {
24
+ $Port = $ports[0]
25
+ Write-Host "Auto-detected port: $Port" -ForegroundColor Green
26
+ } else {
27
+ Write-Host "Multiple COM ports found:" -ForegroundColor Yellow
28
+ for ($i = 0; $i -lt $ports.Count; $i++) {
29
+ Write-Host " [$i] $($ports[$i])"
30
+ }
31
+ $selection = Read-Host "Select port (0-$($ports.Count - 1))"
32
+ $Port = $ports[[int]$selection]
33
+ }
34
+ }
35
+
36
+ Write-Host "Opening monitor on $Port at $Baud baud..." -ForegroundColor Cyan
37
+ Write-Host "Press Ctrl+C to exit" -ForegroundColor Gray
38
+ Write-Host ""
39
+
40
+ # Use espflash monitor
41
+ & espflash monitor --port $Port --baud $Baud
@@ -0,0 +1,118 @@
1
+ # setup.ps1 - One-time Windows setup for RuvLLM ESP32
2
+ # Run this once to install/configure the ESP32 Rust toolchain
3
+
4
+ $ErrorActionPreference = "Stop"
5
+
6
+ Write-Host "`n=== RuvLLM ESP32 Windows Setup ===" -ForegroundColor Cyan
7
+ Write-Host ""
8
+
9
+ # Find Rust ESP toolchain dynamically
10
+ $rustupHome = if ($env:RUSTUP_HOME) { $env:RUSTUP_HOME } else { "$env:USERPROFILE\.rustup" }
11
+ $cargoHome = if ($env:CARGO_HOME) { $env:CARGO_HOME } else { "$env:USERPROFILE\.cargo" }
12
+
13
+ # Check if Rust is installed
14
+ $rustc = Get-Command rustc -ErrorAction SilentlyContinue
15
+ if (-not $rustc) {
16
+ Write-Host "Rust not found. Installing rustup..." -ForegroundColor Yellow
17
+ Invoke-WebRequest -Uri "https://win.rustup.rs/x86_64" -OutFile rustup-init.exe
18
+ .\rustup-init.exe -y --default-toolchain stable
19
+ Remove-Item rustup-init.exe
20
+ $env:PATH = "$cargoHome\bin;" + $env:PATH
21
+ Write-Host "Rust installed successfully" -ForegroundColor Green
22
+ }
23
+
24
+ # Find or install ESP toolchain
25
+ $espToolchain = Get-ChildItem "$rustupHome\toolchains" -Directory -ErrorAction SilentlyContinue |
26
+ Where-Object { $_.Name -like "esp*" } |
27
+ Select-Object -First 1
28
+
29
+ if (-not $espToolchain) {
30
+ Write-Host "ESP toolchain not found. Installing espup..." -ForegroundColor Yellow
31
+
32
+ # Download espup
33
+ $espupUrl = "https://github.com/esp-rs/espup/releases/latest/download/espup-x86_64-pc-windows-msvc.exe"
34
+ $espupPath = "$env:TEMP\espup.exe"
35
+
36
+ Write-Host "Downloading espup..." -ForegroundColor Gray
37
+ Invoke-WebRequest -Uri $espupUrl -OutFile $espupPath
38
+
39
+ Write-Host "Running espup install (this may take several minutes)..." -ForegroundColor Gray
40
+ & $espupPath install
41
+
42
+ if ($LASTEXITCODE -ne 0) {
43
+ Write-Error "espup install failed with exit code $LASTEXITCODE"
44
+ }
45
+
46
+ Remove-Item $espupPath -ErrorAction SilentlyContinue
47
+
48
+ # Re-check for toolchain
49
+ $espToolchain = Get-ChildItem "$rustupHome\toolchains" -Directory |
50
+ Where-Object { $_.Name -like "esp*" } |
51
+ Select-Object -First 1
52
+ }
53
+
54
+ if (-not $espToolchain) {
55
+ Write-Error "ESP toolchain installation failed. Please install manually: https://esp-rs.github.io/book/"
56
+ }
57
+
58
+ Write-Host "Found ESP toolchain: $($espToolchain.Name)" -ForegroundColor Green
59
+
60
+ # Find Python
61
+ $python = Get-Command python -ErrorAction SilentlyContinue
62
+ if (-not $python) {
63
+ $python = Get-Command python3 -ErrorAction SilentlyContinue
64
+ }
65
+ if (-not $python) {
66
+ Write-Error "Python not found. Please install Python 3.8+ from https://python.org"
67
+ }
68
+ Write-Host "Found Python: $($python.Source)" -ForegroundColor Green
69
+
70
+ # Find libclang
71
+ $libclang = Get-ChildItem "$($espToolchain.FullName)" -Recurse -Filter "libclang.dll" -ErrorAction SilentlyContinue |
72
+ Select-Object -First 1
73
+
74
+ if ($libclang) {
75
+ Write-Host "Found libclang: $($libclang.FullName)" -ForegroundColor Green
76
+ } else {
77
+ Write-Host "Warning: libclang.dll not found in toolchain" -ForegroundColor Yellow
78
+ }
79
+
80
+ # Install espflash if not present
81
+ $espflash = Get-Command espflash -ErrorAction SilentlyContinue
82
+ if (-not $espflash) {
83
+ Write-Host "Installing espflash..." -ForegroundColor Yellow
84
+ cargo install espflash
85
+ if ($LASTEXITCODE -ne 0) {
86
+ Write-Error "espflash installation failed"
87
+ }
88
+ Write-Host "espflash installed successfully" -ForegroundColor Green
89
+ } else {
90
+ Write-Host "Found espflash: $($espflash.Source)" -ForegroundColor Green
91
+ }
92
+
93
+ # Install ldproxy if not present
94
+ $ldproxy = Get-Command ldproxy -ErrorAction SilentlyContinue
95
+ if (-not $ldproxy) {
96
+ Write-Host "Installing ldproxy..." -ForegroundColor Yellow
97
+ cargo install ldproxy
98
+ if ($LASTEXITCODE -ne 0) {
99
+ Write-Error "ldproxy installation failed"
100
+ }
101
+ Write-Host "ldproxy installed successfully" -ForegroundColor Green
102
+ }
103
+
104
+ Write-Host ""
105
+ Write-Host "=== Setup Complete ===" -ForegroundColor Green
106
+ Write-Host ""
107
+ Write-Host "Summary:" -ForegroundColor Cyan
108
+ Write-Host " Toolchain: $($espToolchain.Name)"
109
+ Write-Host " Python: $($python.Source)"
110
+ if ($libclang) {
111
+ Write-Host " Libclang: $($libclang.FullName)"
112
+ }
113
+ Write-Host ""
114
+ Write-Host "Next steps:" -ForegroundColor Yellow
115
+ Write-Host " 1. Run: .\build.ps1"
116
+ Write-Host " 2. Connect ESP32 via USB"
117
+ Write-Host " 3. Run: .\flash.ps1"
118
+ Write-Host ""