vor ble umbau

This commit is contained in:
2026-03-12 07:07:00 +01:00
parent 96aed70fc6
commit 5bb0d345da
45 changed files with 3681 additions and 48 deletions

View File

@@ -0,0 +1,5 @@
if(CONFIG_BUZZ_PROTO)
zephyr_library()
zephyr_library_sources(src/buzz_proto.c)
zephyr_include_directories(include)
endif()

View File

@@ -0,0 +1,41 @@
menuconfig BUZZ_PROTO
bool "Buzzer Protocol"
select CRC
help
Library for initializing and managing the buzzer protocol.
config BUZZ_PROTO_SLAB_SIZE
int "Slab Size"
default 256
help
Size of the memory slabs used for message buffers. Must be large enough to hold the largest expected message.
config BUZZ_PROTO_SLAB_COUNT
int "Slab Count"
default 64
help
Number of memory slabs to allocate for message buffers. More slabs allow for more concurrent messages but use more RAM.
config BUZZ_PROTO_MSGQ_SIZE
int "Message Queue Size"
default 16
help
Number of messages that can be queued for processing. Adjust based on expected message burstiness.
config BUZZ_PROT_THREAD_STACK_SIZE
int "Thread Stack Size"
default 2048
help
Stack size for the buzzer protocol thread. Adjust based on the expected workload and function call depth.
config BUZZ_PROTO_THREAD_PRIORITY
int "Thread Priority"
default 7
help
Priority for the buzzer protocol thread. Lower numbers indicate higher priority.
if BUZZ_PROTO
module = BUZZ_PROTO
module-str = buzz_proto
source "subsys/logging/Kconfig.template.log_config"
endif # BUZZ_PROTO

View File

