Files
buzzer/tool/core/cmd/put_fw.py
2026-03-07 08:51:50 +01:00

89 lines
3.4 KiB
Python

import struct
import zlib
from pathlib import Path
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, DownloadColumn, TransferSpeedColumn, TimeRemainingColumn
from core.utils import console, console_err
from core.protocol import COMMANDS
class put_fw:
def __init__(self, bus):
self.bus = bus
def get(self, file_path: str):
try:
p = Path(file_path)
if not p.exists() or not p.is_file():
console_err.print(f"Fehler: Firmware-Datei existiert nicht: {file_path}")
return None
file_size = p.stat().st_size
with open(p, 'rb') as f:
file_data = f.read()
except Exception as e:
console_err.print(f"Lese-Fehler: {e}")
return None
# 1. Schritt: Löschvorgang mit minimalem Feedback
with Progress(
SpinnerColumn(),
TextColumn("[progress.description]{task.description}"),
BarColumn(),
console=console,
transient=True
) as progress:
erase_task = progress.add_task("Lösche Firmware Slot...", total=None)
payload = struct.pack('<I', file_size)
self.bus.send_request(COMMANDS['put_fw'], payload)
# Warten auf ACK (Balken pulsiert ohne Byte-Anzeige)
self.bus.receive_ack(timeout=10.0)
progress.update(erase_task, description="✓ Slot gelöscht", completed=100, total=100)
# 2. Schritt: Eigentlicher Transfer mit allen Metriken (Bytes, Speed, Time)
with Progress(
SpinnerColumn(),
TextColumn("[progress.description]{task.description}"),
BarColumn(),
DownloadColumn(),
TransferSpeedColumn(),
"",
TimeRemainingColumn(),
console=console,
transient=False
) as progress:
transfer_task = progress.add_task("Sende Firmware...", total=file_size)
stream_res = self.bus.send_stream(
file_data,
progress_callback=lambda sent, total: progress.update(transfer_task, total=total, completed=sent)
)
if not stream_res:
return None
remote_crc = stream_res.get('crc32')
local_crc = zlib.crc32(file_data) & 0xFFFFFFFF
return {
'success': local_crc == remote_crc,
'source_path': file_path,
'crc32_remote': remote_crc,
'crc32_local': local_crc,
'size': file_size,
'duration': stream_res.get('duration')
}
def print(self, result):
if not result:
return
if result['success']:
console.print(f"✓ Firmware [info]{result['source_path']}[/info] erfolgreich in Slot 1 geschrieben.")
console.print(" [warning]Achtung:[/warning] Das Image ist als 'Pending' markiert. Führe 'reboot' aus, um das Update zu installieren.")
else:
console_err.print(f"❌ CRC-FEHLER: Die Firmware wurde korrumpiert übertragen!")
console.print(f" • Größe: [info]{result['size'] / 1024:.2f} KB[/info]")
console.print(f" • Remote CRC: [info]{result['crc32_remote']:08X}[/info]")
console.print(f" • Local CRC: [info]{result['crc32_local']:08X}[/info]")