diff --git a/firmware/VERSION b/firmware/VERSION index 57ab7a2..1e4a188 100644 --- a/firmware/VERSION +++ b/firmware/VERSION @@ -1,5 +1,5 @@ VERSION_MAJOR = 0 VERSION_MINOR = 0 -PATCHLEVEL = 2 +PATCHLEVEL = 9 VERSION_TWEAK = 0 EXTRAVERSION = 0 \ No newline at end of file diff --git a/firmware/boards/nrf52840dk_nrf52840.conf b/firmware/boards/nrf52840dk_nrf52840.conf index 332c42f..a012389 100644 --- a/firmware/boards/nrf52840dk_nrf52840.conf +++ b/firmware/boards/nrf52840dk_nrf52840.conf @@ -1,2 +1,6 @@ CONFIG_NRFX_POWER=y -CONFIG_BT=n \ No newline at end of file +CONFIG_BT=n +CONFIG_NCS_APPLICATION_BOOT_BANNER_STRING="Edi's Buzzer" + +# --- Für PRODUKTIONSBUILD: Alle Debug-Features aus --- +# CONFIG_NCS_BOOT_BANNER=n \ No newline at end of file diff --git a/firmware/boards/nrf52840dk_nrf52840.overlay b/firmware/boards/nrf52840dk_nrf52840.overlay index 06c5ea2..fa97a6b 100644 --- a/firmware/boards/nrf52840dk_nrf52840.overlay +++ b/firmware/boards/nrf52840dk_nrf52840.overlay @@ -63,7 +63,6 @@ pinctrl-names = "default", "sleep"; }; -// &uart0 { status = "disabled"; }; &i2c0 { status = "disabled"; }; &spi1 { status = "disabled"; }; &spi3 { status = "disabled"; }; @@ -74,4 +73,15 @@ &radio { status = "disabled"; }; &ieee802154 { status = "disabled"; }; &bt_hci_sdc { status = "disabled"; }; -&cryptocell { status = "disabled"; }; \ No newline at end of file +&cryptocell { status = "disabled"; }; + +// unkommentieren für prod +// &uart0 { status = "disabled"; }; +// / { +// chosen { +// /delete-property/ zephyr,console; +// /delete-property/ zephyr,shell-uart; +// /delete-property/ zephyr,uart-mcumgr; +// /delete-property/ zephyr,ieee802154; +// }; +// }; \ No newline at end of file diff --git a/firmware/pm_static.yml b/firmware/pm_static.yml index f78811f..20b8a1c 100644 --- a/firmware/pm_static.yml +++ b/firmware/pm_static.yml @@ -1,4 +1,29 @@ +mcuboot: + address: 0x0 + size: 0xC000 + region: flash_primary + +mcuboot_primary: + address: 0xC000 + size: 0x25000 + region: flash_primary + +mcuboot_pad: + address: 0xC000 + size: 0x200 + region: flash_primary + +app: + address: 0xC200 + size: 0x24E00 + region: flash_primary + +mcuboot_secondary: + address: 0x31000 + size: 0x25000 + region: flash_primary + littlefs_storage: address: 0x0 size: 0x800000 - region: external_flash + region: external_flash \ No newline at end of file diff --git a/firmware/prj.conf b/firmware/prj.conf index 5ed4f55..03b1eab 100644 --- a/firmware/prj.conf +++ b/firmware/prj.conf @@ -19,6 +19,7 @@ CONFIG_FS_LITTLEFS_PROG_SIZE=256 CONFIG_FS_LITTLEFS_CACHE_SIZE=512 CONFIG_FS_LITTLEFS_LOOKAHEAD_SIZE=128 CONFIG_FS_LITTLEFS_BLOCK_CYCLES=512 +CONFIG_MAIN_STACK_SIZE=2048 # --- USB Device & CDC ACM --- CONFIG_USB_DEVICE_STACK=y @@ -40,12 +41,39 @@ CONFIG_UART_LINE_CTRL=y CONFIG_I2S=y CONFIG_NRFX_I2S=y -# --- Random & HW Info (für Audio-File-Auswahl) --- +# --- MCUMGR für Firmware-Updates --- +CONFIG_REBOOT=y +CONFIG_FLASH_MAP=y +CONFIG_STREAM_FLASH=y +CONFIG_IMG_MANAGER=y +CONFIG_MCUBOOT_IMG_MANAGER=y + +# --- HWINFO und CRC --- CONFIG_HWINFO=y CONFIG_CRC=y +# --- Debugging & Sicherheit --- +CONFIG_ASSERT=y +CONFIG_HW_STACK_PROTECTION=y +CONFIG_RESET_ON_FATAL_ERROR=y + # --- Unbenutze Features --- CONFIG_ADC=n CONFIG_I2C=n CONFIG_SPI=n -CONFIG_PWM=n \ No newline at end of file +CONFIG_PWM=n + +# UNKOMMENTIEREN FÜR PRODUKTIONSBUILD (KEINE KONSOLE, KEIN LOGGING, KEINE DEBUGGING-INFO) +# # --- Konsole & Output komplett aus --- +# CONFIG_CONSOLE=n +# CONFIG_UART_CONSOLE=n +# CONFIG_PRINTK=n +# CONFIG_BOOT_BANNER=n +# CONFIG_STDOUT_CONSOLE=n + +# # --- Logging aus --- +# CONFIG_LOG=n + +# # --- Debugging-Features reduzieren --- +# CONFIG_ASSERT=n +# CONFIG_DEBUG_THREAD_INFO=n \ No newline at end of file diff --git a/firmware/src/audio.c b/firmware/src/audio.c index 9292a46..5e23fc0 100644 --- a/firmware/src/audio.c +++ b/firmware/src/audio.c @@ -10,7 +10,7 @@ #include #include -LOG_MODULE_REGISTER(audio, LOG_LEVEL_DBG); +LOG_MODULE_REGISTER(audio, LOG_LEVEL_INF); /* Dauer eines Blocks in ms (4096 Bytes / (16kHz * 2 Kanäle * 2 Bytes)) = 64 ms */ #define BLOCK_DURATION_MS 64 @@ -68,8 +68,8 @@ void i2s_resume(void) void audio_refresh_file_count(void) { - struct fs_dir_t dirp; - struct fs_dirent entry; + static struct fs_dir_t dirp; + static struct fs_dirent entry; uint32_t count = 0; fs_dir_t_init(&dirp); diff --git a/firmware/src/fs.c b/firmware/src/fs.c index 7008996..786673a 100644 --- a/firmware/src/fs.c +++ b/firmware/src/fs.c @@ -1,10 +1,13 @@ #include #include +#include #include #include -LOG_MODULE_REGISTER(buzz_fs, LOG_LEVEL_DBG); +LOG_MODULE_REGISTER(buzz_fs, LOG_LEVEL_INF); #define STORAGE_PARTITION_ID FIXED_PARTITION_ID(littlefs_storage) +#define SLOT1_ID FIXED_PARTITION_ID(slot1_partition) + FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(fs_storage_data); #define QSPI_FLASH_NODE DT_ALIAS(qspi_flash) @@ -13,8 +16,11 @@ FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(fs_storage_data); #endif static const struct device *flash_dev = DEVICE_DT_GET(QSPI_FLASH_NODE); + static volatile uint32_t open_count = 0; static struct k_mutex flash_pm_lock; +static struct slot_info_t slot1_info; +static struct flash_img_context flash_ctx; static struct fs_mount_t fs_storage_mnt = { .type = FS_LITTLEFS, @@ -30,6 +36,17 @@ int fs_init(void) { return rc; } k_mutex_init(&flash_pm_lock); + + const struct flash_area *fa; + rc = flash_area_open(SLOT1_ID, &fa); + if (rc < 0) { + LOG_ERR("Error opening flash area for slot 1: %d", rc); + return rc; + } + slot1_info.start_addr = fa->fa_off; + slot1_info.size = fa->fa_size; + flash_area_close(fa); + LOG_DBG("Filesystem mounted successfully"); return 0; } @@ -128,10 +145,7 @@ int fs_pm_unlink(const char *path) LOG_DBG("PM Unlinking file '%s'", path); fs_pm_flash_resume(); int rc = fs_unlink(path); - if (rc < 0) - { - fs_pm_flash_suspend(); - } + fs_pm_flash_suspend(); return rc; } @@ -142,4 +156,42 @@ int fs_pm_statvfs(const char *path, struct fs_statvfs *stat) int rc = fs_statvfs(path, stat); fs_pm_flash_suspend(); return rc; +} + +int fs_pm_mkdir(const char *path) +{ + LOG_DBG("PM Creating directory '%s'", path); + fs_pm_flash_resume(); + int rc = fs_mkdir(path); + fs_pm_flash_suspend(); + return rc; +} +int flash_get_slot_info(slot_info_t *info) { + if (slot1_info.size != 0) { + *info = slot1_info; + return 0; + } + return -ENODEV; +} + +int flash_init_firmware_upload(void) { + int rc; + + rc = flash_img_init_id(&flash_ctx, SLOT1_ID); + if (rc != 0) { + printk("Error initializing flash image: %d\n", rc); + return rc; + } + return 0; +} + +int flash_write_firmware_block(const uint8_t *buffer, size_t length, bool is_last_block) { + int rc; + rc = flash_img_buffered_write(&flash_ctx, buffer, length, is_last_block); + + if (rc != 0) { + printk("Error writing flash image: %d\n", rc); + return rc; + } + return 0; } \ No newline at end of file diff --git a/firmware/src/fs.h b/firmware/src/fs.h index 14f7582..fc4272d 100644 --- a/firmware/src/fs.h +++ b/firmware/src/fs.h @@ -3,6 +3,11 @@ #include +typedef struct slot_info_t { + size_t start_addr; + size_t size; +} slot_info_t; + /** * @brief Initializes the filesystem by mounting it */ @@ -68,4 +73,35 @@ int fs_pm_unlink(const char *path); * @return 0 on success, negative error code on failure */ int fs_pm_statvfs(const char *path, struct fs_statvfs *stat); + +/** + * @brief Wrapper around fs_mkdir that handles power management for the flash + * Resumes the flash before creating the directory and suspends it afterwards + * @param path Path to the directory to create + * @return 0 on success, negative error code on failure + */ +int fs_pm_mkdir(const char *path); + +/** + * @brief Retrieves information about the firmware slot, such as start address and size + * @param info Pointer to slot_info_t structure to be filled with slot information + * @return 0 on success, negative error code on failure + */ +int flash_get_slot_info(slot_info_t *info); + +/** + * @brief Initializes the flash for firmware upload, preparing it for receiving new firmware data + * @return 0 on success, negative error code on failure + */ +int flash_init_firmware_upload(void); + +/** + * @brief Writes a block of firmware data to the flash + * @param buffer Pointer to the data buffer + * @param length Length of the data buffer + * @param is_last_block Indicates if this is the last block of the firmware + * @return 0 on success, negative error code on failure + */ +int flash_write_firmware_block(const uint8_t *buffer, size_t length, bool is_last_block); + #endif // FS_H \ No newline at end of file diff --git a/firmware/src/io.c b/firmware/src/io.c index 774b1b4..18d9c12 100644 --- a/firmware/src/io.c +++ b/firmware/src/io.c @@ -3,7 +3,7 @@ #include #include -LOG_MODULE_REGISTER(io, LOG_LEVEL_DBG); +LOG_MODULE_REGISTER(io, LOG_LEVEL_INF); #define STATUS_LED_NODE DT_ALIAS(status_led) #define USB_LED_NODE DT_ALIAS(usb_led) diff --git a/firmware/src/main.c b/firmware/src/main.c index 3285a56..40b619c 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -16,36 +16,9 @@ LOG_MODULE_REGISTER(main, LOG_LEVEL_INF); -void print_device_id(void) { - uint8_t device_id[8]; // 64 Bit = 8 Bytes - ssize_t length; - - // Device ID auslesen - length = hwinfo_get_device_id(device_id, sizeof(device_id)); - - if (length > 0) { - char id_str[17]; // 16 Zeichen + Null-Terminator - for (int i = 0; i < length; i++) { - sprintf(&id_str[i * 2], "%02x", device_id[i]); - } - LOG_INF("Board Device ID: %s", id_str); - } else { - LOG_ERR("Konnte Device ID nicht lesen"); - } -} - -static int print_custom_banner(void) -{ - printk("*** Edis Buzzer Version: " APP_VERSION_STRING " ***" ); - return 0; -} - -SYS_INIT(print_custom_banner, PRE_KERNEL_1, 0); - int main(void) { - LOG_INF("Starting Edis Buzzer Application"); - print_device_id(); + LOG_INF("Starting Edi's Buzzer Application"); int rc; @@ -75,4 +48,10 @@ int main(void) LOG_INF("All subsystems initialized. Starting application threads."); audio_system_ready(); + k_sleep(K_SECONDS(5)); // Kurze Pause, damit die READY-Antworten der Subsysteme noch rausgehen + volatile uint32_t *invalid_pointer = (volatile uint32_t *)0xFFFFFFFF; + *invalid_pointer = 0xDEADBEEF; + while (1) { + k_sleep(K_FOREVER); + } } \ No newline at end of file diff --git a/firmware/src/protocol.c b/firmware/src/protocol.c index e26fcc5..8cd3e89 100644 --- a/firmware/src/protocol.c +++ b/firmware/src/protocol.c @@ -1,9 +1,12 @@ #include #include +#include #include #include #include #include +#include +#include #include #include @@ -80,22 +83,50 @@ int send_info() int put_binary_file(const char *filename, ssize_t filesize, uint32_t expected_crc32) { int rc; - struct fs_file_t file; ssize_t bytes_written = 0; uint32_t running_crc32 = 0; uint32_t retry_count = 0; size_t accumulated = 0; + struct fs_file_t file; + bool firmware_update = false; - fs_file_t_init(&file); - fs_pm_unlink(filename); - LOG_DBG("Opening file '%s' for writing (expected size: %zd bytes, expected CRC32: 0x%08x)", filename, filesize, expected_crc32); - rc = fs_pm_open(&file, filename, FS_O_CREATE | FS_O_WRITE); - if (rc < 0) + if (strcmp(filename, "update.bin") == 0 || + strcmp(filename, "firmware.bin") == 0 || + strcmp(filename, "update") == 0 || + strcmp(filename, "firmware") == 0) { - LOG_ERR("Failed to open file '%s' for writing: %d", filename, rc); - return -rc; + firmware_update = true; + LOG_INF("Firmware update requested with file '%s'", filename); } + if (firmware_update) + { + slot_info_t slot1_info; + rc = flash_get_slot_info(&slot1_info); + if (rc < 0) + { + LOG_ERR("Failed to get slot 1 info: %d", rc); + return rc; + } + if (filesize > slot1_info.size) + { + LOG_ERR("File size %zd exceeds slot 1 size %zu", filesize, slot1_info.size); + return -EFBIG; + } + flash_init_firmware_upload(); + } + else + { + fs_file_t_init(&file); + fs_pm_unlink(filename); + LOG_DBG("Opening file '%s' for writing (expected size: %zd bytes, expected CRC32: 0x%08x)", filename, filesize, expected_crc32); + rc = fs_pm_open(&file, filename, FS_O_CREATE | FS_O_WRITE); + if (rc < 0) + { + LOG_ERR("Failed to open file '%s' for writing: %d", filename, rc); + return -rc; + } + } usb_write_buffer((const uint8_t *)"READY\n", 6); uint32_t start = k_uptime_get_32(); @@ -110,7 +141,13 @@ int put_binary_file(const char *filename, ssize_t filesize, uint32_t expected_cr if (read < 0) { LOG_ERR("Error reading from USB: %d", read); - fs_pm_close(&file); + if (firmware_update) + { + } + else + { + fs_pm_close(&file); + } return -read; } else if (read == 0) @@ -118,18 +155,24 @@ int put_binary_file(const char *filename, ssize_t filesize, uint32_t expected_cr if (retry_count >= 10) { LOG_ERR("No data received from USB after multiple attempts"); - fs_pm_close(&file); + if (firmware_update) + { + } + else + { + fs_pm_close(&file); + } return -ETIMEDOUT; } usb_resume_rx(); if ((bytes_written + accumulated) == 0) { - usb_wait_for_data(K_SECONDS(30)); + usb_wait_for_data(K_SECONDS(1)); } else { - usb_wait_for_data(K_SECONDS(1)); + usb_wait_for_data(K_MSEC(100)); } retry_count++; continue; @@ -144,14 +187,25 @@ int put_binary_file(const char *filename, ssize_t filesize, uint32_t expected_cr ODER wenn wir das Ende der Datei erreicht haben. */ if (accumulated == sizeof(buffer) || (bytes_written + accumulated) == filesize) { - ssize_t written = fs_write(&file, buffer, accumulated); - if (written < 0) + if (firmware_update) { - LOG_ERR("Error writing to file '%s': %d", filename, (int)written); - fs_pm_close(&file); - return (int)written; + int rc = flash_write_firmware_block(buffer, accumulated, (bytes_written + accumulated) == filesize); + if (rc < 0) + { + LOG_ERR("Error writing to flash: %d", rc); + return rc; + } + } + else + { + ssize_t written = fs_write(&file, buffer, accumulated); + if (written < 0) + { + LOG_ERR("Error writing to file '%s': %d", filename, (int)written); + fs_pm_close(&file); + return (int)written; + } } - /* CRC erst nach dem erfolgreichen Block-Schreiben berechnen */ running_crc32 = crc32_ieee_update(running_crc32, buffer, accumulated); bytes_written += accumulated; @@ -164,8 +218,26 @@ int put_binary_file(const char *filename, ssize_t filesize, uint32_t expected_cr uint32_t duration = k_uptime_get_32() - start; uint32_t kb_per_s = (filesize * 1000) / (duration * 1024 + 1); LOG_DBG("Received file '%s' (%zd bytes) in %u ms (%u kb/s), CRC32: 0x%08x", filename, filesize, duration, kb_per_s, running_crc32); - fs_pm_close(&file); - LOG_DBG("Closed file '%s' after writing", filename); + if (firmware_update) + { + int rc; + rc = boot_request_upgrade(BOOT_UPGRADE_TEST); + if (rc < 0) { + LOG_ERR("Failed to request firmware upgrade: %d", rc); + return rc; + } + send_ok(); + LOG_INF("Firmware upgrade requested, rebooting into bootloader..."); + k_sleep(K_MSEC(100)); // Kurze Pause, damit die OK-Antwort noch rausgeht + while (log_process()); + sys_reboot(SYS_REBOOT_COLD); + } + else + { + fs_pm_close(&file); + LOG_DBG("Closed file '%s' after writing", filename); + } + if (running_crc32 != expected_crc32) { LOG_ERR("CRC32 mismatch for file '%s': expected 0x%08x, got 0x%08x", filename, expected_crc32, running_crc32); @@ -175,6 +247,26 @@ int put_binary_file(const char *filename, ssize_t filesize, uint32_t expected_cr return 0; } +int mkdir(const char *path) { + int rc = fs_pm_mkdir(path); + if (rc < 0) + { + LOG_ERR("Failed to create directory '%s': %d", path, rc); + } + LOG_DBG("Directory '%s' created successfully", path); + return rc; +} + +int rm(const char *path) { + int rc = fs_pm_unlink(path); + if (rc < 0) + { + LOG_ERR("Failed to remove '%s': %d", path, rc); + } + LOG_DBG("'%s' removed successfully", path); + return rc; +} + void execute_current_command(void) { int rc; @@ -233,6 +325,27 @@ void execute_current_command(void) send_error(rc); } break; + case CMD_MKDIR: + LOG_DBG("Executing MKDIR command with parameters: '%s'", buffer); + rc = mkdir((char *)buffer); + if (rc == 0) { + send_ok(); + } + else { + send_error(rc); + } + break; + case CMD_RM: + LOG_DBG("Executing RM command with parameters: '%s'", buffer); + rc = rm((char *)buffer); + if (rc == 0) { + send_ok(); + audio_refresh_file_count(); // Nach erfolgreichem Löschen die Anzahl der verfügbaren Audiodateien aktualisieren + } + else { + send_error(rc); + } + break; default: LOG_ERR("No execution logic for command %d", current_command); send_error(ENOSYS); @@ -274,7 +387,16 @@ protocol_state_t reading_command(uint8_t byte) LOG_DBG("Received PUT_BINARY_FILE command"); current_command = CMD_PUT_BINARY_FILE; } - + else if (strcmp((char *)buffer, "mkdir") == 0) + { + LOG_DBG("Received MKDIR command"); + current_command = CMD_MKDIR; + } + else if (strcmp((char *)buffer, "rm") == 0) + { + LOG_DBG("Received RM command"); + current_command = CMD_RM; + } else { LOG_DBG("Unknown command: %s", buffer); diff --git a/firmware/src/protocol.h b/firmware/src/protocol.h index 9a8a852..503a4b7 100644 --- a/firmware/src/protocol.h +++ b/firmware/src/protocol.h @@ -13,6 +13,8 @@ typedef enum { CMD_INFO, CMD_LS, CMD_PUT_BINARY_FILE, + CMD_MKDIR, + CMD_RM, /* Weitere Kommandos folgen hier */ } protocol_cmd_t;