Stand vor Protokollumbau
This commit is contained in:
@@ -3,9 +3,10 @@ mcuboot:
|
||||
size: 0xC000
|
||||
region: flash_primary
|
||||
|
||||
# Primary Slot: Start bleibt 0xC000, Größe jetzt 200KB (0x32000)
|
||||
mcuboot_primary:
|
||||
address: 0xC000
|
||||
size: 0x25000
|
||||
size: 0x32000
|
||||
region: flash_primary
|
||||
|
||||
mcuboot_pad:
|
||||
@@ -13,16 +14,19 @@ mcuboot_pad:
|
||||
size: 0x200
|
||||
region: flash_primary
|
||||
|
||||
# Die App startet nach dem Padding des Primary Slots
|
||||
app:
|
||||
address: 0xC200
|
||||
size: 0x24E00
|
||||
size: 0x31E00 # (0x32000 - 0x200)
|
||||
region: flash_primary
|
||||
|
||||
# Secondary Slot: Startet jetzt bei 0xC000 + 0x32000 = 0x3E000
|
||||
mcuboot_secondary:
|
||||
address: 0x31000
|
||||
size: 0x25000
|
||||
address: 0x3E000
|
||||
size: 0x32000
|
||||
region: flash_primary
|
||||
|
||||
# External Flash bleibt unverändert
|
||||
littlefs_storage:
|
||||
address: 0x0
|
||||
size: 0x800000
|
||||
|
||||
@@ -243,6 +243,8 @@ void audio_thread(void *arg1, void *arg2, void *arg3)
|
||||
continue;
|
||||
}
|
||||
|
||||
ssize_t file_size = fs_get_audio_data_len(&file);
|
||||
|
||||
LOG_INF("Playing: %s", filename);
|
||||
io_status(true);
|
||||
|
||||
@@ -269,7 +271,7 @@ void audio_thread(void *arg1, void *arg2, void *arg3)
|
||||
break;
|
||||
}
|
||||
|
||||
ssize_t bytes_read = fs_read(&file, block, AUDIO_BLOCK_SIZE / 2);
|
||||
ssize_t bytes_read = fs_read_audio(&file, block, AUDIO_BLOCK_SIZE / 2, file_size);
|
||||
|
||||
if (bytes_read <= 0)
|
||||
{
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
#include <zephyr/dfu/flash_img.h>
|
||||
#include <zephyr/dfu/mcuboot.h>
|
||||
#include <zephyr/pm/device.h>
|
||||
|
||||
#include <fs.h>
|
||||
LOG_MODULE_REGISTER(buzz_fs, LOG_LEVEL_INF);
|
||||
#include <utils.h>
|
||||
|
||||
LOG_MODULE_REGISTER(buzz_fs, LOG_LEVEL_DBG);
|
||||
|
||||
#define STORAGE_PARTITION_ID FIXED_PARTITION_ID(littlefs_storage)
|
||||
#define SLOT1_ID FIXED_PARTITION_ID(slot1_partition)
|
||||
@@ -167,6 +170,126 @@ int fs_pm_mkdir(const char *path)
|
||||
fs_pm_flash_suspend();
|
||||
return rc;
|
||||
}
|
||||
|
||||
ssize_t fs_get_audio_data_len(struct fs_file_t *fp) {
|
||||
uint8_t footer[6];
|
||||
off_t file_size;
|
||||
|
||||
fs_seek(fp, 0, FS_SEEK_END);
|
||||
file_size = fs_tell(fp);
|
||||
|
||||
fs_seek(fp, 0, FS_SEEK_SET);
|
||||
if (file_size < 6) return file_size;
|
||||
|
||||
fs_seek(fp, -6, FS_SEEK_END);
|
||||
if (fs_read(fp, footer, 6) == 6) {
|
||||
if (memcmp(&footer[2], "TAG!", 4) == 0) {
|
||||
uint16_t tag_len = footer[0] | (footer[1] << 8);
|
||||
if (tag_len <= file_size) {
|
||||
fs_seek(fp, 0, FS_SEEK_SET);
|
||||
return file_size - tag_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
fs_seek(fp, 0, FS_SEEK_SET);
|
||||
return file_size;
|
||||
}
|
||||
|
||||
ssize_t fs_read_audio(struct fs_file_t *fp, void *buffer, size_t len, size_t audio_limit) {
|
||||
off_t current_pos = fs_tell(fp);
|
||||
if (current_pos >= audio_limit) {
|
||||
return 0; // "Virtuelles" Dateiende erreicht
|
||||
}
|
||||
|
||||
size_t remaining = audio_limit - current_pos;
|
||||
size_t to_read = (len < remaining) ? len : remaining;
|
||||
return fs_read(fp, buffer, to_read);
|
||||
}
|
||||
|
||||
int fs_write_hex_tag(struct fs_file_t *fp, const char *hex_str) {
|
||||
size_t hex_len = strlen(hex_str);
|
||||
|
||||
// Ein Hex-String muss eine gerade Anzahl an Zeichen haben
|
||||
if (hex_len % 2 != 0) return -EINVAL;
|
||||
|
||||
size_t payload_len = hex_len / 2;
|
||||
uint16_t total_footer_len = (uint16_t)(payload_len + 6);
|
||||
|
||||
// 1. Audio-Ende bestimmen und dorthin seeken
|
||||
size_t audio_limit = fs_get_audio_data_len(fp);
|
||||
fs_seek(fp, audio_limit, FS_SEEK_SET);
|
||||
|
||||
// 2. Payload Byte für Byte konvertieren und schreiben
|
||||
for (size_t i = 0; i < hex_len; i += 2) {
|
||||
int high = hex2int(hex_str[i]);
|
||||
int low = hex2int(hex_str[i+1]);
|
||||
|
||||
if (high < 0 || low < 0) return -EINVAL; // Ungültiges Hex-Zeichen
|
||||
|
||||
uint8_t byte = (uint8_t)((high << 4) | low);
|
||||
fs_write(fp, &byte, 1);
|
||||
}
|
||||
|
||||
// 3. Die 2 Bytes Länge schreiben (Little Endian)
|
||||
uint8_t len_bytes[2];
|
||||
len_bytes[0] = (uint8_t)(total_footer_len & 0xFF);
|
||||
len_bytes[1] = (uint8_t)((total_footer_len >> 8) & 0xFF);
|
||||
fs_write(fp, len_bytes, 2);
|
||||
|
||||
// 4. Magic Bytes schreiben
|
||||
fs_write(fp, "TAG!", 4);
|
||||
|
||||
// 5. Datei am aktuellen Punkt abschneiden
|
||||
off_t current_pos = fs_tell(fp);
|
||||
return fs_truncate(fp, current_pos);
|
||||
}
|
||||
|
||||
int fs_read_hex_tag(struct fs_file_t *fp, char *hex_str, size_t hex_str_size) {
|
||||
if (hex_str == NULL || hex_str_size == 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hex_str[0] = '\0';
|
||||
|
||||
// Dateigröße ermitteln
|
||||
fs_seek(fp, 0, FS_SEEK_END);
|
||||
off_t file_size = fs_tell(fp);
|
||||
|
||||
// Audio-Limit finden (Anfang des Payloads)
|
||||
size_t audio_limit = fs_get_audio_data_len(fp);
|
||||
|
||||
// Prüfen, ob überhaupt ein Tag existiert (audio_limit < file_size)
|
||||
if (audio_limit >= file_size) {
|
||||
// Kein Tag vorhanden -> leerer String
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Die Payload-Länge ist: Gesamtgröße - Audio - 6 Bytes (Länge + Magic)
|
||||
size_t payload_len = file_size - audio_limit - 6;
|
||||
|
||||
if ((payload_len * 2U) + 1U > hex_str_size) {
|
||||
return -ENOMEM; // Nicht genug Platz im Zielpuffer
|
||||
}
|
||||
|
||||
// Zum Anfang des Payloads springen
|
||||
fs_seek(fp, audio_limit, FS_SEEK_SET);
|
||||
|
||||
uint8_t byte;
|
||||
for (size_t i = 0; i < payload_len; i++) {
|
||||
if (fs_read(fp, &byte, 1) != 1) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
// Jedes Byte als zwei Hex-Zeichen in den Zielpuffer schreiben
|
||||
hex_str[i * 2] = int2hex(byte >> 4);
|
||||
hex_str[i * 2 + 1] = int2hex(byte & 0x0F);
|
||||
}
|
||||
|
||||
hex_str[payload_len * 2] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flash_get_slot_info(slot_info_t *info) {
|
||||
if (slot1_info.size != 0) {
|
||||
*info = slot1_info;
|
||||
|
||||
@@ -82,6 +82,40 @@ int fs_pm_statvfs(const char *path, struct fs_statvfs *stat);
|
||||
*/
|
||||
int fs_pm_mkdir(const char *path);
|
||||
|
||||
/**
|
||||
* @brief Gets the length of the audio data in a file, accounting for any metadata tags
|
||||
* @param fp Pointer to an open fs_file_t structure representing the audio file
|
||||
* @return Length of the audio data in bytes, or negative error code on failure
|
||||
*/
|
||||
int fs_get_audio_data_len(struct fs_file_t *fp);
|
||||
|
||||
/**
|
||||
* @brief Reads audio data from a file, ensuring that it does not read past the audio data limit
|
||||
* @param fp Pointer to an open fs_file_t structure representing the audio file
|
||||
* @param buffer Pointer to the buffer to read data into
|
||||
* @param len Maximum number of bytes to read
|
||||
* @param audio_limit Maximum byte offset for audio data (e.g. file size minus metadata)
|
||||
* @return Number of bytes read, or negative error code on failure
|
||||
*/
|
||||
int fs_read_audio(struct fs_file_t *fp, void *buffer, size_t len, size_t audio_limit);
|
||||
|
||||
/**
|
||||
* @brief Writes a hexadecimal string as a metadata tag at the end of an audio file
|
||||
* @param fp Pointer to an open fs_file_t structure representing the audio file
|
||||
* @param hex_str Null-terminated string containing hexadecimal characters (0-9, a-f, A-F)
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int fs_write_hex_tag(struct fs_file_t *fp, const char *hex_str);
|
||||
|
||||
/**
|
||||
* @brief Reads a hexadecimal string from a metadata tag at the end of an audio file
|
||||
* @param fp Pointer to an open fs_file_t structure representing the audio file
|
||||
* @param hex_str Buffer to be filled with the hexadecimal string (must be large enough to hold the data)
|
||||
* @param hex_str_size Size of the hex_str buffer
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int fs_read_hex_tag(struct fs_file_t *fp, char *hex_str, size_t hex_str_size);
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#define PROTOCOL_VERSION 2
|
||||
|
||||
LOG_MODULE_REGISTER(protocol, LOG_LEVEL_DBG);
|
||||
LOG_MODULE_REGISTER(protocol, LOG_LEVEL_INF);
|
||||
|
||||
#define PROTOCOL_STACK_SIZE 2048
|
||||
#define PROTOCOL_PRIORITY 6
|
||||
@@ -319,6 +319,63 @@ int cmd_rm(const char *path)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cmd_set_tag(const char *param)
|
||||
{
|
||||
LOG_DBG("SET_TAG command received with parameter: '%s'", param);
|
||||
if (param == NULL || param[0] == '\0')
|
||||
{
|
||||
LOG_ERR("SET_TAG command requires a non-empty parameter");
|
||||
return -EINVAL;
|
||||
}
|
||||
uint8_t tag_buffer[256];
|
||||
uint8_t filename[64];
|
||||
int rc = sscanf(param, "%63[^;];%255[^\n]", filename, tag_buffer);
|
||||
if (rc != 2) {
|
||||
LOG_ERR("Invalid parameters for SET_TAG command (got %d): '%s'", rc, param);
|
||||
return -EINVAL;
|
||||
}
|
||||
struct fs_file_t file;
|
||||
fs_file_t_init(&file);
|
||||
rc = fs_pm_open(&file, (const char *)filename, FS_O_READ | FS_O_WRITE);
|
||||
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to open file '%s' for SET_TAG: %d", filename, rc);
|
||||
return rc;
|
||||
}
|
||||
rc = fs_write_hex_tag(&file, (const char *)tag_buffer);
|
||||
fs_pm_close(&file);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to write tag to file '%s': %d", filename, rc);
|
||||
return rc;
|
||||
}
|
||||
LOG_DBG("Tag written successfully to file '%s'", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_get_tag(const char *param)
|
||||
{
|
||||
LOG_DBG("GET_TAG command received");
|
||||
struct fs_file_t file;
|
||||
fs_file_t_init(&file);
|
||||
int rc = fs_pm_open(&file, param, FS_O_READ);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to open file '%s' for GET_TAG: %d", param, rc);
|
||||
return rc;
|
||||
}
|
||||
uint8_t tag_buffer[256];
|
||||
rc = fs_read_hex_tag(&file, tag_buffer, sizeof(tag_buffer));
|
||||
fs_pm_close(&file);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Failed to read tag from file '%s': %d", param, rc);
|
||||
return rc;
|
||||
}
|
||||
LOG_DBG("Tag read successfully from file '%s': '%s'", param, tag_buffer);
|
||||
LOG_HEXDUMP_DBG(tag_buffer, strlen((char *)tag_buffer), "Tag content");
|
||||
usb_write_buffer(tag_buffer, strlen((char *)tag_buffer));
|
||||
usb_write_char('\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_confirm_firmware()
|
||||
{
|
||||
if (!boot_is_img_confirmed())
|
||||
@@ -370,7 +427,8 @@ int cmd_check(const char *param)
|
||||
uint32_t start_time = k_uptime_get_32();
|
||||
uint8_t buffer[256];
|
||||
ssize_t read;
|
||||
while ((read = fs_read(&file, buffer, sizeof(buffer))) > 0)
|
||||
ssize_t file_size = fs_get_audio_data_len(&file);
|
||||
while ((read = fs_read_audio(&file, buffer, sizeof(buffer), file_size)) > 0)
|
||||
{
|
||||
crc32 = crc32_ieee_update(crc32, buffer, read);
|
||||
}
|
||||
@@ -383,7 +441,7 @@ int cmd_check(const char *param)
|
||||
uint32_t duration = k_uptime_get_32() - start_time;
|
||||
LOG_DBG("Check successful: file '%s' has CRC32 0x%08x, check took %u ms", param, crc32, duration);
|
||||
char response[64];
|
||||
snprintf(response, sizeof(response), "CRC32 %s 0x%08x\n", param, crc32);
|
||||
snprintf(response, sizeof(response), "0x%08x\n", crc32);
|
||||
usb_write_buffer((const uint8_t *)response, strlen(response));
|
||||
return 0;
|
||||
}
|
||||
@@ -506,6 +564,28 @@ void execute_current_command(void)
|
||||
send_error(protocol_map_error(rc));
|
||||
}
|
||||
break;
|
||||
case CMD_SET_TAG:
|
||||
LOG_DBG("Executing SET_TAG command");
|
||||
rc = cmd_set_tag((char *)buffer);
|
||||
if (rc == 0)
|
||||
{
|
||||
send_ok();
|
||||
}
|
||||
else
|
||||
{
|
||||
send_error(protocol_map_error(rc));
|
||||
}
|
||||
break;
|
||||
case CMD_GET_TAG:
|
||||
LOG_DBG("Executing GET_TAG command");
|
||||
rc = cmd_get_tag((char *)buffer);
|
||||
if (rc == 0) {
|
||||
send_ok();
|
||||
}
|
||||
else {
|
||||
send_error(protocol_map_error(rc));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_ERR("No execution logic for command %d", current_command);
|
||||
send_error(P_ERR_NOT_SUPPORTED);
|
||||
@@ -576,6 +656,15 @@ protocol_state_t reading_command(uint8_t byte)
|
||||
{
|
||||
LOG_DBG("Received CHECK command");
|
||||
current_command = CMD_CHECK;
|
||||
} else if (strcmp((char *)buffer, "gett") == 0)
|
||||
{
|
||||
LOG_DBG("Received GETT command");
|
||||
current_command = CMD_GET_TAG;
|
||||
}
|
||||
else if (strcmp((char *)buffer, "sett") == 0)
|
||||
{
|
||||
LOG_DBG("Received SETT command");
|
||||
current_command = CMD_SET_TAG;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -18,6 +18,8 @@ typedef enum {
|
||||
CMD_CONFIRM,
|
||||
CMD_REBOOT,
|
||||
CMD_PLAY,
|
||||
CMD_SET_TAG,
|
||||
CMD_GET_TAG,
|
||||
CMD_CHECK,
|
||||
/* Weitere Kommandos folgen hier */
|
||||
} protocol_cmd_t;
|
||||
|
||||
@@ -50,4 +50,16 @@ uint8_t get_reboot_status(void)
|
||||
printk("Reboot status detected: 0x%02x\n", status);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int hex2int(char c) {
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||
return -1; // Fehlerhaftes Zeichen
|
||||
}
|
||||
|
||||
char int2hex(uint8_t i) {
|
||||
if (i < 10) return '0' + i;
|
||||
return 'a' + (i - 10);
|
||||
}
|
||||
@@ -21,4 +21,19 @@ void reboot_with_status(uint8_t status_code);
|
||||
* @return The reboot status code set before the last reboot, or 0 if no status was set.
|
||||
*/
|
||||
uint8_t get_reboot_status();
|
||||
#endif // UTILS_H
|
||||
|
||||
/**
|
||||
* @brief Converts a hexadecimal character to its integer value.
|
||||
* @param c The hexadecimal character (0-9, a-f, A-F) to convert.
|
||||
* @return The integer value of the hexadecimal character, or -1 if the character is not a valid hexadecimal digit.
|
||||
*/
|
||||
int hex2int(char c);
|
||||
|
||||
/**
|
||||
* @brief Converts an integer value to its hexadecimal character representation.
|
||||
* @param i The integer value to convert (0-15).
|
||||
* @return The hexadecimal character representation of the integer value.
|
||||
*/
|
||||
char int2hex(uint8_t i);
|
||||
|
||||
#endif // UTILS_H
|
||||
|
||||
Reference in New Issue
Block a user