Add broker and web throughput diagnostics
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
#pragma once
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
typedef int esp_err_t;
|
||||
#define ESP_OK 0
|
||||
#define ESP_ERR_INVALID_STATE 1
|
||||
#define ESP_ERR_INVALID_ARG 2
|
||||
#define ESP_ERR_NO_MEM 3
|
||||
#define ESP_ERR_NOT_FOUND 4
|
||||
#define ESP_ERR_TIMEOUT 5
|
||||
static const char *esp_err_to_name(esp_err_t e) { (void)e; return "fake-error"; }
|
||||
#define MALLOC_CAP_SPIRAM 1
|
||||
#define MALLOC_CAP_8BIT 2
|
||||
#define MALLOC_CAP_INTERNAL 4
|
||||
static size_t allocations;
|
||||
static void *heap_caps_calloc_prefer(size_t n, size_t s, int choices, ...) {
|
||||
(void)choices; ++allocations; return calloc(n, s);
|
||||
}
|
||||
#define heap_caps_free free
|
||||
|
||||
typedef unsigned TickType_t;
|
||||
typedef unsigned UBaseType_t;
|
||||
#define pdTRUE 1
|
||||
#define pdPASS 1
|
||||
#define portMAX_DELAY UINT32_MAX
|
||||
#define pdMS_TO_TICKS(ms) (ms)
|
||||
static int mutex;
|
||||
typedef int *SemaphoreHandle_t;
|
||||
static SemaphoreHandle_t xSemaphoreCreateMutex(void) { return &mutex; }
|
||||
static int xSemaphoreTake(SemaphoreHandle_t m, TickType_t ticks) {
|
||||
if (*m) { assert(ticks == 0); return 0; } *m = 1; return pdTRUE;
|
||||
}
|
||||
static void xSemaphoreGive(SemaphoreHandle_t m) { assert(*m); *m = 0; }
|
||||
static void vSemaphoreDelete(SemaphoreHandle_t m) { assert(!*m); }
|
||||
|
||||
typedef struct { uint8_t *data; size_t capacity, used; } StaticStreamBuffer_t;
|
||||
typedef StaticStreamBuffer_t *StreamBufferHandle_t;
|
||||
static StreamBufferHandle_t xStreamBufferCreateStatic(size_t size, size_t trigger,
|
||||
uint8_t *data, StaticStreamBuffer_t *s) {
|
||||
assert(trigger == 1); *s = (StaticStreamBuffer_t){data, size - 1, 0}; return s;
|
||||
}
|
||||
static size_t xStreamBufferBytesAvailable(StreamBufferHandle_t s) {
|
||||
assert(mutex); return s->used;
|
||||
}
|
||||
static size_t xStreamBufferSend(StreamBufferHandle_t s, const void *data, size_t size, TickType_t ticks) {
|
||||
assert(mutex && ticks == 0);
|
||||
if (size > s->capacity - s->used) size = s->capacity - s->used;
|
||||
memcpy(s->data + s->used, data, size); s->used += size; return size;
|
||||
}
|
||||
static size_t xStreamBufferReceive(StreamBufferHandle_t s, void *data, size_t size, TickType_t ticks) {
|
||||
assert(mutex && ticks == 0);
|
||||
if (size > s->used) size = s->used;
|
||||
memcpy(data, s->data, size); s->used -= size;
|
||||
memmove(s->data, s->data + size, s->used); return size;
|
||||
}
|
||||
static void xStreamBufferReset(StreamBufferHandle_t s) { assert(mutex); s->used = 0; }
|
||||
static void vStreamBufferDelete(StreamBufferHandle_t s) { (void)s; }
|
||||
|
||||
typedef struct { uint8_t *data; size_t capacity, item_size, used; } StaticQueue_t;
|
||||
typedef StaticQueue_t *QueueHandle_t;
|
||||
static QueueHandle_t xQueueCreateStatic(size_t capacity, size_t size, uint8_t *data, StaticQueue_t *q) {
|
||||
*q = (StaticQueue_t){data, capacity, size, 0}; return q;
|
||||
}
|
||||
static int xQueueSend(QueueHandle_t q, const void *item, TickType_t ticks) {
|
||||
assert(mutex && ticks == 0); if (q->used == q->capacity) return 0;
|
||||
memcpy(q->data + q->used++ * q->item_size, item, q->item_size); return pdTRUE;
|
||||
}
|
||||
static int xQueueReceive(QueueHandle_t q, void *item, TickType_t ticks) {
|
||||
assert(mutex && ticks == 0); if (!q->used) return 0;
|
||||
memcpy(item, q->data, q->item_size); --q->used;
|
||||
memmove(q->data, q->data + q->item_size, q->used * q->item_size); return pdTRUE;
|
||||
}
|
||||
static UBaseType_t uxQueueMessagesWaiting(QueueHandle_t q) { assert(mutex); return q->used; }
|
||||
static void xQueueReset(QueueHandle_t q) { assert(mutex); q->used = 0; }
|
||||
static void vQueueDelete(QueueHandle_t q) { (void)q; }
|
||||
|
||||
typedef void *TaskHandle_t;
|
||||
static void (*task_entry)(void *);
|
||||
static jmp_buf task_exit;
|
||||
static const uint8_t *serial_input;
|
||||
static size_t serial_remaining;
|
||||
static int xTaskCreate(void (*entry)(void *), const char *name, unsigned stack,
|
||||
void *context, unsigned priority, TaskHandle_t *handle) {
|
||||
(void)name; (void)stack; (void)context; (void)priority;
|
||||
task_entry = entry; *handle = &mutex; return pdPASS;
|
||||
}
|
||||
static void vTaskDelay(TickType_t ticks) {
|
||||
assert(!mutex && ticks > 0); if (!serial_remaining) longjmp(task_exit, 1);
|
||||
}
|
||||
static size_t serial_service_read(uint8_t *data, size_t size) {
|
||||
assert(mutex); if (size > serial_remaining) size = serial_remaining;
|
||||
memcpy(data, serial_input, size); serial_input += size; serial_remaining -= size; return size;
|
||||
}
|
||||
static size_t serial_service_write(const uint8_t *data, size_t size) { (void)data; assert(mutex); return size; }
|
||||
static esp_err_t serial_service_set_session_active(bool active) { (void)active; assert(mutex); return ESP_OK; }
|
||||
|
||||
typedef struct {
|
||||
const char *command, *help, *hint;
|
||||
int (*func)(int, char **);
|
||||
void *argtable;
|
||||
} esp_console_cmd_t;
|
||||
static int (*registered_command)(int, char **);
|
||||
static esp_err_t esp_console_cmd_register(const esp_console_cmd_t *cmd) {
|
||||
registered_command = cmd->func; return ESP_OK;
|
||||
}
|
||||
static char console_output[16384];
|
||||
static size_t console_used;
|
||||
static int capture_printf(const char *format, ...) {
|
||||
/* Console formatting must happen after releasing the broker mutex. */
|
||||
assert(!mutex);
|
||||
va_list args; va_start(args, format);
|
||||
int n = vsnprintf(console_output + console_used, sizeof(console_output) - console_used, format, args);
|
||||
va_end(args); assert(n >= 0 && (size_t)n < sizeof(console_output) - console_used);
|
||||
console_used += (size_t)n; return n;
|
||||
}
|
||||
Reference in New Issue
Block a user