#pragma once #include #include #include #include "esp_err.h" #ifdef __cplusplus extern "C" { #endif #define SESSION_BROKER_MAX_CLIENTS 8U #define SESSION_BROKER_CLIENT_NAME_MAX 23U #define SESSION_BROKER_OUTPUT_SIZE 4096U #define SESSION_BROKER_EVENT_QUEUE_LENGTH 16U typedef uint32_t session_broker_client_id_t; /* ID zero is reserved for "no client" and, specifically, "no writer". */ #define SESSION_BROKER_NO_CLIENT ((session_broker_client_id_t)0U) typedef enum { SESSION_BROKER_CLIENT_CONSOLE = 0, SESSION_BROKER_CLIENT_USB, SESSION_BROKER_CLIENT_WEB, SESSION_BROKER_CLIENT_SSH, SESSION_BROKER_CLIENT_INTERNAL, } session_broker_client_type_t; typedef enum { SESSION_BROKER_EVENT_CONNECT = 0, SESSION_BROKER_EVENT_DISCONNECT, SESSION_BROKER_EVENT_WRITER_GRANTED, SESSION_BROKER_EVENT_WRITER_RELEASED, SESSION_BROKER_EVENT_WRITER_REVOKED, SESSION_BROKER_EVENT_WRITER_DENIED, } session_broker_event_type_t; /* * Events contain no pointers, so transports can encode them without lifetime * concerns. sequence is broker-global and strictly increases per event. * client_id identifies the subject; writer_id is the writer after the event. */ typedef struct { uint64_t sequence; session_broker_event_type_t type; session_broker_client_id_t client_id; session_broker_client_id_t writer_id; } session_broker_event_t; typedef struct { /* UART bytes considered for delivery while this client was connected. */ uint64_t uart_rx_bytes; uint64_t output_queued_bytes; uint64_t output_read_bytes; uint64_t output_dropped_bytes; uint64_t tx_accepted_bytes; uint64_t tx_rejected_bytes; uint64_t connections; uint64_t writer_requests; uint64_t writer_grants; uint64_t writer_releases; uint64_t writer_revocations; uint64_t writer_denials; uint64_t writer_changes; uint64_t events_queued; uint64_t events_popped; uint64_t event_drops; } session_broker_client_counters_t; typedef struct { uint64_t uart_rx_bytes; /* UART RX drained when there were no connected observers. */ uint64_t unobserved_rx_bytes; /* Queue/read/drop totals count one copy per client observer. */ uint64_t output_queued_bytes; uint64_t output_read_bytes; uint64_t output_dropped_bytes; uint64_t tx_accepted_bytes; uint64_t tx_rejected_bytes; uint64_t connections; uint64_t disconnections; uint64_t writer_requests; uint64_t writer_grants; uint64_t writer_releases; uint64_t writer_revocations; uint64_t writer_denials; uint64_t writer_changes; uint64_t events_generated; uint64_t events_queued; uint64_t events_popped; uint64_t event_drops; } session_broker_global_counters_t; typedef struct { session_broker_client_id_t id; session_broker_client_type_t type; char name[SESSION_BROKER_CLIENT_NAME_MAX + 1U]; bool is_writer; size_t output_bytes_pending; uint32_t events_pending; session_broker_client_counters_t counters; } session_broker_client_snapshot_t; typedef struct { session_broker_client_id_t writer_id; uint32_t connected_clients; uint64_t latest_event_sequence; session_broker_global_counters_t counters; } session_broker_global_snapshot_t; /* * Allocates all eight output streams and event queues, then starts the * permanent broker task. The serial service must already be initialized * before the first client connects. */ esp_err_t session_broker_init(void); esp_err_t session_broker_connect(session_broker_client_type_t type, const char *name, session_broker_client_id_t *client_id); esp_err_t session_broker_disconnect(session_broker_client_id_t client_id); /* * There is exactly one writer lease. Requests are granted only while idle; * a competing request emits WRITER_DENIED. Force with ID zero revokes the * current writer without assigning a replacement. */ esp_err_t session_broker_request_writer(session_broker_client_id_t client_id); esp_err_t session_broker_release_writer(session_broker_client_id_t client_id); esp_err_t session_broker_force_writer(session_broker_client_id_t client_id); /* Revoke only if the expected client still owns the writer lease. */ esp_err_t session_broker_force_release_writer(session_broker_client_id_t expected_writer_id); session_broker_client_id_t session_broker_get_writer_id(void); /* * Binary-transparent, zero-time data operations. write is accepted only from * the current writer. read has one logical caller per connected transport. * Partial transfers are normal and are reported through the output count. */ esp_err_t session_broker_write(session_broker_client_id_t client_id, const uint8_t *data, size_t size, size_t *accepted); esp_err_t session_broker_read(session_broker_client_id_t client_id, uint8_t *data, size_t size, size_t *received); esp_err_t session_broker_pop_event(session_broker_client_id_t client_id, session_broker_event_t *event); esp_err_t session_broker_get_client_snapshot(session_broker_client_id_t client_id, session_broker_client_snapshot_t *snapshot); esp_err_t session_broker_get_global_snapshot(session_broker_global_snapshot_t *snapshot); /* Returns the number copied. Pass NULL with capacity zero to count clients. */ size_t session_broker_list_clients(session_broker_client_snapshot_t *clients, size_t capacity); /* Counter clearing does not reset client IDs, queued data, or event sequence. */ esp_err_t session_broker_clear_counters(void); esp_err_t session_broker_clear_client_counters(session_broker_client_id_t client_id); #ifdef __cplusplus } #endif