Choose buffer size/count to maintain packet rate to WS client at different sample rates
This commit is contained in:
@@ -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>
|
||||||
|
|
||||||
|
|||||||
44
main/main.c
44
main/main.c
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user