@@ -0,0 +1,145 @@
#ifndef BUZZ_PROTO_H
#define BUZZ_PROTO_H
#include <stdint.h>
#include <stddef.h>
#include <zephyr/sys/byteorder.h>
#define BUZZ_PROTO_VERSION 1
/* --- Enums für Protokoll-Typen --- */
enum buzz_frame_type
{
BUZZ_FRAME_REQUEST = 0x00,
BUZZ_FRAME_RESPONSE = 0x10,
BUZZ_FRAME_ACK = 0x11,
BUZZ_FRAME_ERROR = 0x12,
BUZZ_FRAME_FILE_START = 0x20,
BUZZ_FRAME_FILE_CHUNK = 0x21,
BUZZ_FRAME_FILE_END = 0x22,
BUZZ_FRAME_FW_START = 0x30,
BUZZ_FRAME_FW_CHUNK = 0x31,
BUZZ_FRAME_FW_END = 0x32,
BUZZ_FRAME_LS_START = 0x40,
BUZZ_FRAME_LS_ENTRY = 0x41,
BUZZ_FRAME_LS_END = 0x42,
};
enum buzz_data_type
{
BUZZ_DATA_PROTO_INFO = 0x01,
BUZZ_DATA_DEVICE_INFO = 0x02,
BUZZ_DATA_FS_INFO = 0x03,
BUZZ_DATA_FILE_GET = 0x20,
BUZZ_DATA_FILE_PUT = 0x21,
BUZZ_DATA_LS = 0x40,
};
enum buzz_fs_entry_type
{
BUZZ_FS_ENTRY_FILE = 0x00,
BUZZ_FS_ENTRY_DIR = 0x01,
};
/* --- Wire Protocol Structs (Packed) --- */
/* Generischer Header für alle Frames */
struct __attribute__((packed)) buzz_proto_header
{
uint8_t frame_type; /* Nutzt enum buzz_frame_type */
uint16_t payload_length; /* Länge der folgenden Daten (Little Endian) */
};
/* Payload für einen Error-Frame */
struct __attribute__((packed)) buzz_resp_error
{
uint16_t error_code; /* Bis 0xFF reserviert für Standard-Fehler, 0x100+ für spezifische Fehler */
};
/* Payload für eine Standard-Anfrage (Request) */
struct __attribute__((packed)) buzz_request_payload
{
uint8_t data_type; /* Nutzt enum buzz_data_type */
};
/* Payload für die Protokollversions-Antwort */
struct __attribute__((packed)) buzz_resp_proto_version
{
uint8_t data_type; /* BUZZ_DATA_PROTO_INFO */
uint16_t version; /* Little Endian */
uint16_t max_chunk_size; /* Little Endian */
};
/* Payload für die Dateisystem-Informationen */
struct __attribute__((packed)) buzz_resp_fs_info
{
uint8_t data_type; /* BUZZ_DATA_FS_INFO */
uint32_t total_size; /* Little Endian */
uint32_t free_size; /* Little Endian */
uint8_t max_path_length; /* Maximale Pfadlänge (z.B. 32) */
uint8_t sys_path_length; /* Länge des System-Ordners (z.B. 2 für "/s") */
uint8_t audio_path_length; /* Länge des Audio-Ordners (z.B. 2 für "/a") */
uint8_t data[]; /* Pfadnamen */
};
/* Payload für das Credit-System (ACK) */
struct __attribute__((packed)) buzz_ack_payload
{
uint16_t credits; /* Little Endian */
};
/* Payload für einen einzelnen Verzeichniseintrag */
struct __attribute__((packed)) buzz_ls_entry_payload
{
uint8_t type; /* enum buzz_fs_entry_type */
uint32_t size; /* Little Endian */
uint8_t name_length;
char name[]; /* Variabler String ohne Null-Terminierung */
};
/* Payload für das Ende der Liste */
struct __attribute__((packed)) buzz_ls_end_payload
{
uint32_t total_entries; /* Little Endian */
};
/* Payload für FILE_START */
struct __attribute__((packed)) buzz_file_start_payload
{
uint32_t total_size; /* Little Endian */
};
/* Payload für FILE_END */
struct __attribute__((packed)) buzz_file_end_payload
{
uint32_t crc32; /* Little Endian */
};
/* --- System API --- */
/* Callback-Signatur für den Transport-Layer (BLE/UART) */
typedef int (*buzz_transport_reply_fn)(const uint8_t *data, uint16_t len);
/* Struktur für die interne Message Queue */
struct buzz_frame_msg
{
uint8_t *data_ptr;
uint16_t length;
buzz_transport_reply_fn reply_cb;
uint16_t max_payload; /* NEU: Maximales Limit für ausgehende Frames dieses Transports */
};
/* Allokation und Freigabe von Memory Slabs */
int buzz_proto_buf_alloc(uint8_t **buf);
void buzz_proto_buf_free(uint8_t **buf);
/* Übergabe eines empfangenen Frames an den Protokoll-Thread */
int buzz_proto_submit_frame(struct buzz_frame_msg *msg);
#endif /* BUZZ_PROTO_H */

View File

