Fix touch crash + make rain a reachability signal + calm the alarm churn
TOUCH CRASH (the blue screen): app_on_touch ran a blocking WebSocket send (up to 5s) directly in the LVGL touch callback, stalling the MIPI-DSI flush into a garbage/blue frame + task-watchdog reboot on every tap. Now touch_cb only gives a semaphore; a dedicated app_task does the blocking sends, audio, and face changes off the render thread. WS send timeout cut 5s to 1.5s as belt-and-braces. RAIN = REACHABILITY (user request): rain now falls only while the gateway WebSocket is live (gated on gw_connected in rain_tick). It drains gracefully on disconnect, resumes on reconnect, a genuine glanceable reachable signal. Idle density bumped 2 to 4 so connected-idle reads distinctly from disconnected-black. CALM THE WEDGE CHURN (user request): transient wifi/WS drops no longer slam to the x_x error face or a CONNECTING banner. Boot goes straight to the calm idle face (dry until connected). Only a sustained 30s+ outage escalates to x_x (clock_cb); the ~15s wedge-recovery just shows a brief rain pause. Two fixes from adversarial concurrency review before flashing: - persistent single capture task (was xTaskCreate per utterance; a rapid re-tap or WS-stop-vs-app-start race could put two readers on one mic/I2S handle and corrupt the codec) - reset s_talking on disconnect (app_on_disconnect) so the first tap after a mid-utterance drop starts fresh, not the stop branch Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+15
-7
@@ -35,6 +35,7 @@ static volatile bool s_capturing;
|
||||
|
||||
typedef enum { JOB_GONG, JOB_REPLY } job_t;
|
||||
static QueueHandle_t s_jobs;
|
||||
static TaskHandle_t s_capture_task;
|
||||
|
||||
/* --- gong: see docs/architecture.md "Sound signature" --- */
|
||||
|
||||
@@ -126,17 +127,23 @@ static void audio_task(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/* One persistent capture task, created once. It parks on a notification until
|
||||
* capture is requested, then streams mic -> gateway while s_capturing holds.
|
||||
* This makes capture single-instance: no create/delete restart race, so a rapid
|
||||
* re-tap (or a WS-disconnect stop racing an app_task start) can never put two
|
||||
* readers on the one mic/I2S handle. */
|
||||
static void capture_task(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
uint8_t *chunk = heap_caps_malloc(CAPTURE_CHUNK, MALLOC_CAP_DEFAULT);
|
||||
while (s_capturing) {
|
||||
if (esp_codec_dev_read(s_mic, chunk, CAPTURE_CHUNK) == ESP_CODEC_DEV_OK) {
|
||||
gw_send_bin(chunk, CAPTURE_CHUNK);
|
||||
for (;;) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
while (s_capturing) {
|
||||
if (esp_codec_dev_read(s_mic, chunk, CAPTURE_CHUNK) == ESP_CODEC_DEV_OK) {
|
||||
gw_send_bin(chunk, CAPTURE_CHUNK);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(chunk);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void audio_init(void)
|
||||
@@ -159,6 +166,7 @@ void audio_init(void)
|
||||
s_reply = heap_caps_malloc(REPLY_MAX, MALLOC_CAP_SPIRAM);
|
||||
s_jobs = xQueueCreate(4, sizeof(job_t));
|
||||
xTaskCreate(audio_task, "audio", 4096, NULL, 5, NULL);
|
||||
xTaskCreate(capture_task, "capture", 4096, NULL, 6, &s_capture_task);
|
||||
ESP_LOGI(TAG, "audio up (spk=%d mic=%d)", s_spk != NULL, s_mic != NULL);
|
||||
}
|
||||
|
||||
@@ -170,11 +178,11 @@ void audio_play_gong(void)
|
||||
|
||||
void audio_capture_start(void)
|
||||
{
|
||||
if (s_mic == NULL || s_capturing) {
|
||||
if (s_mic == NULL || s_capturing || s_capture_task == NULL) {
|
||||
return;
|
||||
}
|
||||
s_capturing = true;
|
||||
xTaskCreate(capture_task, "capture", 4096, NULL, 6, NULL);
|
||||
xTaskNotifyGive(s_capture_task); /* wake the persistent task's inner loop */
|
||||
}
|
||||
|
||||
void audio_capture_stop(void)
|
||||
|
||||
Reference in New Issue
Block a user