This commit is contained in:
2026-03-07 08:51:50 +01:00
parent 4f3fbff258
commit f85143d7e5
60 changed files with 3245 additions and 1205 deletions

View File

@@ -120,6 +120,40 @@ class SerialBus:
full_frame += payload
self.send_binary(full_frame)
def send_stream(self, data: bytes, chunk_size: int = 4096, progress_callback=None):
"""Sendet einen Datenstrom in Chunks und wartet auf die Bestätigung (CRC)."""
start_time = time.time()
size = len(data)
sent_size = 0
while sent_size < size:
chunk = data[sent_size:sent_size+chunk_size]
self.connection.write(chunk)
sent_size += len(chunk)
if progress_callback:
progress_callback(sent_size, size)
if not self.wait_for_sync(SYNC_SEQ, max_time=self.timeout + 5.0):
raise TimeoutError("Timeout beim Warten auf Stream-Ende (Flash ist evtl. noch beschäftigt).")
ftype = self._read_exact(1, "Frame-Typ")[0]
if ftype == FRAME_TYPES['stream_end']:
end_time = time.time()
crc32 = struct.unpack('<I', self._read_exact(4, "CRC32"))[0]
return {
'crc32': crc32,
'duration': end_time - start_time
}
elif ftype == FRAME_TYPES['error']:
err_code_raw = self.connection.read(1)
err_code = err_code_raw[0] if err_code_raw else 0xFF
err_name = ERRORS.get(err_code, "UNKNOWN")
raise ControllerError(err_code, err_name)
else:
raise ValueError(f"Unerwarteter Frame-Typ nach Stream-Upload: 0x{ftype:02X}")
def receive_ack(self, timeout: float = None):
wait_time = timeout if timeout is not None else self.timeout
@@ -212,42 +246,46 @@ class SerialBus:
err_name = ERRORS.get(err_code, "UNKNOWN")
raise ControllerError(err_code, err_name)
def receive_stream(self, chunk_size: int = 1024):
def receive_stream(self, chunk_size: int = 1024, progress_callback=None):
"""Liest einen Datenstrom in Chunks, bis ein Fehler oder Ende-Signal kommt."""
is_stream = False
data_chunks = []
start_time = None
while True:
if not self.wait_for_sync(SYNC_SEQ):
raise TimeoutError("Timeout beim Warten auf Sync im Stream-Modus.")
ftype = self._read_exact(1, "Frame-Typ")[0]
if self.debug: console.print(f"Empfangener Frame-Typ: 0x{ftype:02X} (start: 0x{FRAME_TYPES['stream_start']:02X}, chunk: 0x{FRAME_TYPES['stream_chunk']:02X}, end: 0x{FRAME_TYPES['stream_end']:02X})")
if ftype == FRAME_TYPES['stream_start']:
is_stream = True
data_chunks = []
size = struct.unpack('<I', self._read_exact(4, "Stream-Größe"))[0]
if self.debug: console.print(f"Stream gestartet, erwartete Gesamtgröße: {size} Bytes")
start_time = time.time()
received_size = 0
while received_size < size:
chunk_length = min(chunk_size, size - received_size)
try:
chunk_data = self._read_exact(chunk_length, f"Daten-Chunk @ {received_size}/{size}")
except Exception as e:
raise IOError(f"Stream-Abbruch bei {received_size}/{size} Bytes: {e}") from e
chunk_data = self._read_exact(chunk_length, f"Daten-Chunk @ {received_size}/{size}")
data_chunks.append(chunk_data)
received_size += len(chunk_data)
if self.debug: console.print(f"Empfangen: {received_size}/{size} Bytes ({(received_size/size)*100:.2f}%)")
# Callback für UI-Update (z.B. Progress Bar)
if progress_callback:
progress_callback(received_size, size)
if self.debug: console.print("Stream vollständig empfangen.")
elif ftype == FRAME_TYPES['stream_end']:
end_time = time.time()
if not is_stream: raise ValueError("Ende ohne Start.")
crc32 = struct.unpack('<I', self._read_exact(4, "CRC32"))[0]
if self.debug: console.print(f"Stream-Ende empfangen, CRC32: 0x{crc32:08X}")
return {'data': b''.join(data_chunks), 'crc32': crc32}
return {
'data': b''.join(data_chunks),
'crc32': crc32,
'duration': end_time - start_time if start_time and end_time else None
}
# elif ftype == FRAME_TYPES['list_chunk']:
# if not is_list: raise ValueError("Chunk ohne Start.")