@@ -0,0 +1,619 @@
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/logging/log_ctrl.h>
#include <zephyr/fs/fs.h>
#include <zephyr/sys/crc.h>
#include <errno.h>
#include <stdlib.h>
#include "buzz_proto.h"
#include "fs_mgmt.h"
LOG_MODULE_REGISTER(buzz_proto, CONFIG_BUZZ_PROTO_LOG_LEVEL);
K_MEM_SLAB_DEFINE(buzz_proto_slabs, CONFIG_BUZZ_PROTO_SLAB_SIZE, CONFIG_BUZZ_PROTO_SLAB_COUNT, 4);
K_MSGQ_DEFINE(buzz_proto_msgq, sizeof(struct buzz_frame_msg), CONFIG_BUZZ_PROTO_MSGQ_SIZE, 4);
struct ls_state_t
{
bool active;
int credits;
uint32_t entries_sent;
uint32_t retry_counter;
struct fs_dir_t dir;
struct fs_dirent entry;
buzz_transport_reply_fn reply_cb;
};
static struct ls_state_t ls_state = {
.active = false,
.credits = 0,
.entries_sent = 0,
.retry_counter = 0,
.reply_cb = NULL,
};
struct get_file_state_t
{
bool active;
int credits;
uint32_t offset;
uint32_t retry_counter;
uint32_t crc32;
struct fs_file_t file;
buzz_transport_reply_fn reply_cb;
uint16_t max_payload;
};
static struct get_file_state_t get_file_state = {
.active = false,
.credits = 0,
.offset = 0,
.retry_counter = 0,
.crc32 = 0,
.reply_cb = NULL,
};
enum stream_state_t
{
STREAM_IDLE,
STREAM_LS,
STREAM_FILE_PUT,
STREAM_FILE_GET,
STREAM_FW_UPDATE,
};
static enum stream_state_t current_stream = STREAM_IDLE;
static char src_path[FS_MGMT_MAX_PATH_LENGTH], dst_path[FS_MGMT_MAX_PATH_LENGTH];
int buzz_proto_buf_alloc(uint8_t **buf)
{
return k_mem_slab_alloc(&buzz_proto_slabs, (void **)buf, K_NO_WAIT);
}
void buzz_proto_buf_free(uint8_t **buf)
{
if (buf && *buf)
{
k_mem_slab_free(&buzz_proto_slabs, (void **)*buf);
*buf = NULL;
}
}
int buzz_proto_submit_frame(struct buzz_frame_msg *msg)
{
return k_msgq_put(&buzz_proto_msgq, msg, K_NO_WAIT);
}
static void send_error_frame(struct buzz_frame_msg *msg, uint16_t error_code)
{
struct buzz_proto_header *hdr = (struct buzz_proto_header *)msg->data_ptr;
struct buzz_resp_error *err = (struct buzz_resp_error *)(msg->data_ptr + sizeof(*hdr));
hdr->frame_type = BUZZ_FRAME_ERROR;
hdr->payload_length = sys_cpu_to_le16(sizeof(struct buzz_resp_error));
err->error_code = sys_cpu_to_le16(error_code);
if (msg->reply_cb)
{
msg->reply_cb(msg->data_ptr, sizeof(*hdr) + sizeof(*err));
}
}
static void handle_proto_version_request(struct buzz_frame_msg *msg)
{
struct buzz_proto_header *hdr = (struct buzz_proto_header *)msg->data_ptr;
hdr->frame_type = BUZZ_FRAME_RESPONSE;
struct buzz_resp_proto_version *resp_data = (struct buzz_resp_proto_version *)(msg->data_ptr + sizeof(*hdr));
resp_data->data_type = BUZZ_DATA_PROTO_INFO;
resp_data->version = sys_cpu_to_le16(BUZZ_PROTO_VERSION);
resp_data->max_chunk_size = sys_cpu_to_le16(CONFIG_BUZZ_PROTO_SLAB_SIZE - sizeof(struct buzz_proto_header));
hdr->payload_length = sys_cpu_to_le16(sizeof(struct buzz_resp_proto_version));
uint16_t total_len = sizeof(struct buzz_proto_header) + sizeof(struct buzz_resp_proto_version);
if (msg->reply_cb)
{
msg->reply_cb(msg->data_ptr, total_len);
}
}
void handle_fs_info_request(struct buzz_frame_msg *msg)
{
struct buzz_proto_header *hdr = (struct buzz_proto_header *)msg->data_ptr;
struct fs_statvfs stat;
int rc = fs_mgmt_pm_statvfs(FS_AUDIO_PATH, &stat);
if (rc != 0)
{
LOG_ERR("Failed to statvfs audio path");
send_error_frame(msg, abs(rc));
return;
}
hdr->frame_type = BUZZ_FRAME_RESPONSE;
struct buzz_resp_fs_info *resp_data = (struct buzz_resp_fs_info *)(msg->data_ptr + sizeof(*hdr));
uint32_t block_size = stat.f_frsize;
uint32_t total_size = stat.f_blocks * block_size;
uint32_t free_size = stat.f_bfree * block_size;
LOG_DBG("FS Info: block_size=%u, total_size=%u, free_size=%u", block_size, total_size, free_size);
resp_data->data_type = BUZZ_DATA_FS_INFO;
resp_data->total_size = sys_cpu_to_le32(total_size);
resp_data->free_size = sys_cpu_to_le32(free_size);
resp_data->max_path_length = FS_MGMT_MAX_PATH_LENGTH;
resp_data->sys_path_length = strlen(FS_SYSTEM_PATH);
resp_data->audio_path_length = strlen(FS_AUDIO_PATH);
memcpy(resp_data->data, FS_SYSTEM_PATH, resp_data->sys_path_length);
memcpy(resp_data->data + resp_data->sys_path_length, FS_AUDIO_PATH, resp_data->audio_path_length);
uint16_t payload_length = sizeof(struct buzz_resp_fs_info) + resp_data->sys_path_length + resp_data->audio_path_length;
hdr->payload_length = sys_cpu_to_le16(payload_length);
uint16_t total_len = sizeof(struct buzz_proto_header) + payload_length;
if (msg->reply_cb)
{
msg->reply_cb(msg->data_ptr, total_len);
}
}
static void handle_ls_request(struct buzz_frame_msg *msg)
{
struct buzz_proto_header *hdr = (struct buzz_proto_header *)msg->data_ptr;
uint16_t payload_len = sys_le16_to_cpu(hdr->payload_length);
if (current_stream != STREAM_IDLE)
{
LOG_WRN("Stream active, rejecting LS request");
send_error_frame(msg, EBUSY);
return;
}
uint16_t path_len = payload_len - 1;
if (path_len >= sizeof(src_path))
{
LOG_ERR("Path too long for LS request");
send_error_frame(msg, ENAMETOOLONG);
return;
}
memcpy(src_path, msg->data_ptr + sizeof(*hdr) + 1, path_len);
src_path[path_len] = '\0';
int rc = fs_mgmt_pm_opendir(&ls_state.dir, src_path);
if (rc != 0)
{
LOG_ERR("Failed to open dir: %d", rc);
send_error_frame(msg, abs(rc));
return;
}
current_stream = STREAM_LS;
ls_state.active = true;
ls_state.credits = 0;
ls_state.entries_sent = 0;
ls_state.retry_counter = 0;
ls_state.reply_cb = msg->reply_cb;
LOG_DBG("Started LS stream for path '%s'", src_path);
hdr->frame_type = BUZZ_FRAME_LS_START;
hdr->payload_length = 0;
if (msg->reply_cb)
{
msg->reply_cb(msg->data_ptr, sizeof(*hdr));
}
}
static void handle_file_get_request(struct buzz_frame_msg *msg)
{
struct buzz_proto_header *hdr = (struct buzz_proto_header *)msg->data_ptr;
uint16_t payload_len = sys_le16_to_cpu(hdr->payload_length);
if (current_stream != STREAM_IDLE)
{
LOG_WRN("Stream active, rejecting FILE_GET request");
send_error_frame(msg, EBUSY);
return;
}
uint16_t path_len = payload_len - 1; // 1 Byte für data_type abziehen
if (path_len >= sizeof(src_path))
{
LOG_ERR("Path too long for FILE_GET request");
send_error_frame(msg, ENAMETOOLONG);
return;
}
memcpy(src_path, msg->data_ptr + sizeof(*hdr) + 1, path_len);
src_path[path_len] = '\0';
// 1. Datei-Größe ermitteln
struct fs_dirent entry;
if (fs_mgmt_pm_stat(src_path, &entry) != 0)
{
LOG_ERR("File not found: %s", src_path);
send_error_frame(msg, ENOENT);
return;
}
// 2. Datei öffnen
fs_file_t_init(&get_file_state.file);
int rc = fs_mgmt_pm_open(&get_file_state.file, src_path, FS_O_READ);
if (rc != 0)
{
LOG_ERR("Failed to open file: %d", rc);
send_error_frame(msg, abs(rc));
return;
}
// 3. State initialisieren
current_stream = STREAM_FILE_GET;
get_file_state.active = true;
get_file_state.credits = 0;
get_file_state.offset = 0;
get_file_state.crc32 = 0; // IEEE CRC32 Startwert
get_file_state.retry_counter = 0;
get_file_state.reply_cb = msg->reply_cb;
get_file_state.max_payload = msg->max_payload;
LOG_INF("Started FILE_GET stream for '%s' (%u bytes)", src_path, entry.size);
// 4. FILE_START Frame senden
hdr->frame_type = BUZZ_FRAME_FILE_START;
hdr->payload_length = sys_cpu_to_le16(sizeof(struct buzz_file_start_payload));
struct buzz_file_start_payload *start_pl = (struct buzz_file_start_payload *)(msg->data_ptr + sizeof(*hdr));
start_pl->total_size = sys_cpu_to_le32(entry.size);
if (msg->reply_cb)
{
int send_rc = msg->reply_cb(msg->data_ptr, sizeof(*hdr) + sizeof(*start_pl));
if (send_rc)
{
LOG_ERR("Failed to send FILE_START (err %d)", send_rc);
fs_mgmt_pm_close(&get_file_state.file);
get_file_state.active = false;
current_stream = STREAM_IDLE;
return;
}
}
}
static void process_file_get_stream(void)
{
uint8_t *buf = NULL;
if (buzz_proto_buf_alloc(&buf) != 0)
{
return; // Puffer voll, im nächsten Zyklus nochmal probieren
}
struct buzz_proto_header *hdr = (struct buzz_proto_header *)buf;
uint8_t *payload_ptr = buf + sizeof(*hdr);
if (get_file_state.max_payload <= sizeof(*hdr))
{
struct buzz_frame_msg err_msg = {
.data_ptr = buf,
.reply_cb = get_file_state.reply_cb,
.max_payload = get_file_state.max_payload,
};
send_error_frame(&err_msg, EMSGSIZE);
fs_mgmt_pm_close(&get_file_state.file);
get_file_state.active = false;
current_stream = STREAM_IDLE;
buzz_proto_buf_free(&buf);
LOG_ERR("Invalid max payload for FILE_GET: %u", get_file_state.max_payload);
return;
}
// Chunk Size berechnen
uint16_t max_chunk_size = MIN(
get_file_state.max_payload - sizeof(*hdr),
CONFIG_BUZZ_PROTO_SLAB_SIZE - sizeof(struct buzz_proto_header));
ssize_t read_len = fs_read(&get_file_state.file, payload_ptr, max_chunk_size);
if (read_len < 0)
{
// Lesefehler
struct buzz_frame_msg err_msg = {.data_ptr = buf, .reply_cb = get_file_state.reply_cb, .max_payload = get_file_state.max_payload};
send_error_frame(&err_msg, EIO);
fs_mgmt_pm_close(&get_file_state.file);
get_file_state.active = false;
current_stream = STREAM_IDLE;
buzz_proto_buf_free(&buf);
LOG_ERR("Error reading file: %d", (int)read_len);
return;
}
if (read_len == 0)
{
// EOF erreicht -> FILE_END senden
hdr->frame_type = BUZZ_FRAME_FILE_END;
hdr->payload_length = sys_cpu_to_le16(sizeof(struct buzz_file_end_payload));
struct buzz_file_end_payload *end_pl = (struct buzz_file_end_payload *)payload_ptr;
end_pl->crc32 = sys_cpu_to_le32(get_file_state.crc32);
if (get_file_state.reply_cb)
{
int send_rc = get_file_state.reply_cb(buf, sizeof(*hdr) + sizeof(*end_pl));
if (send_rc)
{
LOG_WRN("Failed to send FILE_END (err %d)", send_rc);
}
}
fs_mgmt_pm_close(&get_file_state.file);
get_file_state.active = false;
current_stream = STREAM_IDLE;
buzz_proto_buf_free(&buf);
LOG_INF("FILE_GET stream ended. CRC32: 0x%08X", get_file_state.crc32);
return;
}
// Daten gelesen -> CRC aktualisieren und Chunk senden
get_file_state.crc32 = crc32_ieee_update(get_file_state.crc32, payload_ptr, read_len);
get_file_state.offset += read_len;
hdr->frame_type = BUZZ_FRAME_FILE_CHUNK;
hdr->payload_length = sys_cpu_to_le16(read_len);
if (get_file_state.reply_cb)
{
int send_rc = get_file_state.reply_cb(buf, sizeof(*hdr) + read_len);
if (send_rc)
{
LOG_ERR("Failed to send FILE_CHUNK (err %d)", send_rc);
fs_mgmt_pm_close(&get_file_state.file);
get_file_state.active = false;
current_stream = STREAM_IDLE;
buzz_proto_buf_free(&buf);
return;
}
}
get_file_state.credits--;
get_file_state.retry_counter = 0;
buzz_proto_buf_free(&buf);
}
static void handle_request(struct buzz_frame_msg *msg)
{
struct buzz_proto_header *hdr = (struct buzz_proto_header *)msg->data_ptr;
uint16_t payload_len = sys_le16_to_cpu(hdr->payload_length);
if (payload_len < sizeof(struct buzz_request_payload))
{
LOG_WRN("Invalid request length");
send_error_frame(msg, EINVAL);
return;
}
struct buzz_request_payload *req_data = (struct buzz_request_payload *)(msg->data_ptr + sizeof(*hdr));
switch (req_data->data_type)
{
case BUZZ_DATA_PROTO_INFO:
LOG_DBG("Received Proto Version Request");
handle_proto_version_request(msg);
break;
case BUZZ_DATA_FS_INFO:
LOG_DBG("Received FS Info Request");
handle_fs_info_request(msg);
break;
case BUZZ_DATA_LS:
LOG_DBG("Received LS Request");
handle_ls_request(msg);
break;
case BUZZ_DATA_FILE_GET:
LOG_DBG("Received FILE_GET Request");
handle_file_get_request(msg);
break;
default:
LOG_WRN("Unknown request data_type: 0x%02x", req_data->data_type);
send_error_frame(msg, EINVAL);
break;
}
}
static void process_ls_stream(void)
{
uint8_t *buf = NULL;
if (buzz_proto_buf_alloc(&buf) != 0)
{
return; // Nächster Versuch im nächsten Zyklus
}
int rc = fs_readdir(&ls_state.dir, &ls_state.entry);
if (rc < 0)
{
struct buzz_frame_msg err_msg = {.data_ptr = buf, .reply_cb = ls_state.reply_cb};
send_error_frame(&err_msg, abs(rc));
fs_mgmt_pm_closedir(&ls_state.dir);
ls_state.active = false;
current_stream = STREAM_IDLE;
buzz_proto_buf_free(&buf);
LOG_ERR("Error reading directory: %d", rc);
return;
}
struct buzz_proto_header *hdr = (struct buzz_proto_header *)buf;
if (ls_state.entry.name[0] == 0)
{
hdr->frame_type = BUZZ_FRAME_LS_END;
hdr->payload_length = sys_cpu_to_le16(sizeof(struct buzz_ls_end_payload));
struct buzz_ls_end_payload *end_pl = (struct buzz_ls_end_payload *)(buf + sizeof(*hdr));
end_pl->total_entries = sys_cpu_to_le32(ls_state.entries_sent);
if (ls_state.reply_cb)
{
ls_state.reply_cb(buf, sizeof(*hdr) + sizeof(*end_pl));
}
fs_mgmt_pm_closedir(&ls_state.dir);
ls_state.active = false;
current_stream = STREAM_IDLE;
buzz_proto_buf_free(&buf);
LOG_DBG("LS stream ended. Total entries sent: %u", ls_state.entries_sent);
return;
}
hdr->frame_type = BUZZ_FRAME_LS_ENTRY;
struct buzz_ls_entry_payload *entry_pl = (struct buzz_ls_entry_payload *)(buf + sizeof(*hdr));
entry_pl->type = (ls_state.entry.type == FS_DIR_ENTRY_DIR) ? BUZZ_FS_ENTRY_DIR : BUZZ_FS_ENTRY_FILE;
entry_pl->size = sys_cpu_to_le32(ls_state.entry.size);
size_t name_len = strlen(ls_state.entry.name);
entry_pl->name_length = (uint8_t)name_len;
memcpy(entry_pl->name, ls_state.entry.name, name_len);
uint16_t payload_len = sizeof(*entry_pl) + name_len;
hdr->payload_length = sys_cpu_to_le16(payload_len);
if (ls_state.reply_cb)
{
ls_state.reply_cb(buf, sizeof(*hdr) + payload_len);
}
ls_state.credits--;
ls_state.entries_sent++;
ls_state.retry_counter = 0;
buzz_proto_buf_free(&buf);
}
static void buzz_proto_thread_fn(void *p1, void *p2, void *p3)
{
struct buzz_frame_msg msg;
struct buzz_proto_header *hdr;
LOG_INF("Buzz Protocol Thread started");
while (1)
{
k_timeout_t wait_time = K_FOREVER;
if ((current_stream == STREAM_LS && ls_state.active && ls_state.credits > 0) ||
(current_stream == STREAM_FILE_GET && get_file_state.active && get_file_state.credits > 0))
{
wait_time = K_NO_WAIT;
}
else if (current_stream != STREAM_IDLE)
{
wait_time = K_MSEC(500); // Watchdog Timeout
}
int q_res = k_msgq_get(&buzz_proto_msgq, &msg, wait_time);
/* 1. Eingehende Nachrichten verarbeiten */
if (q_res == 0)
{
if (msg.length < sizeof(struct buzz_proto_header))
{
LOG_WRN("Received frame too short");
buzz_proto_buf_free(&msg.data_ptr);
continue;
}
hdr = (struct buzz_proto_header *)msg.data_ptr;
switch (hdr->frame_type)
{
case BUZZ_FRAME_REQUEST:
handle_request(&msg);
buzz_proto_buf_free(&msg.data_ptr);
break;
case BUZZ_FRAME_ACK:
if (current_stream == STREAM_LS && msg.length >= sizeof(*hdr) + sizeof(struct buzz_ack_payload))
{
struct buzz_ack_payload *ack = (struct buzz_ack_payload *)(msg.data_ptr + sizeof(*hdr));
// Absolute Credits übernehmen, wie von dir vorgeschlagen
ls_state.credits = sys_le16_to_cpu(ack->credits);
ls_state.retry_counter = 0;
LOG_DBG("Got %u credits", ls_state.credits);
}
else if (current_stream == STREAM_FILE_GET && msg.length >= sizeof(*hdr) + sizeof(struct buzz_ack_payload))
{
struct buzz_ack_payload *ack = (struct buzz_ack_payload *)(msg.data_ptr + sizeof(*hdr));
get_file_state.credits = sys_le16_to_cpu(ack->credits);
get_file_state.retry_counter = 0;
}
buzz_proto_buf_free(&msg.data_ptr);
break;
case BUZZ_FRAME_FILE_CHUNK:
send_error_frame(&msg, ENOSYS);
buzz_proto_buf_free(&msg.data_ptr);
break;
case BUZZ_FRAME_FW_CHUNK:
send_error_frame(&msg, ENOSYS);
buzz_proto_buf_free(&msg.data_ptr);
break;
case BUZZ_FRAME_LS_ENTRY:
send_error_frame(&msg, ENOSYS);
buzz_proto_buf_free(&msg.data_ptr);
break;
default:
LOG_WRN("Unhandled frame type: 0x%02x", hdr->frame_type);
send_error_frame(&msg, EPROTO);
buzz_proto_buf_free(&msg.data_ptr);
break;
}
}
if (current_stream == STREAM_LS && ls_state.active)
{
if (ls_state.credits > 0)
{
process_ls_stream();
}
else if (q_res == -EAGAIN)
{
// Watchdog: Queue hat 500ms blockiert, weil keine Credits (ACK) kamen
ls_state.retry_counter++;
if (ls_state.retry_counter > 5)
{
LOG_WRN("LS timeout waiting for ACK");
fs_mgmt_pm_closedir(&ls_state.dir);
ls_state.active = false;
current_stream = STREAM_IDLE;
}
}
}
else if (current_stream == STREAM_FILE_GET && get_file_state.active)
{
if (get_file_state.credits > 0)
{
process_file_get_stream();
}
else if (q_res == -EAGAIN)
{
get_file_state.retry_counter++;
if (get_file_state.retry_counter > 5)
{
LOG_WRN("FILE_GET timeout waiting for ACK");
fs_close(&get_file_state.file);
get_file_state.active = false;
current_stream = STREAM_IDLE;
}
}
}
}
}
K_THREAD_DEFINE(buzz_proto_thread, CONFIG_BUZZ_PROT_THREAD_STACK_SIZE, buzz_proto_thread_fn, NULL, NULL, NULL, CONFIG_BUZZ_PROTO_THREAD_PRIORITY, 0, 0);