191 lines
7.1 KiB
Batchfile
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
|