|
| 1 | +@ECHO OFF |
| 2 | +SETLOCAL EnableDelayedExpansion |
| 3 | +TITLE Meshtastic device-install |
| 4 | + |
| 5 | +SET "SCRIPT_NAME=%~nx0" |
| 6 | +SET "DEBUG=0" |
| 7 | +SET "PYTHON=" |
| 8 | +SET "TFT_BUILD=0" |
| 9 | +SET "BIGDB8=0" |
| 10 | +SET "MUIDB8=0" |
| 11 | +SET "BIGDB16=0" |
| 12 | +SET "ESPTOOL_BAUD=115200" |
| 13 | +SET "ESPTOOL_CMD=" |
| 14 | +SET "LOGCOUNTER=0" |
| 15 | +SET "BPS_RESET=0" |
| 16 | + |
| 17 | +@REM FIXME: Determine mcu from PlatformIO variant, this is unmaintainable. |
| 18 | +SET "S3=s3 v3 t-deck wireless-paper wireless-tracker station-g2 unphone t-eth-elite tlora-pager mesh-tab dreamcatcher ESP32-S3-Pico seeed-sensecap-indicator heltec_capsule_sensor_v3 vision-master icarus tracksenger elecrow-adv" |
| 19 | +SET "C3=esp32c3" |
| 20 | +@REM FIXME: Determine flash size from PlatformIO variant, this is unmaintainable. |
| 21 | +SET "BIGDB_8MB=crowpanel-esp32s3 heltec_capsule_sensor_v3 heltec-v3 heltec-vision-master-e213 heltec-vision-master-e290 heltec-vision-master-t190 heltec-wireless-paper heltec-wireless-tracker heltec-wsl-v3 icarus seeed-xiao-s3 tbeam-s3-core tracksenger" |
| 22 | +SET "MUIDB_8MB=picomputer-s3 unphone seeed-sensecap-indicator" |
| 23 | +SET "BIGDB_16MB=t-deck mesh-tab t-energy-s3 dreamcatcher ESP32-S3-Pico m5stack-cores3 station-g2 t-eth-elite tlora-pager t-watch-s3 elecrow-adv" |
| 24 | + |
| 25 | +GOTO getopts |
| 26 | +:help |
| 27 | +ECHO Flash image file to device, but first erasing and writing system information. |
| 28 | +ECHO. |
| 29 | +ECHO Usage: %SCRIPT_NAME% -f filename [-p PORT] [-P python] [--1200bps-reset] |
| 30 | +ECHO. |
| 31 | +ECHO Options: |
| 32 | +ECHO -f filename The firmware .bin file to flash. Custom to your device type and region. (required) |
| 33 | +ECHO The file must be located in this current directory. |
| 34 | +ECHO -p PORT Set the environment variable for ESPTOOL_PORT. |
| 35 | +ECHO If not set, ESPTOOL iterates all ports (Dangerous). |
| 36 | +ECHO -P python Specify alternate python interpreter to use to invoke esptool. (default: python) |
| 37 | +ECHO If supplied the script will use python. |
| 38 | +ECHO If not supplied the script will try to find esptool in Path. |
| 39 | +ECHO --1200bps-reset Attempt to place the device in correct mode. (1200bps Reset) |
| 40 | +ECHO Some hardware requires this twice. |
| 41 | +ECHO. |
| 42 | +ECHO Example: %SCRIPT_NAME% -p COM17 --1200bps-reset |
| 43 | +ECHO Example: %SCRIPT_NAME% -f firmware-t-deck-tft-2.6.0.0b106d4.bin -p COM11 |
| 44 | +ECHO Example: %SCRIPT_NAME% -f firmware-unphone-2.6.0.0b106d4.bin -p COM11 |
| 45 | +GOTO eof |
| 46 | + |
| 47 | +:version |
| 48 | +ECHO %SCRIPT_NAME% [Version 2.6.2] |
| 49 | +ECHO Meshtastic |
| 50 | +GOTO eof |
| 51 | + |
| 52 | +:getopts |
| 53 | +IF "%~1"=="" GOTO endopts |
| 54 | +IF /I "%~1"=="-?" GOTO help |
| 55 | +IF /I "%~1"=="-h" GOTO help |
| 56 | +IF /I "%~1"=="--help" GOTO help |
| 57 | +IF /I "%~1"=="-v" GOTO version |
| 58 | +IF /I "%~1"=="--version" GOTO version |
| 59 | +IF /I "%~1"=="--debug" SET "DEBUG=1" & CALL :LOG_MESSAGE DEBUG "DEBUG mode: enabled." |
| 60 | +IF /I "%~1"=="-f" SET "FILENAME=%~2" & SHIFT |
| 61 | +IF "%~1"=="-p" SET "ESPTOOL_PORT=%~2" & SHIFT |
| 62 | +IF /I "%~1"=="--port" SET "ESPTOOL_PORT=%~2" & SHIFT |
| 63 | +IF "%~1"=="-P" SET "PYTHON=%~2" & SHIFT |
| 64 | +IF /I "%~1"=="--1200bps-reset" SET "BPS_RESET=1" |
| 65 | +SHIFT |
| 66 | +GOTO getopts |
| 67 | +:endopts |
| 68 | + |
| 69 | +IF %BPS_RESET% EQU 1 GOTO skip-filename |
| 70 | + |
| 71 | +CALL :LOG_MESSAGE DEBUG "Checking FILENAME parameter..." |
| 72 | +IF "__!FILENAME!__"=="____" ( |
| 73 | + CALL :LOG_MESSAGE DEBUG "Missing -f filename input." |
| 74 | + GOTO help |
| 75 | +) ELSE ( |
| 76 | + CALL :LOG_MESSAGE DEBUG "Filename: !FILENAME!" |
| 77 | + IF NOT "__!FILENAME: =!__"=="__!FILENAME!__" ( |
| 78 | + CALL :LOG_MESSAGE ERROR "Filename containing spaces are not supported." |
| 79 | + GOTO help |
| 80 | + ) |
| 81 | + IF "__!FILENAME:firmware-=!__"=="__!FILENAME!__" ( |
| 82 | + CALL :LOG_MESSAGE ERROR "Filename must be a firmware-* file." |
| 83 | + GOTO help |
| 84 | + ) |
| 85 | + @REM Remove ".\" or "./" file prefix if present. |
| 86 | + SET "FILENAME=!FILENAME:.\=!" |
| 87 | + SET "FILENAME=!FILENAME:./=!" |
| 88 | +) |
| 89 | + |
| 90 | +CALL :LOG_MESSAGE DEBUG "Checking if !FILENAME! exists..." |
| 91 | +IF NOT EXIST !FILENAME! ( |
| 92 | + CALL :LOG_MESSAGE ERROR "File does not exist: !FILENAME!. Terminating." |
| 93 | + GOTO eof |
| 94 | +) |
| 95 | + |
| 96 | +IF NOT "!FILENAME:update=!"=="!FILENAME!" ( |
| 97 | + CALL :LOG_MESSAGE DEBUG "We are working with a *update* file. !FILENAME!" |
| 98 | + CALL :LOG_MESSAGE INFO "Use script device-update.bat to flash update !FILENAME!." |
| 99 | + GOTO eof |
| 100 | +) ELSE ( |
| 101 | + CALL :LOG_MESSAGE DEBUG "We are NOT working with a *update* file. !FILENAME!" |
| 102 | +) |
| 103 | + |
| 104 | +:skip-filename |
| 105 | + |
| 106 | +CALL :LOG_MESSAGE DEBUG "Determine the correct esptool command to use..." |
| 107 | +IF NOT "__%PYTHON%__"=="____" ( |
| 108 | + SET "ESPTOOL_CMD=!PYTHON! -m esptool" |
| 109 | + CALL :LOG_MESSAGE DEBUG "Python interpreter supplied." |
| 110 | +) ELSE ( |
| 111 | + CALL :LOG_MESSAGE DEBUG "Python interpreter NOT supplied. Looking for esptool... |
| 112 | + WHERE esptool >nul 2>&1 |
| 113 | + IF %ERRORLEVEL% EQU 0 ( |
| 114 | + @REM WHERE exits with code 0 if esptool is found. |
| 115 | + SET "ESPTOOL_CMD=esptool" |
| 116 | + ) ELSE ( |
| 117 | + SET "ESPTOOL_CMD=python -m esptool" |
| 118 | + CALL :RESET_ERROR |
| 119 | + ) |
| 120 | +) |
| 121 | + |
| 122 | +CALL :LOG_MESSAGE DEBUG "Checking esptool command !ESPTOOL_CMD!..." |
| 123 | +!ESPTOOL_CMD! >nul 2>&1 |
| 124 | +IF %ERRORLEVEL% EQU 9009 ( |
| 125 | + @REM 9009 = command not found on Windows |
| 126 | + CALL :LOG_MESSAGE ERROR "esptool not found: !ESPTOOL_CMD!" |
| 127 | + EXIT /B 1 |
| 128 | +) |
| 129 | +IF %DEBUG% EQU 1 ( |
| 130 | + CALL :LOG_MESSAGE DEBUG "Skipping ESPTOOL_CMD steps." |
| 131 | + SET "ESPTOOL_CMD=REM !ESPTOOL_CMD!" |
| 132 | +) |
| 133 | + |
| 134 | +CALL :LOG_MESSAGE DEBUG "Using esptool command: !ESPTOOL_CMD!" |
| 135 | +IF "__!ESPTOOL_PORT!__" == "____" ( |
| 136 | + CALL :LOG_MESSAGE WARN "Using esptool port: UNSET." |
| 137 | +) ELSE ( |
| 138 | + SET "ESPTOOL_CMD=!ESPTOOL_CMD! --port !ESPTOOL_PORT!" |
| 139 | + CALL :LOG_MESSAGE INFO "Using esptool port: !ESPTOOL_PORT!." |
| 140 | +) |
| 141 | +CALL :LOG_MESSAGE INFO "Using esptool baud: !ESPTOOL_BAUD!." |
| 142 | + |
| 143 | +IF %BPS_RESET% EQU 1 ( |
| 144 | + @REM Attempt to change mode via 1200bps Reset. |
| 145 | + CALL :RUN_ESPTOOL 1200 --after no_reset read_flash_status |
| 146 | + GOTO eof |
| 147 | +) |
| 148 | + |
| 149 | +@REM Check if FILENAME contains "-tft-" and set target partitionScheme accordingly. |
| 150 | +@REM https://github.com/meshtastic/web-flasher/blob/main/types/resources.ts#L3 |
| 151 | +IF NOT "!FILENAME:-tft-=!"=="!FILENAME!" ( |
| 152 | + CALL :LOG_MESSAGE DEBUG "We are working with a *-tft-* file. !FILENAME!" |
| 153 | + SET "TFT_BUILD=1" |
| 154 | +) ELSE ( |
| 155 | + CALL :LOG_MESSAGE DEBUG "We are NOT working with a *-tft-* file. !FILENAME!" |
| 156 | +) |
| 157 | + |
| 158 | +FOR %%a IN (%BIGDB_8MB%) DO ( |
| 159 | + IF NOT "!FILENAME:%%a=!"=="!FILENAME!" ( |
| 160 | + @REM We are working with any of %BIGDB_8MB%. |
| 161 | + SET "BIGDB8=1" |
| 162 | + GOTO end_loop_bigdb_8mb |
| 163 | + ) |
| 164 | +) |
| 165 | +:end_loop_bigdb_8mb |
| 166 | + |
| 167 | +FOR %%a IN (%MUIDB_8MB%) DO ( |
| 168 | + IF NOT "!FILENAME:%%a=!"=="!FILENAME!" ( |
| 169 | + @REM We are working with any of %MUIDB_8MB%. |
| 170 | + SET "MUIDB8=1" |
| 171 | + GOTO end_loop_muidb_8mb |
| 172 | + ) |
| 173 | +) |
| 174 | +:end_loop_muidb_8mb |
| 175 | + |
| 176 | +FOR %%a IN (%BIGDB_16MB%) DO ( |
| 177 | + IF NOT "!FILENAME:%%a=!"=="!FILENAME!" ( |
| 178 | + @REM We are working with any of %BIGDB_16MB%. |
| 179 | + SET "BIGDB16=1" |
| 180 | + GOTO end_loop_bigdb_16mb |
| 181 | + ) |
| 182 | +) |
| 183 | +:end_loop_bigdb_16mb |
| 184 | + |
| 185 | +IF %BIGDB8% EQU 1 CALL :LOG_MESSAGE INFO "BigDB 8mb partition selected." |
| 186 | +IF %MUIDB8% EQU 1 CALL :LOG_MESSAGE INFO "MUIDB 8mb partition selected." |
| 187 | +IF %BIGDB16% EQU 1 CALL :LOG_MESSAGE INFO "BigDB 16mb partition selected." |
| 188 | + |
| 189 | +@REM Extract BASENAME from %FILENAME% for later use. |
| 190 | +SET "BASENAME=!FILENAME:firmware-=!" |
| 191 | +CALL :LOG_MESSAGE DEBUG "Computed firmware basename: !BASENAME!" |
| 192 | + |
| 193 | +@REM Account for S3 and C3 board's different OTA partition. |
| 194 | +FOR %%a IN (%S3%) DO ( |
| 195 | + IF NOT "!FILENAME:%%a=!"=="!FILENAME!" ( |
| 196 | + @REM We are working with any of %S3%. |
| 197 | + SET "OTA_FILENAME=bleota-s3.bin" |
| 198 | + GOTO :end_loop_s3 |
| 199 | + ) |
| 200 | +) |
| 201 | + |
| 202 | +FOR %%a IN (%C3%) DO ( |
| 203 | + IF NOT "!FILENAME:%%a=!"=="!FILENAME!" ( |
| 204 | + @REM We are working with any of %C3%. |
| 205 | + SET "OTA_FILENAME=bleota-c3.bin" |
| 206 | + GOTO :end_loop_c3 |
| 207 | + ) |
| 208 | +) |
| 209 | + |
| 210 | +@REM Everything else |
| 211 | +SET "OTA_FILENAME=bleota.bin" |
| 212 | +:end_loop_s3 |
| 213 | +:end_loop_c3 |
| 214 | +CALL :LOG_MESSAGE DEBUG "Set OTA_FILENAME to: !OTA_FILENAME!" |
| 215 | + |
| 216 | +@REM Set SPIFFS filename with "littlefs-" prefix. |
| 217 | +SET "SPIFFS_FILENAME=littlefs-%BASENAME%" |
| 218 | +CALL :LOG_MESSAGE DEBUG "Set SPIFFS_FILENAME to: !SPIFFS_FILENAME!" |
| 219 | + |
| 220 | +@REM Default offsets. |
| 221 | +@REM https://github.com/meshtastic/web-flasher/blob/main/stores/firmwareStore.ts#L202 |
| 222 | +SET "OTA_OFFSET=0x260000" |
| 223 | +SET "SPIFFS_OFFSET=0x300000" |
| 224 | + |
| 225 | +@REM Offsets for BigDB 8mb. |
| 226 | +IF %BIGDB8% EQU 1 ( |
| 227 | + SET "OTA_OFFSET=0x340000" |
| 228 | + SET "SPIFFS_OFFSET=0x670000" |
| 229 | +) |
| 230 | + |
| 231 | +@REM Offsets for MUIDB 8mb. |
| 232 | +IF %MUIDB8% EQU 1 ( |
| 233 | + SET "OTA_OFFSET=0x5D0000" |
| 234 | + SET "SPIFFS_OFFSET=0x670000" |
| 235 | +) |
| 236 | + |
| 237 | +@REM Offsets for BigDB 16mb. |
| 238 | +IF %BIGDB16% EQU 1 ( |
| 239 | + SET "OTA_OFFSET=0x650000" |
| 240 | + SET "SPIFFS_OFFSET=0xc90000" |
| 241 | +) |
| 242 | + |
| 243 | +CALL :LOG_MESSAGE DEBUG "Set OTA_OFFSET to: !OTA_OFFSET!" |
| 244 | +CALL :LOG_MESSAGE DEBUG "Set SPIFFS_OFFSET to: !SPIFFS_OFFSET!" |
| 245 | + |
| 246 | +@REM Ensure target files exist before flashing operations. |
| 247 | +IF NOT EXIST !FILENAME! CALL :LOG_MESSAGE ERROR "File does not exist: "!FILENAME!". Terminating." & EXIT /B 2 & GOTO eof |
| 248 | +IF NOT EXIST !OTA_FILENAME! CALL :LOG_MESSAGE ERROR "File does not exist: "!OTA_FILENAME!". Terminating." & EXIT /B 2 & GOTO eof |
| 249 | +IF NOT EXIST !SPIFFS_FILENAME! CALL :LOG_MESSAGE ERROR "File does not exist: "!SPIFFS_FILENAME!". Terminating." & EXIT /B 2 & GOTO eof |
| 250 | + |
| 251 | +@REM Flashing operations. |
| 252 | +CALL :LOG_MESSAGE INFO "Trying to flash "!FILENAME!", but first erasing and writing system information..." |
| 253 | +CALL :RUN_ESPTOOL !ESPTOOL_BAUD! erase_flash || GOTO eof |
| 254 | +CALL :RUN_ESPTOOL !ESPTOOL_BAUD! write_flash 0x00 "!FILENAME!" || GOTO eof |
| 255 | + |
| 256 | +CALL :LOG_MESSAGE INFO "Trying to flash BLEOTA "!OTA_FILENAME!" at OTA_OFFSET !OTA_OFFSET!..." |
| 257 | +CALL :RUN_ESPTOOL !ESPTOOL_BAUD! write_flash !OTA_OFFSET! "!OTA_FILENAME!" || GOTO eof |
| 258 | + |
| 259 | +CALL :LOG_MESSAGE INFO "Trying to flash SPIFFS "!SPIFFS_FILENAME!" at SPIFFS_OFFSET !SPIFFS_OFFSET!..." |
| 260 | +CALL :RUN_ESPTOOL !ESPTOOL_BAUD! write_flash !SPIFFS_OFFSET! "!SPIFFS_FILENAME!" || GOTO eof |
| 261 | + |
| 262 | +CALL :LOG_MESSAGE INFO "Script complete!." |
| 263 | + |
| 264 | +:eof |
| 265 | +ENDLOCAL |
| 266 | +EXIT /B %ERRORLEVEL% |
| 267 | + |
| 268 | + |
| 269 | +:RUN_ESPTOOL |
| 270 | +@REM Subroutine used to run ESPTOOL_CMD with arguments. |
| 271 | +@REM Also handles %ERRORLEVEL%. |
| 272 | +@REM CALL :RUN_ESPTOOL [Baud] [erase_flash|write_flash] [OFFSET] [Filename] |
| 273 | +@REM. |
| 274 | +@REM Example:: CALL :RUN_ESPTOOL 115200 write_flash 0x10000 "firmwarefile.bin" |
| 275 | +IF %DEBUG% EQU 1 CALL :LOG_MESSAGE DEBUG "About to run command: !ESPTOOL_CMD! --baud %~1 %~2 %~3 %~4" |
| 276 | +CALL :RESET_ERROR |
| 277 | +!ESPTOOL_CMD! --baud %~1 %~2 %~3 %~4 |
| 278 | +IF %BPS_RESET% EQU 1 GOTO :eof |
| 279 | +IF %ERRORLEVEL% NEQ 0 ( |
| 280 | + CALL :LOG_MESSAGE ERROR "Error running command: !ESPTOOL_CMD! --baud %~1 %~2 %~3 %~4" |
| 281 | + EXIT /B %ERRORLEVEL% |
| 282 | +) |
| 283 | +GOTO :eof |
| 284 | + |
| 285 | +:LOG_MESSAGE |
| 286 | +@REM Subroutine used to print log messages in four different levels. |
| 287 | +@REM DEBUG messages only get printed if [-d] flag is passed to script. |
| 288 | +@REM CALL :LOG_MESSAGE [ERROR|INFO|WARN|DEBUG] "Message" |
| 289 | +@REM. |
| 290 | +@REM Example:: CALL :LOG_MESSAGE INFO "Message." |
| 291 | +SET /A LOGCOUNTER=LOGCOUNTER+1 |
| 292 | +IF "%1" == "ERROR" CALL :GET_TIMESTAMP & ECHO [91m%1 [0m[37m^| !TIMESTAMP! !LOGCOUNTER! [0m[91m%~2[0m |
| 293 | +IF "%1" == "INFO" CALL :GET_TIMESTAMP & ECHO [32m%1 [0m[37m^| !TIMESTAMP! !LOGCOUNTER! [0m[32m%~2[0m |
| 294 | +IF "%1" == "WARN" CALL :GET_TIMESTAMP & ECHO [33m%1 [0m[37m^| !TIMESTAMP! !LOGCOUNTER! [0m[33m%~2[0m |
| 295 | +IF "%1" == "DEBUG" IF %DEBUG% EQU 1 CALL :GET_TIMESTAMP & ECHO [34m%1 [0m[37m^| !TIMESTAMP! !LOGCOUNTER! [0m[34m%~2[0m |
| 296 | +GOTO :eof |
| 297 | + |
| 298 | +:GET_TIMESTAMP |
| 299 | +@REM Subroutine used to set !TIMESTAMP! to HH:MM:ss. |
| 300 | +@REM CALL :GET_TIMESTAMP |
| 301 | +@REM. |
| 302 | +@REM Updates: !TIMESTAMP! |
| 303 | +FOR /F "tokens=1,2,3 delims=:,." %%a IN ("%TIME%") DO ( |
| 304 | + SET "HH=%%a" |
| 305 | + SET "MM=%%b" |
| 306 | + SET "ss=%%c" |
| 307 | +) |
| 308 | +SET "TIMESTAMP=!HH!:!MM!:!ss!" |
| 309 | +GOTO :eof |
| 310 | + |
| 311 | +:RESET_ERROR |
| 312 | +@REM Subroutine to reset %ERRORLEVEL% to 0. |
| 313 | +@REM CALL :RESET_ERROR |
| 314 | +@REM. |
| 315 | +@REM Updates: %ERRORLEVEL% |
| 316 | +EXIT /B 0 |
| 317 | +GOTO :eof |
0 commit comments