Choose buffer size/count to maintain packet rate to WS client at different sample rates

This commit is contained in:
Matt
2025-12-13 11:21:09 +00:00
parent 74dd3646b5
commit 33f3360a4b
2 changed files with 52 additions and 18 deletions

View File

@@ -33,7 +33,7 @@
.controls { .controls {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(8em, 1fr));
gap: 15px; gap: 15px;
} }
@@ -44,9 +44,13 @@
color: #bbb; color: #bbb;
} }
label {
width: 8em;
}
input, input,
select { select {
width: 80%; width: 6em;
padding: 8px; padding: 8px;
background: #3d3d3d; background: #3d3d3d;
border: 1px solid #555; border: 1px solid #555;
@@ -108,11 +112,12 @@
} }
#resetBtn { #resetBtn {
background:#ef4444; background: #222;
color:#fff; color: #e66;
padding:4px 8px; border: 1px solid;
font-size: 0.8rem; font-size: 0.8rem;
height: 4em; height: 4em;
width: 6em;
} }
</style> </style>
</head> </head>
@@ -139,7 +144,7 @@
<label>Sample Rate (Hz)</label> <label>Sample Rate (Hz)</label>
<input type="number" id="sampleRate" value="10000" min="1" max="83333"> <input type="number" id="sampleRate" value="10000" min="1" max="83333">
</div> </div>
<div> <div style="display: none;">
<label>Bit Width</label> <label>Bit Width</label>
<select id="bitWidth"> <select id="bitWidth">
<option value="12" selected>12-bit</option> <option value="12" selected>12-bit</option>
@@ -157,14 +162,13 @@
<option value="3" selected>11 dB</option> <option value="3" selected>11 dB</option>
</select> </select>
</div> </div>
<div style="display: flex; align-items: center; gap: 10px;"> <div>
<div> <div>
<label>Test Hz</label> <label>Test Hz</label>
<input type="number" id="testHz" value="100" min="1" max="10000"> <input type="number" id="testHz" value="100" min="1" max="10000">
</div> </div>
<button id="resetBtn">Reset
</button>
</div> </div>
<button id="resetBtn">Reset</button>
</form> </form>
</div> </div>

View File

@@ -82,6 +82,25 @@ static void continuous_adc_init(adc_channel_t *channel, uint8_t channel_num,
adc_continuous_handle_t *out_handle); adc_continuous_handle_t *out_handle);
static esp_err_t ws_handler(httpd_req_t *req); static esp_err_t ws_handler(httpd_req_t *req);
// Forward declarations
static void wifi_init_sta(void);
static void continuous_adc_init(adc_channel_t *channel, uint8_t channel_num,
adc_continuous_handle_t *out_handle);
static esp_err_t ws_handler(httpd_req_t *req);
// Helper to calculate optimal buffer size (approx 50ms latency, max 4096, aligned to 4)
static uint32_t get_optimal_buffer_size(uint32_t sample_rate) {
uint32_t bytes_per_sec = sample_rate * sizeof(adc_digi_output_data_t);
uint32_t target_size = bytes_per_sec / 50; // 20ms (50Hz)
// Clamp to min/max
if (target_size < 128) target_size = 128;
if (target_size > ADC_READ_LEN) target_size = ADC_READ_LEN;
// Align to 4 bytes
return (target_size + 3) & ~3;
}
/* /*
* Task to read from ADC Continuous driver * Task to read from ADC Continuous driver
*/ */
@@ -134,7 +153,7 @@ static void adc_read_task(void *arg) {
s_reconfig_needed = false; s_reconfig_needed = false;
} }
ret = adc_continuous_read(adc_handle, result, ADC_READ_LEN, &ret_num, 0); ret = adc_continuous_read(adc_handle, result, get_optimal_buffer_size(s_sample_rate), &ret_num, 0);
if (ret == ESP_OK) { if (ret == ESP_OK) {
// ESP_LOGI(TAG, "ret is %x, ret_num is %"PRIu32" bytes", ret, ret_num); // ESP_LOGI(TAG, "ret is %x, ret_num is %"PRIu32" bytes", ret, ret_num);
@@ -172,11 +191,12 @@ static void adc_read_task(void *arg) {
// Non-blocking send (best effort) // Non-blocking send (best effort)
esp_err_t ret_ws = httpd_ws_send_frame_async(s_server, s_ws_client_fd, &ws_frame); esp_err_t ret_ws = httpd_ws_send_frame_async(s_server, s_ws_client_fd, &ws_frame);
if (ret_ws != ESP_OK) { if (ret_ws != ESP_OK) {
ESP_LOGW(TAG, "dropped"); ESP_LOGW(TAG, "dropped: %s", esp_err_to_name(ret_ws));
// Failed to send, possibly socket busy or buffer full.
// Just ignore for now to keep ADC running. // Invalidate FD if it's no longer valid (client disconnected)
// If it's a fatal socket error, we might want to invalidate fd, if (ret_ws == ESP_ERR_INVALID_ARG || ret_ws == ESP_FAIL) {
// but async send usually returns QUEUE_FULL etc. for temp errors. s_ws_client_fd = -1;
}
} }
} }
} }
@@ -193,14 +213,24 @@ static void adc_read_task(void *arg) {
} }
} }
static void continuous_adc_init(adc_channel_t *channel, uint8_t channel_num, static void continuous_adc_init(adc_channel_t *channel, uint8_t channel_num,
adc_continuous_handle_t *out_handle) { adc_continuous_handle_t *out_handle) {
uint32_t frame_size = get_optimal_buffer_size(s_sample_rate);
ESP_LOGI(TAG, "Dynamic Buffer Size: %lu bytes", frame_size);
adc_continuous_handle_cfg_t adc_config = { adc_continuous_handle_cfg_t adc_config = {
.max_store_buf_size = 16384, .max_store_buf_size = 16384,
.conv_frame_size = ADC_READ_LEN, .conv_frame_size = frame_size,
}; };
ESP_ERROR_CHECK(adc_continuous_new_handle(&adc_config, out_handle)); ESP_ERROR_CHECK(adc_continuous_new_handle(&adc_config, out_handle));
// Update the global read length used by the task (hacky but simple for now)
// Ideally return it, but our init function signature is fixed.
// We can rely on get_optimal_buffer_size(s_sample_rate) being consistent.
adc_continuous_config_t dig_cfg = { adc_continuous_config_t dig_cfg = {
.sample_freq_hz = s_sample_rate, .sample_freq_hz = s_sample_rate,
.conv_mode = ADC_CONV_MODE, .conv_mode = ADC_CONV_MODE,