From dc3467ac0f1013c65cd0b0636279e06eb6fb85e9 Mon Sep 17 00:00:00 2001 From: Eduard Iten Date: Fri, 27 Feb 2026 17:07:07 +0100 Subject: [PATCH] sync --- buzzer_tool/core/commands/info.py | 4 +- buzzer_tool/core/connection.py | 41 +++++++- firmware/src/fs.c | 29 +++++- firmware/src/main.c | 3 +- firmware/src/protocol.c | 162 ++++++++++++++++++++++-------- firmware/src/protocol.h | 23 +++++ 6 files changed, 206 insertions(+), 56 deletions(-) diff --git a/buzzer_tool/core/commands/info.py b/buzzer_tool/core/commands/info.py index f65890c..f925d6f 100644 --- a/buzzer_tool/core/commands/info.py +++ b/buzzer_tool/core/commands/info.py @@ -13,8 +13,8 @@ def execute(conn) -> dict: raise BuzzerError(f"Unerwartetes Info-Format: {lines[0]}") protocol_version = int(parts[0]) - if protocol_version != 1: - raise BuzzerError(f"Inkompatibles Protokoll: Gerät nutzt v{protocol_version}, Host erwartet v1.") + if protocol_version != 2: + raise BuzzerError(f"Inkompatibles Protokoll: Gerät nutzt v{protocol_version}, Host erwartet v2.") app_version = parts[1] f_frsize = int(parts[2]) diff --git a/buzzer_tool/core/connection.py b/buzzer_tool/core/connection.py index 32818d8..3ffc416 100644 --- a/buzzer_tool/core/connection.py +++ b/buzzer_tool/core/connection.py @@ -3,6 +3,26 @@ import serial import time import os +PROTOCOL_ERROR_MESSAGES = { + 0x01: "Ungültiger Befehl.", + 0x02: "Ungültige Parameter.", + 0x03: "Befehl oder Parameter sind zu lang.", + 0x10: "Datei oder Verzeichnis wurde nicht gefunden.", + 0x11: "Ziel existiert bereits.", + 0x12: "Pfad ist kein Verzeichnis.", + 0x13: "Pfad ist ein Verzeichnis.", + 0x14: "Zugriff verweigert.", + 0x15: "Kein freier Speicher mehr vorhanden.", + 0x16: "Datei ist zu groß.", + 0x20: "Allgemeiner Ein-/Ausgabefehler auf dem Gerät.", + 0x21: "Zeitüberschreitung auf dem Gerät.", + 0x22: "CRC-Prüfung fehlgeschlagen (Daten beschädigt).", + 0x23: "Übertragung wurde vom Gerät abgebrochen.", + 0x30: "Befehl wird vom Gerät nicht unterstützt.", + 0x31: "Gerät ist beschäftigt.", + 0x32: "Interner Gerätefehler.", +} + class BuzzerError(Exception): pass @@ -31,6 +51,16 @@ class BuzzerConnection: if self.serial and self.serial.is_open: self.serial.close() + def _parse_controller_error(self, line: str) -> str: + code_str = line.split(" ", 1)[1].strip() if " " in line else "" + try: + code = int(code_str, 10) + except ValueError: + return f"Controller meldet einen unbekannten Fehler: '{line}'" + + message = PROTOCOL_ERROR_MESSAGES.get(code, "Unbekannter Fehlercode vom Gerät.") + return f"Controller-Fehler {code} (0x{code:02X}): {message}" + def send_command(self, command: str, custom_timeout: float = None) -> list: eff_timeout = custom_timeout if custom_timeout is not None else self.timeout self.serial.reset_input_buffer() @@ -53,10 +83,11 @@ class BuzzerConnection: if line == "OK": return lines elif line.startswith("ERR"): - err_code = line.split(" ")[1] if " " in line else "UNKNOWN" - raise BuzzerError(f"Controller meldet Fehlercode: {err_code}") + raise BuzzerError(self._parse_controller_error(line)) else: lines.append(line) + except BuzzerError: + raise except Exception as e: raise BuzzerError(f"Fehler beim Lesen der Antwort: {e}") else: @@ -78,7 +109,7 @@ class BuzzerConnection: ready = True break elif line.startswith("ERR"): - raise BuzzerError(f"Fehler vor Binärtransfer: {line}") + raise BuzzerError(f"Fehler vor Binärtransfer: {self._parse_controller_error(line)}") time.sleep(0.01) if not ready: @@ -94,7 +125,7 @@ class BuzzerConnection: if self.serial.in_waiting > 0: line = self.serial.readline().decode('utf-8', errors='ignore').strip() if line.startswith("ERR"): - raise BuzzerError(f"Controller hat Transfer abgebrochen: {line}") + raise BuzzerError(f"Controller hat Transfer abgebrochen: {self._parse_controller_error(line)}") # 2. Chunk lesen und schreiben chunk = f.read(chunk_size) @@ -119,7 +150,7 @@ class BuzzerConnection: if line == "OK": return True elif line.startswith("ERR"): - raise BuzzerError(f"Fehler beim Speichern der Binärdatei: {line}") + raise BuzzerError(f"Fehler beim Speichern der Binärdatei: {self._parse_controller_error(line)}") time.sleep(0.01) raise TimeoutError("Zeitüberschreitung nach Binärtransfer (kein OK empfangen).") \ No newline at end of file diff --git a/firmware/src/fs.c b/firmware/src/fs.c index e66e7c6..6d9943e 100644 --- a/firmware/src/fs.c +++ b/firmware/src/fs.c @@ -176,14 +176,37 @@ int flash_get_slot_info(slot_info_t *info) { } int flash_init_firmware_upload(void) { + const struct flash_area *fa; int rc; - rc = flash_img_init_id(&flash_ctx, SLOT1_ID); + rc = flash_area_open(SLOT1_ID, &fa); if (rc != 0) { - printk("Error initializing flash image: %d\n", rc); return rc; } - return 0; + + LOG_INF("Erasing secondary slot (size: %zu)...", fa->fa_size); + rc = flash_area_erase(fa, 0, fa->fa_size); + + flash_area_close(fa); + + if (rc != 0) { + LOG_ERR("Failed to erase flash area: %d", rc); + return rc; + } + + rc = flash_img_init_id(&flash_ctx, SLOT1_ID); + + if (rc != 0) + { + LOG_ERR("Failed to initialize flash image context: %d", rc); + return rc; + } + else + { + LOG_INF("Flash image context initialized for slot 1 with size %zu", flash_ctx.flash_area->fa_size); + } + + return rc; } int flash_write_firmware_block(const uint8_t *buffer, size_t length, bool is_last_block) { diff --git a/firmware/src/main.c b/firmware/src/main.c index fbbe2cc..1d80614 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -75,8 +75,7 @@ int main(void) } else if (reboot_code == REBOOT_STATUS_FIRMWARE_CONFIRMED) { - LOG_INF("Firmware was just confirmed in the last reboot. Playing confirmation sound."); - audio_play("/lfs/sys/confirm"); + LOG_INF("Firmware was just confirmed in the last reboot."); } else { diff --git a/firmware/src/protocol.c b/firmware/src/protocol.c index aaec0c0..3c3865e 100644 --- a/firmware/src/protocol.c +++ b/firmware/src/protocol.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -12,7 +13,7 @@ #include #include -#define PROTOCOL_VERSION 1 +#define PROTOCOL_VERSION 2 LOG_MODULE_REGISTER(protocol, LOG_LEVEL_INF); @@ -33,7 +34,57 @@ void send_ok() usb_write_buffer((const uint8_t *)response, strlen(response)); } -void send_error(int32_t error_code) +static protocol_error_t protocol_map_error(int32_t rc) +{ + if (rc == 0) + { + return P_ERR_NONE; + } + + int32_t err = rc < 0 ? -rc : rc; + + switch (err) + { + case ENOENT: + return P_ERR_FILE_NOT_FOUND; + case EEXIST: + return P_ERR_ALREADY_EXISTS; + case ENOTDIR: + return P_ERR_NOT_A_DIRECTORY; + case EISDIR: + return P_ERR_IS_A_DIRECTORY; + case EACCES: + case EPERM: + return P_ERR_ACCESS_DENIED; + case ENOSPC: + return P_ERR_NO_SPACE; + case EFBIG: + return P_ERR_FILE_TOO_LARGE; + case ETIMEDOUT: + return P_ERR_TIMEOUT; + case EMSGSIZE: + return P_ERR_COMMAND_TOO_LONG; + case EINVAL: + return P_ERR_INVALID_PARAMETERS; + case EILSEQ: + return P_ERR_INVALID_COMMAND; + case ECANCELED: + return P_ERR_TRANSFER_ABORTED; + case ENOSYS: + case ENOTSUP: + return P_ERR_NOT_SUPPORTED; + case EBUSY: + return P_ERR_BUSY; + case EBADMSG: + return P_ERR_CRC_MISMATCH; + case EIO: + return P_ERR_IO; + default: + return P_ERR_INTERNAL; + } +} + +void send_error(protocol_error_t error_code) { char response[32]; snprintf(response, sizeof(response), "ERR %d\n", error_code); @@ -51,7 +102,7 @@ int cmd_ls(const char *path) if (fs_pm_opendir(&dirp, ls_path) < 0) { LOG_ERR("Failed to open directory '%s'", ls_path); - return ENOENT; + return -ENOENT; } char tx_buffer[300]; @@ -73,7 +124,7 @@ int cmd_info() if (rc) { LOG_ERR("Failed to get filesystem stats: %d", rc); - return -rc; + return rc; } snprintf(info, sizeof(info), "%u;%s;%lu;%lu;%lu;%s\n", PROTOCOL_VERSION, APP_VERSION_STRING, stat.f_frsize, stat.f_blocks, stat.f_bfree, boot_is_img_confirmed() ? "CONFIRMED" : "UNCONFIRMED"); usb_write_buffer((const uint8_t *)info, strlen(info)); @@ -124,7 +175,7 @@ int cmd_put_binary_file(const char *filename, ssize_t filesize, uint32_t expecte if (rc < 0) { LOG_ERR("Failed to open file '%s' for writing: %d", filename, rc); - return -rc; + return rc; } } usb_write_buffer((const uint8_t *)"READY\n", 6); @@ -148,7 +199,7 @@ int cmd_put_binary_file(const char *filename, ssize_t filesize, uint32_t expecte { fs_pm_close(&file); } - return -read; + return (int)read; } else if (read == 0) { @@ -222,7 +273,8 @@ int cmd_put_binary_file(const char *filename, ssize_t filesize, uint32_t expecte { int rc; rc = boot_request_upgrade(BOOT_UPGRADE_TEST); - if (rc < 0) { + if (rc < 0) + { LOG_ERR("Failed to request firmware upgrade: %d", rc); return rc; } @@ -239,13 +291,14 @@ int cmd_put_binary_file(const char *filename, ssize_t filesize, uint32_t expecte if (running_crc32 != expected_crc32) { LOG_ERR("CRC32 mismatch for file '%s': expected 0x%08x, got 0x%08x", filename, expected_crc32, running_crc32); - return -EIO; + return -EBADMSG; } LOG_DBG("File '%s' received successfully with matching CRC32", filename); return 0; } -int cmd_mkdir(const char *path) { +int cmd_mkdir(const char *path) +{ int rc = fs_pm_mkdir(path); if (rc < 0) { @@ -255,7 +308,8 @@ int cmd_mkdir(const char *path) { return rc; } -int cmd_rm(const char *path) { +int cmd_rm(const char *path) +{ int rc = fs_pm_unlink(path); if (rc < 0) { @@ -265,37 +319,49 @@ int cmd_rm(const char *path) { return rc; } -int cmd_confirm_firmware() { - int rc = boot_write_img_confirmed(); - if (rc < 0) +int cmd_confirm_firmware() +{ + if (!boot_is_img_confirmed()) { - LOG_ERR("Failed to confirm firmware: %d", rc); - return rc; + int rc = boot_write_img_confirmed(); + if (rc < 0) + { + LOG_ERR("Failed to confirm firmware: %d", rc); + return rc; + } + LOG_INF("Firmware confirmed successfully"); + send_ok(); + audio_play("/lfs/sys/confirm"); + } + else + { + LOG_INF("Firmware is already confirmed, no action taken"); } - LOG_INF("Firmware confirmed successfully"); - send_ok(); - reboot_with_status(REBOOT_STATUS_FIRMWARE_CONFIRMED); return 0; } -int cmd_reboot_device() { +int cmd_reboot_device() +{ LOG_INF("Rebooting device as requested by host..."); send_ok(); reboot_with_status(REBOOT_STATUS_NORMAL); return 0; // Dieser Code wird nie erreicht, aber wir geben ihn der Vollständigkeit halber zurück } -void cmd_play(const char *filename) { +void cmd_play(const char *filename) +{ LOG_DBG("Play command received with filename: '%s'", filename); audio_play(filename); } -int cmd_check(const char *param) { +int cmd_check(const char *param) +{ LOG_DBG("Check command received with parameter: '%s'", param); struct fs_file_t file; fs_file_t_init(&file); int rc = fs_pm_open(&file, param, FS_O_READ); - if (rc < 0) { + if (rc < 0) + { LOG_ERR("Check failed: file '%s' not found", param); return -ENOENT; } @@ -307,7 +373,8 @@ int cmd_check(const char *param) { crc32 = crc32_ieee_update(crc32, buffer, read); } fs_pm_close(&file); - if (read < 0) { + if (read < 0) + { LOG_ERR("Check failed: error reading file '%s': %d", param, (int)read); return (int)read; } @@ -332,7 +399,7 @@ void execute_current_command(void) } else { - send_error(rc); + send_error(protocol_map_error(rc)); } break; case CMD_INFO: @@ -348,7 +415,7 @@ void execute_current_command(void) } else { - send_error(rc); + send_error(protocol_map_error(rc)); } break; case CMD_PUT_BINARY_FILE: @@ -360,7 +427,7 @@ void execute_current_command(void) if (rc != 3) { LOG_ERR("Invalid parameters for PUT_BINARY_FILE command (got %d): '%s'", rc, buffer); - send_error(EINVAL); + send_error(P_ERR_INVALID_PARAMETERS); break; } LOG_DBG("Executing PUT_BINARY_FILE command filename: '%s', filesize: %zd, crc32: 0x%08x", filename, filesize, crc32); @@ -373,35 +440,40 @@ void execute_current_command(void) else { usb_flush_rx(); - send_error(rc); + send_error(protocol_map_error(rc)); } break; case CMD_MKDIR: LOG_DBG("Executing MKDIR command with parameters: '%s'", buffer); rc = cmd_mkdir((char *)buffer); - if (rc == 0) { + if (rc == 0) + { send_ok(); } - else { - send_error(rc); + else + { + send_error(protocol_map_error(rc)); } break; case CMD_RM: LOG_DBG("Executing RM command with parameters: '%s'", buffer); rc = cmd_rm((char *)buffer); - if (rc == 0) { + if (rc == 0) + { send_ok(); audio_refresh_file_count(); // Nach erfolgreichem Löschen die Anzahl der verfügbaren Audiodateien aktualisieren } - else { - send_error(rc); + else + { + send_error(protocol_map_error(rc)); } break; case CMD_CONFIRM: LOG_DBG("Executing CONFIRM command"); rc = cmd_confirm_firmware(); - if (rc != 0) { - send_error(rc); + if (rc != 0) + { + send_error(protocol_map_error(rc)); break; } send_ok(); @@ -409,11 +481,12 @@ void execute_current_command(void) case CMD_REBOOT: LOG_DBG("Executing REBOOT command"); rc = cmd_reboot_device(); - if (rc != 0) { - send_error(rc); + if (rc != 0) + { + send_error(protocol_map_error(rc)); } break; - case CMD_PLAY: + case CMD_PLAY: LOG_DBG("Executing PLAY command"); cmd_play((char *)buffer); send_ok(); @@ -421,17 +494,18 @@ void execute_current_command(void) case CMD_CHECK: LOG_DBG("Executing CHECK command"); rc = cmd_check((char *)buffer); - if (rc == 0) { + if (rc == 0) + { send_ok(); } else { - send_error(rc); + send_error(protocol_map_error(rc)); } break; default: LOG_ERR("No execution logic for command %d", current_command); - send_error(ENOSYS); + send_error(P_ERR_NOT_SUPPORTED); break; } } @@ -504,7 +578,7 @@ protocol_state_t reading_command(uint8_t byte) { LOG_DBG("Unknown command: %s", buffer); current_command = CMD_INVALID; - send_error(EILSEQ); + send_error(P_ERR_INVALID_COMMAND); if (byte != '\n' && byte != '\r') return PS_WAITING_FOR_END_OF_LINE; return PS_WAITING_FOR_COMMAND; @@ -531,7 +605,7 @@ protocol_state_t reading_command(uint8_t byte) } else { - send_error(EMSGSIZE); + send_error(P_ERR_COMMAND_TOO_LONG); return PS_WAITING_FOR_END_OF_LINE; } } @@ -553,7 +627,7 @@ protocol_state_t reading_parameters(uint8_t byte) if (rx_index >= BUFFER_SIZE) { rx_index = 0; - send_error(EMSGSIZE); + send_error(P_ERR_COMMAND_TOO_LONG); return PS_WAITING_FOR_COMMAND; } return PS_READING_PARAMETERS; diff --git a/firmware/src/protocol.h b/firmware/src/protocol.h index 387f69c..d66e4f1 100644 --- a/firmware/src/protocol.h +++ b/firmware/src/protocol.h @@ -22,4 +22,27 @@ typedef enum { /* Weitere Kommandos folgen hier */ } protocol_cmd_t; +typedef enum { + P_ERR_NONE = 0x00, + P_ERR_INVALID_COMMAND = 0x01, + P_ERR_INVALID_PARAMETERS = 0x02, + P_ERR_COMMAND_TOO_LONG = 0x03, + + P_ERR_FILE_NOT_FOUND = 0x10, + P_ERR_ALREADY_EXISTS = 0x11, + P_ERR_NOT_A_DIRECTORY = 0x12, + P_ERR_IS_A_DIRECTORY = 0x13, + P_ERR_ACCESS_DENIED = 0x14, + P_ERR_NO_SPACE = 0x15, + P_ERR_FILE_TOO_LARGE = 0x16, + + P_ERR_IO = 0x20, + P_ERR_TIMEOUT = 0x21, + P_ERR_CRC_MISMATCH = 0x22, + P_ERR_TRANSFER_ABORTED = 0x23, + + P_ERR_NOT_SUPPORTED = 0x30, + P_ERR_BUSY = 0x31, + P_ERR_INTERNAL = 0x32, +} protocol_error_t; #endif // PROTOCOL_H \ No newline at end of file