Stand vor Protokollumbau

This commit is contained in:
2026-03-01 11:11:56 +01:00
parent c914333236
commit 4d88194f7d
17 changed files with 624 additions and 79 deletions

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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

View File

@@ -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
{

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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