update flasher
This commit is contained in:
@@ -21,8 +21,9 @@
|
|||||||
"Bash(pkill:*)",
|
"Bash(pkill:*)",
|
||||||
"Bash(curl -s http://127.0.0.1:5000/)",
|
"Bash(curl -s http://127.0.0.1:5000/)",
|
||||||
"Bash(./build_web_macos.sh:*)",
|
"Bash(./build_web_macos.sh:*)",
|
||||||
"Bash(./dist/ESP32_Flasher.app/Contents/MacOS/ESP32_Flasher:*)"
|
"Bash(./dist/ESP32_Flasher.app/Contents/MacOS/ESP32_Flasher:*)",
|
||||||
|
"Bash(where:*)"
|
||||||
],
|
],
|
||||||
"deny": []
|
"deny": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
17
.vscode/c_cpp_properties.json
vendored
17
.vscode/c_cpp_properties.json
vendored
@@ -1,5 +1,22 @@
|
|||||||
{
|
{
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Win32",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**",
|
||||||
|
"${env:USERPROFILE}/esp/v5.4.1/esp-idf/components/**",
|
||||||
|
"${env:USERPROFILE}/.espressif/tools/xtensa-esp-elf/**",
|
||||||
|
"${workspaceFolder}/build/config",
|
||||||
|
"${workspaceFolder}/managed_components/**"
|
||||||
|
],
|
||||||
|
"defines": [
|
||||||
|
"ESP_PLATFORM"
|
||||||
|
],
|
||||||
|
"compilerPath": "${env:USERPROFILE}/.espressif/tools/xtensa-esp-elf/esp-13.2.0_20241113/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc.exe",
|
||||||
|
"cStandard": "c11",
|
||||||
|
"cppStandard": "c++20",
|
||||||
|
"intelliSenseMode": "gcc-x64"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Mac",
|
"name": "Mac",
|
||||||
"includePath": [
|
"includePath": [
|
||||||
|
|||||||
50
.vscode/launch.json
vendored
Normal file
50
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Build ESP32 Firmware (Windows)",
|
||||||
|
"type": "process",
|
||||||
|
"request": "launch",
|
||||||
|
"command": "idf.py",
|
||||||
|
"args": ["build"],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"windows": {
|
||||||
|
"command": "idf.py"
|
||||||
|
},
|
||||||
|
"problemMatcher": ["$gcc"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Build ESP32 Firmware (macOS)",
|
||||||
|
"type": "process",
|
||||||
|
"request": "launch",
|
||||||
|
"command": "bash",
|
||||||
|
"args": ["-lc", "source ${IDF_PATH:-/opt/esp/idf}/export.sh && idf.py build"],
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"osx": {
|
||||||
|
"command": "bash"
|
||||||
|
},
|
||||||
|
"problemMatcher": ["$gcc"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Build Windows Flasher",
|
||||||
|
"type": "process",
|
||||||
|
"request": "launch",
|
||||||
|
"command": "${workspaceFolder}/flash_tool/build_from_spec.bat",
|
||||||
|
"cwd": "${workspaceFolder}/flash_tool",
|
||||||
|
"windows": {
|
||||||
|
"command": "${workspaceFolder}/flash_tool/build_from_spec.bat"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Build macOS Flasher",
|
||||||
|
"type": "process",
|
||||||
|
"request": "launch",
|
||||||
|
"command": "${workspaceFolder}/flash_tool/build_macos.sh",
|
||||||
|
"cwd": "${workspaceFolder}/flash_tool",
|
||||||
|
"osx": {
|
||||||
|
"command": "bash",
|
||||||
|
"args": ["${workspaceFolder}/flash_tool/build_macos.sh"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"C_Cpp.intelliSenseEngine": "default",
|
"C_Cpp.intelliSenseEngine": "default",
|
||||||
"idf.espIdfPathWin": "C:\\esp\\frameworks\\esp-idf-v5.3.3",
|
"idf.espIdfPathWin": "C:\\Users\\Brent.Perteet\\esp\\v5.4.1\\esp-idf",
|
||||||
"idf.openOcdConfigs": [
|
"idf.openOcdConfigs": [
|
||||||
"board/esp32-wrover-kit-3.3v.cfg"
|
"board/esp32-wrover-kit-3.3v.cfg"
|
||||||
],
|
],
|
||||||
"idf.portWin": "COM4",
|
"idf.portWin": "COM4",
|
||||||
"idf.toolsPathWin": "C:\\esp\\frameworks\\esp-idf-v5.3.3\\tools\\tools",
|
"idf.toolsPathWin": "C:\\Users\\Brent.Perteet\\.espressif",
|
||||||
"idf.flashType": "UART",
|
"idf.flashType": "UART",
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"esp_system.h": "c",
|
"esp_system.h": "c",
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
"random": "c"
|
"random": "c"
|
||||||
},
|
},
|
||||||
"git.ignoreLimitWarning": true,
|
"git.ignoreLimitWarning": true,
|
||||||
"idf.pythonInstallPath": "/opt/homebrew/bin/python3",
|
"idf.pythonInstallPath": "C:\\Users\\Brent.Perteet\\.espressif\\tools\\idf-python\\3.11.2\\python.exe",
|
||||||
"idf.espIdfPath": "/Users/brent/esp/v5.5.1/esp-idf",
|
"idf.espIdfPath": "/Users/brent/esp/v5.5.1/esp-idf",
|
||||||
"idf.toolsPath": "/Users/brent/.espressif"
|
"idf.toolsPath": "/Users/brent/.espressif"
|
||||||
}
|
}
|
||||||
|
|||||||
26
.vscode/tasks.json
vendored
26
.vscode/tasks.json
vendored
@@ -1,11 +1,35 @@
|
|||||||
{
|
{
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "adapter",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "idf.py",
|
||||||
|
"args": ["build"],
|
||||||
|
"windows": {
|
||||||
|
"command": "cmd.exe",
|
||||||
|
"args": ["/c", "${env:USERPROFILE}\\esp\\v5.4.1\\esp-idf\\export.bat", "&&", "idf.py", "build"]
|
||||||
|
},
|
||||||
|
"osx": {
|
||||||
|
"command": "bash",
|
||||||
|
"args": ["-lc", "source ${IDF_PATH:-/opt/esp/idf}/export.sh && idf.py build"]
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"command": "bash",
|
||||||
|
"args": ["-lc", "source ${IDF_PATH:-/opt/esp/idf}/export.sh && idf.py build"]
|
||||||
|
},
|
||||||
|
"group": { "kind": "build", "isDefault": true },
|
||||||
|
"problemMatcher": ["${config:idf.cmakeCompilerArgs}"],
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "dedicated"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "ESP-IDF: Build (RAM) + Sync to Host",
|
"label": "ESP-IDF: Build (RAM) + Sync to Host",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "bash -lc 'source ${IDF_PATH:-/opt/esp/idf}/export.sh && idf.py build && rsync -a --delete \"$PWD/build/\" /host_build/'",
|
"command": "bash -lc 'source ${IDF_PATH:-/opt/esp/idf}/export.sh && idf.py build && rsync -a --delete \"$PWD/build/\" /host_build/'",
|
||||||
"group": { "kind": "build", "isDefault": true },
|
"group": "build",
|
||||||
"problemMatcher": "$gcc"
|
"problemMatcher": "$gcc"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
32
flash_tool/build_web_windows.bat
Normal file
32
flash_tool/build_web_windows.bat
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
@echo off
|
||||||
|
echo === ESP32 Flasher (Web UI) - Windows Build Script ===
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM Check if running on Windows
|
||||||
|
if not "%OS%"=="Windows_NT" (
|
||||||
|
echo Error: This script is for Windows only.
|
||||||
|
echo Use build_web_macos.sh on macOS.
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Installing dependencies...
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Building Windows executable...
|
||||||
|
pyinstaller ESP32_WebFlasher_Windows.spec
|
||||||
|
|
||||||
|
echo.
|
||||||
|
if exist "dist\ESP32_Flasher.exe" (
|
||||||
|
echo Build complete!
|
||||||
|
echo.
|
||||||
|
echo Executable created at: dist\ESP32_Flasher.exe
|
||||||
|
echo.
|
||||||
|
echo The app will open in your default web browser!
|
||||||
|
echo You can now distribute ESP32_Flasher.exe to users.
|
||||||
|
) else (
|
||||||
|
echo Build failed - executable not found in dist folder
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
pause
|
||||||
@@ -136,6 +136,28 @@
|
|||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.output-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output-toggle {
|
||||||
|
background: #f0f0f0;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #333;
|
||||||
|
transition: background 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output-toggle:hover {
|
||||||
|
background: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
.output-box {
|
.output-box {
|
||||||
background: #1e1e1e;
|
background: #1e1e1e;
|
||||||
color: #d4d4d4;
|
color: #d4d4d4;
|
||||||
@@ -148,6 +170,11 @@
|
|||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output-box.expanded {
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.output-box:empty::before {
|
.output-box:empty::before {
|
||||||
@@ -173,6 +200,10 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
background: linear-gradient(90deg, #667eea, #764ba2);
|
background: linear-gradient(90deg, #667eea, #764ba2);
|
||||||
width: 0%;
|
width: 0%;
|
||||||
|
transition: width 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar-fill.indeterminate {
|
||||||
animation: progress 2s ease-in-out infinite;
|
animation: progress 2s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,6 +213,19 @@
|
|||||||
100% { width: 0%; }
|
100% { width: 0%; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.progress-text {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #667eea;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-top: 5px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-text.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.status-message {
|
.status-message {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -270,14 +314,18 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div class="progress-bar" id="progressBar">
|
<div class="progress-bar" id="progressBar">
|
||||||
<div class="progress-bar-fill"></div>
|
<div class="progress-bar-fill" id="progressBarFill"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="progress-text" id="progressText">0%</div>
|
||||||
|
|
||||||
<div class="status-message" id="statusMessage"></div>
|
<div class="status-message" id="statusMessage"></div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="output-section">
|
<div class="output-section">
|
||||||
<label>Output Log</label>
|
<div class="output-header">
|
||||||
|
<label>Output Log</label>
|
||||||
|
<button type="button" class="output-toggle" id="outputToggle" onclick="toggleOutput()">▼ Show Details</button>
|
||||||
|
</div>
|
||||||
<div class="output-box" id="output"></div>
|
<div class="output-box" id="output"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -287,6 +335,20 @@
|
|||||||
let socket = null;
|
let socket = null;
|
||||||
let heartbeatInterval = null;
|
let heartbeatInterval = null;
|
||||||
|
|
||||||
|
// Toggle output visibility
|
||||||
|
function toggleOutput() {
|
||||||
|
const output = document.getElementById('output');
|
||||||
|
const toggle = document.getElementById('outputToggle');
|
||||||
|
|
||||||
|
if (output.classList.contains('expanded')) {
|
||||||
|
output.classList.remove('expanded');
|
||||||
|
toggle.textContent = '▼ Show Details';
|
||||||
|
} else {
|
||||||
|
output.classList.add('expanded');
|
||||||
|
toggle.textContent = '▲ Hide Details';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize Socket.IO connection
|
// Initialize Socket.IO connection
|
||||||
function initWebSocket() {
|
function initWebSocket() {
|
||||||
socket = io();
|
socket = io();
|
||||||
@@ -368,14 +430,23 @@
|
|||||||
|
|
||||||
const flashBtn = document.getElementById('flashBtn');
|
const flashBtn = document.getElementById('flashBtn');
|
||||||
const progressBar = document.getElementById('progressBar');
|
const progressBar = document.getElementById('progressBar');
|
||||||
|
const progressBarFill = document.getElementById('progressBarFill');
|
||||||
|
const progressText = document.getElementById('progressText');
|
||||||
const output = document.getElementById('output');
|
const output = document.getElementById('output');
|
||||||
|
const outputToggle = document.getElementById('outputToggle');
|
||||||
const statusMessage = document.getElementById('statusMessage');
|
const statusMessage = document.getElementById('statusMessage');
|
||||||
|
|
||||||
// Disable form
|
// Disable form
|
||||||
flashBtn.disabled = true;
|
flashBtn.disabled = true;
|
||||||
flashBtn.textContent = '⚡ Flashing...';
|
flashBtn.textContent = '⚡ Flashing...';
|
||||||
progressBar.classList.add('active');
|
progressBar.classList.add('active');
|
||||||
|
progressBarFill.classList.add('indeterminate');
|
||||||
|
progressBarFill.style.width = '0%';
|
||||||
|
progressText.classList.add('active');
|
||||||
|
progressText.textContent = '0%';
|
||||||
output.textContent = '';
|
output.textContent = '';
|
||||||
|
output.classList.remove('expanded');
|
||||||
|
outputToggle.textContent = '▼ Show Details';
|
||||||
statusMessage.style.display = 'none';
|
statusMessage.style.display = 'none';
|
||||||
statusMessage.className = 'status-message';
|
statusMessage.className = 'status-message';
|
||||||
|
|
||||||
@@ -413,6 +484,16 @@
|
|||||||
output.textContent = data.output.join('\n');
|
output.textContent = data.output.join('\n');
|
||||||
output.scrollTop = output.scrollHeight;
|
output.scrollTop = output.scrollHeight;
|
||||||
|
|
||||||
|
// Update progress bar
|
||||||
|
const progressBarFill = document.getElementById('progressBarFill');
|
||||||
|
const progressText = document.getElementById('progressText');
|
||||||
|
if (data.progress !== undefined && data.progress > 0) {
|
||||||
|
// Switch from indeterminate to determinate
|
||||||
|
progressBarFill.classList.remove('indeterminate');
|
||||||
|
progressBarFill.style.width = data.progress + '%';
|
||||||
|
progressText.textContent = data.progress.toFixed(1) + '%';
|
||||||
|
}
|
||||||
|
|
||||||
// Check if complete
|
// Check if complete
|
||||||
if (!data.running && statusCheckInterval) {
|
if (!data.running && statusCheckInterval) {
|
||||||
clearInterval(statusCheckInterval);
|
clearInterval(statusCheckInterval);
|
||||||
@@ -420,11 +501,15 @@
|
|||||||
|
|
||||||
const statusMessage = document.getElementById('statusMessage');
|
const statusMessage = document.getElementById('statusMessage');
|
||||||
if (data.success === true) {
|
if (data.success === true) {
|
||||||
statusMessage.textContent = '✓ Firmware flashed successfully!';
|
progressBarFill.style.width = '100%';
|
||||||
|
progressText.textContent = '100%';
|
||||||
|
statusMessage.textContent = '✓ Flash completed successfully!';
|
||||||
statusMessage.className = 'status-message success';
|
statusMessage.className = 'status-message success';
|
||||||
|
statusMessage.style.display = 'block';
|
||||||
} else if (data.success === false) {
|
} else if (data.success === false) {
|
||||||
statusMessage.textContent = '✗ Flash operation failed. Check the output log for details.';
|
statusMessage.textContent = '✗ Flash operation failed. Check the output log for details.';
|
||||||
statusMessage.className = 'status-message error';
|
statusMessage.className = 'status-message error';
|
||||||
|
statusMessage.style.display = 'block';
|
||||||
}
|
}
|
||||||
|
|
||||||
resetForm();
|
resetForm();
|
||||||
@@ -441,15 +526,25 @@
|
|||||||
const statusMessage = document.getElementById('statusMessage');
|
const statusMessage = document.getElementById('statusMessage');
|
||||||
statusMessage.textContent = '✗ ' + message;
|
statusMessage.textContent = '✗ ' + message;
|
||||||
statusMessage.className = 'status-message error';
|
statusMessage.className = 'status-message error';
|
||||||
|
statusMessage.style.display = 'block';
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetForm() {
|
function resetForm() {
|
||||||
const flashBtn = document.getElementById('flashBtn');
|
const flashBtn = document.getElementById('flashBtn');
|
||||||
const progressBar = document.getElementById('progressBar');
|
const progressBar = document.getElementById('progressBar');
|
||||||
|
const progressBarFill = document.getElementById('progressBarFill');
|
||||||
|
const progressText = document.getElementById('progressText');
|
||||||
|
|
||||||
flashBtn.disabled = false;
|
flashBtn.disabled = false;
|
||||||
flashBtn.textContent = '⚡ Flash Firmware';
|
flashBtn.textContent = '⚡ Flash Firmware';
|
||||||
progressBar.classList.remove('active');
|
|
||||||
|
// Delay hiding progress to let user see completion
|
||||||
|
setTimeout(() => {
|
||||||
|
progressBar.classList.remove('active');
|
||||||
|
progressText.classList.remove('active');
|
||||||
|
progressBarFill.classList.remove('indeterminate');
|
||||||
|
progressBarFill.style.width = '0%';
|
||||||
|
}, 2000);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ socketio = SocketIO(app, cors_allowed_origins="*")
|
|||||||
flash_status = {
|
flash_status = {
|
||||||
'running': False,
|
'running': False,
|
||||||
'output': [],
|
'output': [],
|
||||||
'success': None
|
'success': None,
|
||||||
|
'progress': 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# Client connection tracking
|
# Client connection tracking
|
||||||
@@ -96,7 +97,7 @@ def flash_firmware():
|
|||||||
zip_file.extractall(temp_dir)
|
zip_file.extractall(temp_dir)
|
||||||
|
|
||||||
# Start flash in background thread
|
# Start flash in background thread
|
||||||
flash_status = {'running': True, 'output': [], 'success': None}
|
flash_status = {'running': True, 'output': [], 'success': None, 'progress': 0}
|
||||||
thread = threading.Thread(
|
thread = threading.Thread(
|
||||||
target=flash_worker,
|
target=flash_worker,
|
||||||
args=(temp_dir, port, chip, baud, flash_mode, flash_freq, flash_size)
|
args=(temp_dir, port, chip, baud, flash_mode, flash_freq, flash_size)
|
||||||
@@ -169,6 +170,7 @@ def shutdown_server():
|
|||||||
def flash_worker(temp_dir, port, chip, baud, flash_mode, flash_freq, flash_size):
|
def flash_worker(temp_dir, port, chip, baud, flash_mode, flash_freq, flash_size):
|
||||||
"""Background worker for flashing firmware"""
|
"""Background worker for flashing firmware"""
|
||||||
global flash_status
|
global flash_status
|
||||||
|
import re
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Define file paths
|
# Define file paths
|
||||||
@@ -217,9 +219,24 @@ def flash_worker(temp_dir, port, chip, baud, flash_mode, flash_freq, flash_size)
|
|||||||
universal_newlines=True
|
universal_newlines=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Regex to parse progress lines
|
||||||
|
# Example: "Writing at 0x0011325c... (85 %)"
|
||||||
|
# or "Writing at 0x0011325c [========================> ] 85.3% 622592/730050 bytes..."
|
||||||
|
progress_pattern = re.compile(r'(\d+(?:\.\d+)?)\s*%')
|
||||||
|
|
||||||
# Stream output
|
# Stream output
|
||||||
for line in process.stdout:
|
for line in process.stdout:
|
||||||
flash_status['output'].append(line.rstrip())
|
line_stripped = line.rstrip()
|
||||||
|
flash_status['output'].append(line_stripped)
|
||||||
|
|
||||||
|
# Try to extract progress percentage
|
||||||
|
match = progress_pattern.search(line_stripped)
|
||||||
|
if match:
|
||||||
|
try:
|
||||||
|
percent = float(match.group(1))
|
||||||
|
flash_status['progress'] = percent
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
process.wait()
|
process.wait()
|
||||||
|
|
||||||
@@ -227,6 +244,7 @@ def flash_worker(temp_dir, port, chip, baud, flash_mode, flash_freq, flash_size)
|
|||||||
flash_status['output'].append("")
|
flash_status['output'].append("")
|
||||||
flash_status['output'].append("✓ Flash completed successfully!")
|
flash_status['output'].append("✓ Flash completed successfully!")
|
||||||
flash_status['success'] = True
|
flash_status['success'] = True
|
||||||
|
flash_status['progress'] = 100
|
||||||
else:
|
else:
|
||||||
flash_status['output'].append("")
|
flash_status['output'].append("")
|
||||||
flash_status['output'].append(f"✗ Flash failed with return code {process.returncode}")
|
flash_status['output'].append(f"✗ Flash failed with return code {process.returncode}")
|
||||||
|
|||||||
Reference in New Issue
Block a user