Files
mcu-codegen-template/App/OutputHex.bat
T

191 lines
7.1 KiB
Batchfile

@echo off
setlocal
@REM ============================================================
@REM Keil AfterMake: copy HEX and generate BIN after each build
@REM Working dir may be MDK-ARM, so always switch to script dir
@REM ============================================================
cd /d "%~dp0"
@REM Executable name (same as Keil OutputName)
set HEX_NAME=Project
@REM Keil output directory
set HEX_PATH=%cd%\MDK-ARM\Objects
@REM Custom output directory
set OUTPUT_PATH=%cd%\Output
@REM Project code: application.h __PROJECT_CODE__
@REM Soft version: jb_product.h JB_MCU_SW_VERSION_* (single source of truth)
set APP_H=%cd%\Inc\application.h
set PRODUCT_H=%cd%\Protocol\jb_product.h
@REM Optional arg1: Keil root ($K) passed by AfterMake
set "KEIL_ROOT=%~1"
@REM ------------------------------------------------------------
@REM Timestamp: yyMMdd_HHmmss
@REM ------------------------------------------------------------
for /f %%i in ('powershell -NoProfile -Command "Get-Date -Format yyMMdd_HHmmss"') do set CURRENT_DATE=%%i
@REM ------------------------------------------------------------
@REM Compose name: PROJECT_MAJOR.MINOR.PATCH
@REM ------------------------------------------------------------
set PROJECT_CODE=DEMO
set VER_MAJOR=0
set VER_MINOR=0
set VER_PATCH=0
for /f "tokens=3 delims= " %%i in ('findstr /C:"#define __PROJECT_CODE__" "%APP_H%"') do set PROJECT_CODE=%%i
if defined PROJECT_CODE set PROJECT_CODE=%PROJECT_CODE:"=%
for /f "tokens=3 delims= " %%i in ('findstr /C:"#define JB_MCU_SW_VERSION_MAJOR" "%PRODUCT_H%"') do set VER_MAJOR=%%i
for /f "tokens=3 delims= " %%i in ('findstr /C:"#define JB_MCU_SW_VERSION_MINOR" "%PRODUCT_H%"') do set VER_MINOR=%%i
for /f "tokens=3 delims= " %%i in ('findstr /C:"#define JB_MCU_SW_VERSION_PATCH" "%PRODUCT_H%"') do set VER_PATCH=%%i
set SW_Ver=%PROJECT_CODE%_%VER_MAJOR%.%VER_MINOR%.%VER_PATCH%
set output_file_name=%SW_Ver%_%CURRENT_DATE%
echo Firmware version: %SW_Ver%
if not exist "%OUTPUT_PATH%" mkdir "%OUTPUT_PATH%"
@REM ------------------------------------------------------------
@REM Copy HEX
@REM ------------------------------------------------------------
if exist "%HEX_PATH%\%HEX_NAME%.hex" (
echo Output hex file: %OUTPUT_PATH%\%output_file_name%.hex
copy /Y "%HEX_PATH%\%HEX_NAME%.hex" "%OUTPUT_PATH%\%output_file_name%.hex" >nul
if errorlevel 1 (
echo [ERROR] Failed to copy HEX
) else (
echo [OK] HEX copied
)
) else (
echo [ERROR] HEX not found: %HEX_PATH%\%HEX_NAME%.hex
)
@REM ------------------------------------------------------------
@REM Generate BIN via fromelf (AXF), fallback: HEX to BIN
@REM ------------------------------------------------------------
set "FROMELF="
set "BIN_FILE=%HEX_PATH%\%HEX_NAME%.bin"
call :find_fromelf
if not "%FROMELF%"=="" if exist "%HEX_PATH%\%HEX_NAME%.axf" (
echo Using fromelf: %FROMELF%
"%FROMELF%" --bincombined --output="%BIN_FILE%" "%HEX_PATH%\%HEX_NAME%.axf"
if errorlevel 1 (
echo [WARN] fromelf --bincombined failed, try --bin
"%FROMELF%" --bin --output="%BIN_FILE%" "%HEX_PATH%\%HEX_NAME%.axf"
)
)
if not exist "%BIN_FILE%" (
echo [WARN] Convert HEX to BIN
call :hex2bin
)
if not exist "%BIN_FILE%" (
echo [ERROR] BIN not generated
exit /b 1
)
echo Output bin file: %OUTPUT_PATH%\%output_file_name%.bin
copy /Y "%BIN_FILE%" "%OUTPUT_PATH%\%output_file_name%.bin" >nul
if errorlevel 1 (
echo [ERROR] Failed to copy BIN
exit /b 1
) else (
echo [OK] BIN copied
)
exit /b 0
@REM ============================================================
@REM Find fromelf.exe
@REM ============================================================
:find_fromelf
if not "%KEIL_ROOT%"=="" (
if exist "%KEIL_ROOT%\ARM\ARM_Compiler_5.06u7\bin\fromelf.exe" (
set "FROMELF=%KEIL_ROOT%\ARM\ARM_Compiler_5.06u7\bin\fromelf.exe"
goto :eof
)
if exist "%KEIL_ROOT%\ARM\ARMCC\bin\fromelf.exe" (
set "FROMELF=%KEIL_ROOT%\ARM\ARMCC\bin\fromelf.exe"
goto :eof
)
if exist "%KEIL_ROOT%\ARM\ARMCLANG\bin\fromelf.exe" (
set "FROMELF=%KEIL_ROOT%\ARM\ARMCLANG\bin\fromelf.exe"
goto :eof
)
)
set "KEIL_ARM="
for /f "tokens=2*" %%a in ('reg query "HKLM\SOFTWARE\WOW6432Node\Keil\Products\MDK" /v Path 2^>nul') do set "KEIL_ARM=%%b"
if "%KEIL_ARM%"=="" (
for /f "tokens=2*" %%a in ('reg query "HKLM\SOFTWARE\Keil\Products\MDK" /v Path 2^>nul') do set "KEIL_ARM=%%b"
)
if not "%KEIL_ARM%"=="" (
if exist "%KEIL_ARM%\ARM_Compiler_5.06u7\bin\fromelf.exe" (
set "FROMELF=%KEIL_ARM%\ARM_Compiler_5.06u7\bin\fromelf.exe"
goto :eof
)
if exist "%KEIL_ARM%\ARMCC\bin\fromelf.exe" (
set "FROMELF=%KEIL_ARM%\ARMCC\bin\fromelf.exe"
goto :eof
)
if exist "%KEIL_ARM%\ARMCLANG\bin\fromelf.exe" (
set "FROMELF=%KEIL_ARM%\ARMCLANG\bin\fromelf.exe"
goto :eof
)
)
where fromelf.exe >nul 2>&1
if not errorlevel 1 set "FROMELF=fromelf.exe"
goto :eof
@REM ============================================================
@REM Fallback: Intel HEX -> BIN (image starts at first data addr)
@REM Write a temp ps1 to avoid cmd parenthesis parsing issues
@REM ============================================================
:hex2bin
if not exist "%HEX_PATH%\%HEX_NAME%.hex" (
echo [ERROR] HEX not found, cannot convert to BIN
goto :eof
)
set "PS1_FILE=%TEMP%\ota_hex2bin.ps1"
> "%PS1_FILE%" echo $hex = $args[0]
>> "%PS1_FILE%" echo $bin = $args[1]
>> "%PS1_FILE%" echo $map = @{}
>> "%PS1_FILE%" echo $min = [uint32]::MaxValue
>> "%PS1_FILE%" echo $max = [uint32]0
>> "%PS1_FILE%" echo $ext = [uint32]0
>> "%PS1_FILE%" echo Get-Content -LiteralPath $hex ^| ForEach-Object {
>> "%PS1_FILE%" echo if ($_.Length -lt 11) { return }
>> "%PS1_FILE%" echo if ($_[0] -ne [char]58) { return }
>> "%PS1_FILE%" echo $len = [Convert]::ToInt32($_.Substring(1,2),16)
>> "%PS1_FILE%" echo $addr = [Convert]::ToUInt32($_.Substring(3,4),16)
>> "%PS1_FILE%" echo $type = [Convert]::ToInt32($_.Substring(7,2),16)
>> "%PS1_FILE%" echo if ($type -eq 4) { $ext = [Convert]::ToUInt32($_.Substring(9,4),16) -shl 16; return }
>> "%PS1_FILE%" echo if ($type -eq 2) { $ext = [Convert]::ToUInt32($_.Substring(9,4),16) * 16; return }
>> "%PS1_FILE%" echo if ($type -ne 0) { return }
>> "%PS1_FILE%" echo $fa = $ext + $addr
>> "%PS1_FILE%" echo if ($fa -lt $min) { $min = $fa }
>> "%PS1_FILE%" echo for ($i = 0; $i -lt $len; $i++) { $map[$fa+$i] = [Convert]::ToByte($_.Substring(9+$i*2,2),16) }
>> "%PS1_FILE%" echo if (($fa+$len) -gt $max) { $max = $fa+$len }
>> "%PS1_FILE%" echo }
>> "%PS1_FILE%" echo if ($max -le $min) { throw 'No HEX data records' }
>> "%PS1_FILE%" echo $size = $max - $min
>> "%PS1_FILE%" echo $bytes = New-Object byte[] $size
>> "%PS1_FILE%" echo for ($i = 0; $i -lt $size; $i++) { $bytes[$i] = 0xFF }
>> "%PS1_FILE%" echo foreach ($k in $map.Keys) { $bytes[$k-$min] = $map[$k] }
>> "%PS1_FILE%" echo [IO.File]::WriteAllBytes($bin, $bytes)
>> "%PS1_FILE%" echo Write-Host ('[OK] HEX converted to BIN, size={0} bytes, base=0x{1:X8}' -f $size, $min)
powershell -NoProfile -ExecutionPolicy Bypass -File "%PS1_FILE%" "%HEX_PATH%\%HEX_NAME%.hex" "%BIN_FILE%"
goto :eof