Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # build_all.ps1 - Build all ESP monitor board configurations in parallel
- param(
- [int]$MaxParallel = [Environment]::ProcessorCount
- )
- $ErrorActionPreference = "Stop"
- # Check for IDF_PATH
- if (-not $env:IDF_TOOLS_PATH) {
- Write-Host "ERROR: IDF_PATH environment variable not set!" -ForegroundColor Red
- Write-Host "Please install ESP-IDF and run the installer's environment setup."
- exit 1
- }
- Write-Host "Activating ESP-IDF environment..." -ForegroundColor Cyan
- $espIdfConfigPath = Join-Path $env:IDF_TOOLS_PATH "esp_idf.json"
- if (-not (Test-Path $espIdfConfigPath)) {
- Write-Host "ERROR: esp_idf.json not found at $espIdfConfigPath" -ForegroundColor Red
- exit 1
- }
- $espIdfConfig = Get-Content $espIdfConfigPath | ConvertFrom-Json
- $idfId = $espIdfConfig.idfSelectedId
- $initScript = Join-Path $env:IDF_TOOLS_PATH "Initialize-Idf.ps1"
- Write-Host "Using ESP-IDF ID: $idfId" -ForegroundColor Gray
- . $initScript -IdfId $idfId
- if (-not (Get-Command idf.py -ErrorAction SilentlyContinue)) {
- Write-Host "Failed to activate ESP-IDF environment!" -ForegroundColor Red
- exit 1
- }
- $commonPath = Join-Path $PSScriptRoot ".."
- $commonPath = Join-Path $commonPath "common"
- $nanopbgenPath = Join-Path $PSScriptRoot "nanopb_generator"
- $nanopbgenPath = Join-Path $nanopbgenPath "nanopb_generator.py"
- #./nanopb_generator/nanopb_generator.py -I ../common espmon.proto -D ../common
- Write-Host "Generating nanopb code" -ForegroundColor Gray
- & pip install protobuf grpcio-tools
- & python $nanopbgenPath -I $commonPath espmon.proto -D $commonPath
- # Read boards.json
- $boardsJsonPath = Join-Path $PSScriptRoot "boards.json"
- if (-not (Test-Path $boardsJsonPath)) {
- Write-Host "ERROR: boards.json not found at $boardsJsonPath" -ForegroundColor Red
- exit 1
- }
- $boardsJsonTime = (Get-Item $boardsJsonPath).LastWriteTime
- $boardsData = Get-Content $boardsJsonPath | ConvertFrom-Json
- $boards = $boardsData.boards
- # Capture UTC epoch timestamp once for the whole build.
- # This is passed to each firmware build as BUILD_TIMESTAMP_UTC so the
- # firmware can report an exact UTC epoch value without any date/time parsing.
- $buildTimestampUtc = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds()
- Write-Host "Build timestamp (UTC): $buildTimestampUtc" -ForegroundColor Gray
- Write-Host ""
- Write-Host "========================================"
- Write-Host "Building $($boards.Count) board configurations in parallel"
- Write-Host "Max parallel jobs: $MaxParallel"
- Write-Host "========================================"
- Write-Host ""
- # Create firmware output directory
- $firmwareDir = Join-Path $PSScriptRoot ".."
- $firmwareDir = Join-Path $firmwareDir "EspMon.PortDispatcher"
- $firmwareDir = Join-Path $firmwareDir "firmware"
- if (-not (Test-Path $firmwareDir)) {
- New-Item -ItemType Directory -Path $firmwareDir | Out-Null
- }
- $pbcCommonPath = Join-Path $commonPath "espmon.pb.c"
- $pbcTargetPath = Join-Path $PSScriptRoot "shared"
- $pbcTargetPath = Join-Path $pbcTargetPath "main"
- if (-not (Test-Path $pbcTargetPath) -or (Get-Item $pbcTargetPath).LastWriteTime -lt (Get-Item $pbcCommonPath).LastWriteTime) {
- Write-Host "Copying protobuf source" -ForegroundColor Gray
- Copy-Item $pbcCommonPath $pbcTargetPath
- }
- # Start parallel builds
- $jobs = @()
- $scriptRootForJobs = $PSScriptRoot # Capture it first
- foreach ($board in $boards) {
- # Wait if we have hit max parallel jobs
- while ((Get-Job -State Running).Count -ge $MaxParallel) {
- Start-Sleep -Milliseconds 100
- }
- Write-Host "Starting build for: $($board.name)" -ForegroundColor Cyan
- $boardName = $board.name
- $boardSlug = $board.slug
- $boardTarget = $board.target
- $boardId = $board.id
- $boardDiagonalInches = $board.diagonal_inches
- $needsClean = $false
- # Write idf_component.yml for this board
- $ymlPath = Join-Path $PSScriptRoot "boards"
- $ymlPath = Join-Path $ymlPath $boardSlug
- $ymlPath = Join-Path $ymlPath "main"
- $ymlPath = Join-Path $ymlPath "idf_component.yml"
- if (-not (Test-Path $ymlPath) -or (Get-Item $ymlPath).LastWriteTime -lt $boardsJsonTime) {
- $ymlLines = [System.Collections.Generic.List[string]]::new()
- $ymlLines.Add("## IDF Component Manager Manifest File")
- $ymlLines.Add("## Auto-generated by build_all.ps1 -- do not edit by hand.")
- $ymlLines.Add("dependencies:")
- $ymlLines.Add(" idf:")
- $ymlLines.Add(" version: '>=5.4.3'")
- # Merge global and board-specific dependencies
- $allDeps = @()
- if ($boardsData.dependencies) { $allDeps += $boardsData.dependencies }
- if ($board.dependencies) { $allDeps += $board.dependencies }
- foreach ($dep in $allDeps) {
- $ymlLines.Add(" $($dep.id): `"$($dep.version)`"")
- }
- Set-Content -Path $ymlPath -Value $ymlLines -Encoding UTF8
- Write-Host " Written: idf_component.yml" -ForegroundColor Gray
- $needsClean = $true
- } else {
- Write-Host " Skipped: idf_component.yml (up to date)" -ForegroundColor DarkGray
- }
- # Write board_config.h for this board before the build
- $boardConfigPath = Join-Path $PSScriptRoot "boards"
- $boardConfigPath = Join-Path $boardConfigPath $boardSlug
- $boardConfigPath = Join-Path $boardConfigPath "main"
- $boardConfigPath = Join-Path $boardConfigPath "board_config.h"
- if (-not (Test-Path $boardConfigPath) -or (Get-Item $boardConfigPath).LastWriteTime -lt $boardsJsonTime) {
- # Escape inner quotes in display name for use in a C string literal
- $escapedName = $boardName -replace '"', '\"'
- $lines = [System.Collections.Generic.List[string]]::new()
- $lines.Add("// <auto-generated>")
- $lines.Add("// Generated by build_all.ps1 -- do not edit by hand.")
- $lines.Add("// </auto-generated>")
- $lines.Add("#ifndef BOARD_CONFIG_H")
- $lines.Add("#define BOARD_CONFIG_H")
- $lines.Add("#define FIRMWARE_BOARD_ID $boardId")
- $lines.Add("#define FIRMWARE_DISPLAY_NAME `"$escapedName`"")
- $lines.Add("#define FIRMWARE_SLUG `"$boardSlug`"")
- $lines.Add("#define LCD_INCHES ((float)${boardDiagonalInches})")
- $lines.Add("#endif")
- Set-Content -Path $boardConfigPath -Value $lines -Encoding UTF8
- Write-Host " Written: board_config.h" -ForegroundColor Gray
- } else {
- Write-Host " Skipped: board_config.h (up to date)" -ForegroundColor DarkGray
- }
- # Write CMakeLists.txt for this board
- $cmakePath = Join-Path $PSScriptRoot "boards"
- $cmakePath = Join-Path $cmakePath $boardSlug
- $cmakePath = Join-Path $cmakePath "CMakeLists.txt"
- if (-not (Test-Path $cmakePath) -or (Get-Item $cmakePath).LastWriteTime -lt $boardsJsonTime) {
- $cmakeLines = [System.Collections.Generic.List[string]]::new()
- $cmakeLines.Add("cmake_minimum_required(VERSION 3.16)")
- $cmakeLines.Add("")
- $cmakeLines.Add("# Auto-generated by build_all.ps1 -- do not edit by hand.")
- $cmakeLines.Add("")
- $cmakeLines.Add("# Injected by build system")
- $cmakeLines.Add("add_compile_definitions(BUILD_TIMESTAMP_UTC=`${BUILD_TIMESTAMP_UTC})")
- $cmakeLines.Add("")
- $cmakeLines.Add("# Board-specific defines")
- foreach ($define in $board.defines) {
- $cmakeLines.Add("add_compile_definitions($define)")
- }
- $cmakeLines.Add("")
- $cmakeLines.Add("include(`$ENV{IDF_PATH}/tools/cmake/project.cmake)")
- $cmakeLines.Add("")
- $cmakeLines.Add("project(espmon)")
- Set-Content -Path $cmakePath -Value $cmakeLines -Encoding UTF8
- Write-Host " Written: CMakeLists.txt" -ForegroundColor Gray
- $needsClean = $true
- } else {
- Write-Host " Skipped: CMakeLists.txt (up to date)" -ForegroundColor DarkGray
- }
- # If any generated files changed, wipe build artifacts so CMake/IDF starts fresh
- if ($needsClean) {
- $boardDir = Join-Path $PSScriptRoot "boards" | Join-Path -ChildPath $boardSlug
- $buildDir = Join-Path $boardDir "build"
- $managedComponentsDir = Join-Path $boardDir "managed_components"
- foreach ($cleanDir in @($buildDir, $managedComponentsDir)) {
- if (Test-Path $cleanDir) {
- Remove-Item $cleanDir -Recurse -Force
- Write-Host " Cleaned: $($cleanDir | Split-Path -Leaf)" -ForegroundColor DarkYellow
- }
- }
- }
- $job = Start-Job -ScriptBlock {
- param($name, $slug, $target, $root, $buildTimestampUtc, $defines)
- $boardDir = "$root\boards\$slug"
- $buildDir = "$boardDir\build"
- $result = @{
- Name = $name
- Slug = $slug
- Success = $false
- Error = $null
- }
- Write-Host "Name: $name" -ForegroundColor Cyan
- Write-Host "Slug: $slug" -ForegroundColor Cyan
- Write-Host "Target: $target" -ForegroundColor Cyan
- Write-Host ""
- try {
- # Set target
- Write-Host "[$name] Setting target to $target..." -ForegroundColor Yellow
- $setTargetOutput = & idf.py.exe -C $boardDir set-target $target 2>&1
- if ($LASTEXITCODE -ne 0) {
- throw "Failed to set target: $setTargetOutput"
- }
- # Build
- Write-Host "[$name] Building..." -ForegroundColor Yellow
- $dArgs = @("-DBUILD_TIMESTAMP_UTC=$buildTimestampUtc") + ($defines | ForEach-Object {
- if ($_ -match '=') { "-D$_" } else { "-D$_=1" }
- })
- $buildOutput = & idf.py -C $boardDir build @dArgs 2>&1 | Out-String
- $buildExitCode = $LASTEXITCODE
- if ($buildExitCode -ne 0) {
- throw "Build failed with exit code $buildExitCode : $buildOutput"
- }
- Write-Host "[$name] Build completed, creating output directory..." -ForegroundColor Yellow
- $firmwareOutDir = Join-Path $root ".."
- $firmwareOutDir = Join-Path $firmwareOutDir "Espmon.PortDispatcher"
- $firmwareOutDir = Join-Path $firmwareOutDir "firmware"
- $firmwareOutDir = Join-Path $firmwareOutDir $slug
- if (-not (Test-Path $firmwareOutDir)) {
- New-Item -ItemType Directory -Path $firmwareOutDir | Out-Null
- }
- Write-Host "[$name] Copying binaries..." -ForegroundColor Yellow
- Copy-Item "$buildDir\bootloader\*.bin" $firmwareOutDir
- Write-Host "[$name] Copied bootloader" -ForegroundColor Yellow
- Copy-Item "$buildDir\partition_table\*.bin" $firmwareOutDir
- Write-Host "[$name] Copied partition table" -ForegroundColor Yellow
- $appBin = Get-ChildItem "$buildDir\*.bin" -Exclude "*bootloader*","*partition*" | Select-Object -First 1
- Copy-Item $appBin.FullName -Destination "$firmwareOutDir\firmware.bin"
- Write-Host "[$name] Copied app binary" -ForegroundColor Yellow
- $result.Success = $true
- Write-Host "[$name] Build completed successfully!" -ForegroundColor Green
- }
- catch {
- $result.Error = $_.Exception.Message
- Write-Host "[$name] Build failed: $($_.Exception.Message)" -ForegroundColor Red
- }
- return $result
- } -ArgumentList $boardName, $boardSlug, $boardTarget, $scriptRootForJobs, $buildTimestampUtc, $board.defines
- $jobs += $job
- }
- # Wait for all jobs to complete and collect results
- Write-Host ""
- Write-Host "Waiting for builds to complete..." -ForegroundColor Cyan
- $results = $jobs | Wait-Job | Receive-Job
- $jobs | Remove-Job
- # Display summary
- Write-Host ""
- Write-Host "========================================"
- Write-Host "Build Summary"
- Write-Host "========================================"
- $successCount = 0
- $failCount = 0
- foreach ($result in $results) {
- if ($result.Success) {
- Write-Host "OK $($result.Name)" -ForegroundColor Green
- $successCount++
- }
- else {
- Write-Host "FAIL $($result.Name)" -ForegroundColor Red
- Write-Host " Error: $($result.Error)" -ForegroundColor Red
- $failCount++
- }
- }
- Write-Host ""
- Write-Host "Success: $successCount | Failed: $failCount" -ForegroundColor $(if ($failCount -eq 0) { "Green" } else { "Yellow" })
- if ($failCount -eq 0) {
- Write-Host ""
- Write-Host "All boards built successfully!" -ForegroundColor Green
- # Create boards.zip with all files except boards.json
- Write-Host ""
- Write-Host "Creating boards.zip..." -ForegroundColor Cyan
- $zipPath = Join-Path $firmwareDir "boards.zip"
- # Remove existing zip if present
- if (Test-Path $zipPath) {
- Remove-Item $zipPath -Force
- }
- # Get all items in firmware directory (subdirectories only at this point)
- $itemsToZip = Get-ChildItem -Path $firmwareDir -Directory
- if ($itemsToZip.Count -gt 0) {
- # Create zip archive with all subdirectories
- Compress-Archive -Path ($itemsToZip | ForEach-Object { $_.FullName }) `
- -DestinationPath $zipPath `
- -CompressionLevel Optimal
- Write-Host "Created boards.zip successfully" -ForegroundColor Green
- # Delete the loose directories
- Write-Host "Cleaning up loose files..." -ForegroundColor Cyan
- $itemsToZip | ForEach-Object {
- Remove-Item $_.FullName -Recurse -Force
- Write-Host " Removed: $($_.Name)" -ForegroundColor Gray
- }
- Write-Host "Cleanup completed" -ForegroundColor Green
- }
- else {
- Write-Host "Warning: No files to zip" -ForegroundColor Yellow
- }
- # Copy boards.json to firmware directory after cleanup
- Copy-Item $boardsJsonPath (Join-Path $firmwareDir "boards.json")
- # Generate FirmwareBuildTimestamp.cs
- Write-Host ""
- Write-Host "Generating FirmwareBuildTimestamp.cs..." -ForegroundColor Cyan
- # Use the same timestamp injected into the firmware so both sides are identical.
- $csContent = @"
- // <auto-generated>
- // Generated by build_all.ps1 -- do not edit by hand.
- // </auto-generated>
- using System;
- namespace Espmon
- {
- public static class FirmwareBuild
- {
- public static readonly ulong Timestamp = (ulong)$buildTimestampUtc;
- }
- }
- "@
- $csOutputPath = Join-Path $firmwareDir ".."
- $csOutputPath = Join-Path $csOutputPath "FirmwareBuildTimestamp.cs"
- $csOutputPath = [System.IO.Path]::GetFullPath($csOutputPath)
- Set-Content -Path $csOutputPath -Value $csContent -Encoding UTF8
- Write-Host "Written: $csOutputPath" -ForegroundColor Green
- Write-Host " Timestamp (UTC): $buildTimestampUtc" -ForegroundColor Gray
- Write-Host ""
- Write-Host "Firmware package available in: firmware/" -ForegroundColor Cyan
- Write-Host " - boards.zip (firmware binaries)" -ForegroundColor Cyan
- Write-Host " - boards.json (metadata)" -ForegroundColor Cyan
- exit 0
- }
- else {
- Write-Host ""
- Write-Host "Some boards failed to build. Check errors above." -ForegroundColor Red
- exit 1
- }
Advertisement
Add Comment
Please, Sign In to add comment