You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

179 lines
5.8 KiB

/**
* @file etcp_api.c
* @brief Реализация API для приёма-передачи пакетов через ETCP
*/
#include "etcp_api.h"
#include "etcp.h"
#include "pkt_normalizer.h"
#include "../lib/debug_config.h"
#include <string.h>
#define DEBUG_CATEGORY_ETCP_API 1
#define ETCP_MAX_BINDINGS 256 /**< Максимальное количество bindings (по одному на каждый ID 0-255) */
/**
* @brief Структура binding для ID
*/
struct ETCP_BINDING {
etcp_recv_fn callback; /**< Коллбэк для обработки пакетов */
uint8_t active; /**< Флаг активности binding */
};
// Таблица bindings (индекс = ID пакета)
static struct ETCP_BINDING g_bindings[ETCP_MAX_BINDINGS];
static int g_api_initialized = 0;
void etcp_api_init(void) {
if (g_api_initialized) {
return;
}
memset(g_bindings, 0, sizeof(g_bindings));
g_api_initialized = 1;
DEBUG_INFO(DEBUG_CATEGORY_ETCP_API, "ETCP API initialized");
}
void etcp_api_deinit(void) {
if (!g_api_initialized) {
return;
}
memset(g_bindings, 0, sizeof(g_bindings));
g_api_initialized = 0;
DEBUG_INFO(DEBUG_CATEGORY_ETCP_API, "ETCP API deinitialized");
}
int etcp_bind(uint8_t id, etcp_recv_fn callback) {
if (!g_api_initialized) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_bind: API not initialized");
return -1;
}
if (!callback) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_bind: NULL callback for id=%u", id);
return -1;
}
if (g_bindings[id].active) {
DEBUG_WARN(DEBUG_CATEGORY_ETCP_API, "etcp_bind: ID %u already bound, overwriting", id);
}
g_bindings[id].callback = callback;
g_bindings[id].active = 1;
DEBUG_INFO(DEBUG_CATEGORY_ETCP_API, "etcp_bind: Bound ID %u to callback %p", id, (void*)callback);
return 0;
}
int etcp_unbind(uint8_t id) {
if (!g_api_initialized) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_unbind: API not initialized");
return -1;
}
if (!g_bindings[id].active) {
DEBUG_WARN(DEBUG_CATEGORY_ETCP_API, "etcp_unbind: ID %u not bound", id);
return -1;
}
g_bindings[id].callback = NULL;
g_bindings[id].active = 0;
DEBUG_INFO(DEBUG_CATEGORY_ETCP_API, "etcp_unbind: Unbound ID %u", id);
return 0;
}
int etcp_send(struct ETCP_CONN* conn, struct ll_entry* entry) {
if (!conn) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_send: NULL connection");
return -1;
}
if (!entry) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_send: NULL entry");
return -1;
}
if (!conn->normalizer) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_send: Connection has no normalizer");
return -1;
}
struct PKTNORM* pn = conn->normalizer;
if (!pn->input) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_send: Normalizer has no input queue");
return -1;
}
// Помещаем entry в очередь input normalizer
// queue_data_put забирает ownership entry
int result = queue_data_put(pn->input, entry, 0);
if (result != 0) {
DEBUG_WARN(DEBUG_CATEGORY_ETCP_API, "etcp_send: queue_data_put failed (queue full?)");
return -1;
}
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP_API, "etcp_send: Packet queued for sending");
return 0;
}
void etcp_recv(struct ll_queue* queue, void* arg) {
struct ETCP_CONN* conn = (struct ETCP_CONN*)arg;
if (!queue || !conn) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_recv: Invalid arguments (queue=%p, conn=%p)",
(void*)queue, (void*)conn);
return;
}
// Получаем элемент из очереди
struct ll_entry* entry = queue_data_get(queue);
if (!entry) {
// Очередь пуста - это нормально, просто возобновляем коллбэк
queue_resume_callback(queue);
return;
}
// Проверяем что есть данные
if (!entry->dgram || entry->len == 0) {
DEBUG_WARN(DEBUG_CATEGORY_ETCP_API, "etcp_recv: Empty packet received");
queue_entry_free(entry);
queue_dgram_free(entry);
queue_resume_callback(queue);
return;
}
// Получаем ID пакета (первый байт кодограммы)
uint8_t id = entry->dgram[0];
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP_API, "etcp_recv: Received packet with ID %u from conn %p",
id, (void*)conn);
// Ищем binding для этого ID
if (id < ETCP_MAX_BINDINGS && g_bindings[id].active && g_bindings[id].callback) {
// Вызываем коллбэк
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP_API, "etcp_recv: Delivering packet ID %u to callback %p",
id, (void*)g_bindings[id].callback);
g_bindings[id].callback(conn, entry);
} else {
// Нет binding для этого ID - по умолчанию считаем что это данные (ID=0)
if (g_bindings[0].active && g_bindings[0].callback) {
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP_API, "etcp_recv: No binding for ID %u, routing to default (ID=0)", id);
g_bindings[0].callback(conn, entry);
} else {
// Нет default binding - освобождаем пакет
DEBUG_WARN(DEBUG_CATEGORY_ETCP_API, "etcp_recv: No binding for ID %u and no default handler, dropping packet", id);
queue_entry_free(entry);
queue_dgram_free(entry);
}
}
// Возобновляем коллбэк для получения следующего пакета
queue_resume_callback(queue);
}