This commit is contained in:
2026-02-25 11:32:55 +01:00
parent f2ec804aab
commit fa58fe5f20
3 changed files with 102 additions and 84 deletions

View File

@@ -1,7 +1,8 @@
# core/commands/put.py
import os
import zlib
import glob
import time
import sys
from core.connection import BuzzerError
def get_file_crc32(filepath: str) -> int:
@@ -13,55 +14,66 @@ def get_file_crc32(filepath: str) -> int:
return crc & 0xFFFFFFFF
def execute(conn, sources: list, target: str):
"""
Lädt Dateien auf den Mikrocontroller hoch.
"""
# 1. Globbing auflösen (Notwendig für Windows, da die CMD Wildcards nicht auflöst)
resolved_files = []
for src in sources:
matches = glob.glob(src)
if matches:
resolved_files.extend(matches)
else:
print(f"Warnung: Datei '{src}' nicht gefunden.")
# 1. Globbing auflösen
resolved_files = [f for src in sources for f in glob.glob(src) if os.path.isfile(f)]
if not resolved_files:
print("Keine gültigen Dateien zum Übertragen gefunden.")
print("Keine gültigen Dateien gefunden.")
return
total_size_all = sum(os.path.getsize(f) for f in resolved_files)
sent_all = 0
start_time_all = time.monotonic()
is_target_dir = target.endswith('/')
# Wenn mehrere Dateien angegeben sind, muss das Ziel zwingend ein Verzeichnis sein
if len(resolved_files) > 1 and not is_target_dir:
print("Fehler: Bei mehreren Quelldateien muss das Ziel ein Verzeichnis sein (mit '/' enden).")
return
# 2. Transfer-Schleife
for filepath in resolved_files:
if not os.path.isfile(filepath):
print(f"Überspringe '{filepath}' (ist keine Datei)")
continue
filename = os.path.basename(filepath)
filesize = os.path.getsize(filepath)
crc32 = get_file_crc32(filepath)
dest_path = f"{target}{filename}" if is_target_dir else target
size_kb = filesize / 1024
print(f"Sende 📄 {filename} \033[90m({size_kb:.1f} KB)\033[0m nach {dest_path} ... ", end="", flush=True)
print(f"Sende 📄 {filename} ({filesize/1024:.1f} KB) -> {dest_path}")
start_time_file = time.monotonic()
sent_file = 0
def progress_handler(chunk_len):
nonlocal sent_file, sent_all
sent_file += chunk_len
sent_all += chunk_len
elapsed = time.monotonic() - start_time_file
speed = (sent_file / 1024) / elapsed if elapsed > 0 else 0
# Prozentberechnungen
perc_file = (sent_file / filesize) * 100
perc_all = (sent_all / total_size_all) * 100
# ETA (Basierend auf Gesamtgeschwindigkeit)
elapsed_all = time.monotonic() - start_time_all
avg_speed_all = sent_all / elapsed_all if elapsed_all > 0 else 0
eta_sec = (total_size_all - sent_all) / avg_speed_all if avg_speed_all > 0 else 0
eta_str = f"{int(eta_sec // 60):02d}:{int(eta_sec % 60):02d}"
# Ausgabezeile (\r überschreibt die aktuelle Zeile)
sys.stdout.write(
f"\r \033[90mProg: {perc_file:3.0f}% | Gesamt: {perc_all:3.0f}% | "
f"{speed:6.1f} KB/s | ETA: {eta_str}\033[0m"
)
sys.stdout.flush()
try:
# PUT-Befehl ohne Warten auf 'OK' senden
cmd = f"put {dest_path};{filesize};{crc32}\n"
conn.serial.write(cmd.encode('utf-8'))
conn.serial.flush()
# Warten auf READY, Binärdaten senden und auf abschließendes OK warten
conn.send_binary(filepath)
# Binärtransfer mit unserem Handler
conn.send_binary(filepath, progress_callback=progress_handler)
print("\033[32mErfolgreich\033[0m")
except BuzzerError as e:
print(f"\n\033[31mFehler vom Controller: {e}\033[0m")
# Zeile nach Erfolg abschließen
print(f"\r \033[32mFertig: {filename} übertragen. \033[0m")
except Exception as e:
print(f"\n\033[31mÜbertragungsfehler: {e}\033[0m")
print(f"\n\033[31mFehler: {e}\033[0m")
total_duration = time.monotonic() - start_time_all
print(f"\nAlle {len(resolved_files)} Dateien in {total_duration:.1f}s übertragen.")