89 lines
3.4 KiB
Python
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]") |