param(
    [Parameter(Mandatory = $true)] [string] $Bootloader,
    [Parameter(Mandatory = $true)] [string] $App1,
    [Parameter(Mandatory = $true)] [string] $App2,
    [Parameter(Mandatory = $true)] [string] $Output
)

$ErrorActionPreference = 'Stop'

$flashSize = 0x20000
$bootloaderOffset = 0x00000
$bootloaderSize = 0x06000
$app1Offset = 0x06000
$app1Size = 0x0D000
$app2Offset = 0x13000
$app2Size = 0x0D000

$image = [byte[]]::new($flashSize)
for ($index = 0; $index -lt $image.Length; $index++) {
    $image[$index] = 0xFF
}

function Add-FirmwareImage {
    param(
        [string] $Path,
        [int] $Offset,
        [int] $MaximumSize,
        [string] $Name
    )

    $bytes = [System.IO.File]::ReadAllBytes((Resolve-Path -LiteralPath $Path))
    if ($bytes.Length -gt $MaximumSize) {
        throw "$Name is $($bytes.Length) bytes; its slot is only $MaximumSize bytes."
    }

    [System.Array]::Copy($bytes, 0, $image, $Offset, $bytes.Length)
}

Add-FirmwareImage -Path $Bootloader -Offset $bootloaderOffset `
    -MaximumSize $bootloaderSize -Name 'Bootloader'
Add-FirmwareImage -Path $App1 -Offset $app1Offset `
    -MaximumSize $app1Size -Name 'XInput App1'
Add-FirmwareImage -Path $App2 -Offset $app2Offset `
    -MaximumSize $app2Size -Name 'DInput App2'

[System.IO.File]::WriteAllBytes($Output, $image)
Write-Host "Combined 128 KB firmware image written to $Output"
