elemes/velxio-deployer-firmware/main/serial_bridge.c

115 lines
2.8 KiB
C

#include <string.h>
#include "esp_log.h"
#include "esp_timer.h"
#include "serial_bridge.h"
#include "ble_service.h"
#include "usb_host.h"
static const char *TAG = "SERIAL_BRIDGE";
static bool active = false;
static int64_t last_flush_time = 0;
static int notify_count = 0;
static int64_t rate_window_start = 0;
#define BRIDGE_BUF_SIZE 240
#define MAX_NOTIFY_RATE 20
#define RATE_WINDOW_MS 1000
#define THROTTLE_INTERVAL_MS 50
#define BUFFER_FLUSH_MS 500
static uint8_t bridge_buf[BRIDGE_BUF_SIZE];
static size_t bridge_buf_len = 0;
void serial_bridge_init(void)
{
active = false;
bridge_buf_len = 0;
last_flush_time = 0;
notify_count = 0;
rate_window_start = 0;
ESP_LOGI(TAG, "Serial bridge initialized");
}
void serial_bridge_start(void)
{
active = true;
bridge_buf_len = 0;
last_flush_time = esp_timer_get_time() / 1000;
notify_count = 0;
rate_window_start = esp_timer_get_time() / 1000;
ESP_LOGI(TAG, "Serial bridge started");
}
void serial_bridge_stop(void)
{
/* Flush any remaining buffered data before stopping. */
if (active && bridge_buf_len > 0) {
ble_service_send_notify_serial(bridge_buf, bridge_buf_len);
bridge_buf_len = 0;
}
active = false;
ESP_LOGI(TAG, "Serial bridge stopped");
}
bool serial_bridge_is_active(void)
{
return active;
}
void serial_bridge_on_ble_write(uint8_t *data, size_t len)
{
if (!active) return;
usb_host_write_cdc(data, len);
}
void serial_bridge_on_usb_data(uint8_t *data, size_t len)
{
if (!active) return;
/* Large packet: flush buffer first, then send directly. */
size_t remaining = BRIDGE_BUF_SIZE - bridge_buf_len;
if (len >= BRIDGE_BUF_SIZE) {
if (bridge_buf_len > 0) {
ble_service_send_notify_serial(bridge_buf, bridge_buf_len);
bridge_buf_len = 0;
}
ble_service_send_notify_serial(data, len);
return;
}
/* Buffer nearly full: flush first. */
if (len > remaining) {
ble_service_send_notify_serial(bridge_buf, bridge_buf_len);
bridge_buf_len = 0;
}
memcpy(bridge_buf + bridge_buf_len, data, len);
bridge_buf_len += len;
}
void serial_bridge_tick(void)
{
if (!active || bridge_buf_len == 0) return;
int64_t now = esp_timer_get_time() / 1000;
/* Reset rate counter every second. */
if (now - rate_window_start >= RATE_WINDOW_MS) {
rate_window_start = now;
notify_count = 0;
}
int64_t since_flush = now - last_flush_time;
bool time_to_flush = (since_flush >= THROTTLE_INTERVAL_MS) &&
(notify_count < MAX_NOTIFY_RATE);
bool stale = since_flush >= BUFFER_FLUSH_MS;
if (time_to_flush || stale) {
ble_service_send_notify_serial(bridge_buf, bridge_buf_len);
bridge_buf_len = 0;
last_flush_time = now;
notify_count++;
}
}