/* * DeskLock — living-room face and voice for the Tatlock butler. * * Boot sequence (planned): * 1. BSP init: display + LVGL, touch, audio codec (ES8311/ES7210) * 2. Wi-Fi up via ESP32-C6 (ESP-Hosted over SDIO) * 3. WebSocket connection to the DeskLock gateway * 4. Face state machine: idle / listening / thinking / speaking * * Current stage: bring-up — display + a placeholder face. */ #include #include #include "esp_log.h" #include "bsp/esp-bsp.h" #include "esp_codec_dev.h" #include "lvgl.h" static const char *TAG = "desklock"; #define CHIME_RATE 16000 #define CHIME_SAMPLES (CHIME_RATE / 2) /* 0.5 s */ /* Bring-up proof for the audio path: C5 -> E5 with a fade-out. */ static void play_boot_chime(void) { esp_codec_dev_handle_t spk = bsp_audio_codec_speaker_init(); if (spk == NULL) { ESP_LOGW(TAG, "speaker init failed — no chime"); return; } esp_codec_dev_sample_info_t fs = { .sample_rate = CHIME_RATE, .channel = 1, .bits_per_sample = 16, }; esp_codec_dev_set_out_vol(spk, 70); esp_codec_dev_open(spk, &fs); int16_t *buf = malloc(CHIME_SAMPLES * sizeof(int16_t)); if (buf != NULL) { float phase = 0.0f; for (int i = 0; i < CHIME_SAMPLES; i++) { float freq = (i < CHIME_SAMPLES / 2) ? 523.25f : 659.25f; phase += 2.0f * (float)M_PI * freq / CHIME_RATE; float envelope = 1.0f - (float)i / CHIME_SAMPLES; buf[i] = (int16_t)(sinf(phase) * 12000.0f * envelope); } esp_codec_dev_write(spk, buf, CHIME_SAMPLES * sizeof(int16_t)); free(buf); ESP_LOGI(TAG, "boot chime played"); } esp_codec_dev_close(spk); } static void show_placeholder_face(void) { bsp_display_lock(0); lv_obj_t *scr = lv_screen_active(); lv_obj_set_style_bg_color(scr, lv_color_black(), 0); lv_obj_t *eyes = lv_label_create(scr); lv_label_set_text(eyes, "- -"); lv_obj_set_style_text_color(eyes, lv_color_hex(0xADFFC8), 0); lv_obj_set_style_text_font(eyes, &lv_font_montserrat_48, 0); lv_obj_align(eyes, LV_ALIGN_CENTER, 0, -80); lv_obj_t *mouth = lv_label_create(scr); lv_label_set_text(mouth, "\\_/"); lv_obj_set_style_text_color(mouth, lv_color_hex(0xADFFC8), 0); lv_obj_set_style_text_font(mouth, &lv_font_montserrat_48, 0); lv_obj_align(mouth, LV_ALIGN_CENTER, 0, 40); lv_obj_t *tag = lv_label_create(scr); lv_label_set_text(tag, "DESKLOCK"); lv_obj_set_style_text_color(tag, lv_color_hex(0x2F7A4B), 0); lv_obj_align(tag, LV_ALIGN_CENTER, 0, 160); bsp_display_unlock(); } void app_main(void) { ESP_LOGI(TAG, "DeskLock starting"); bsp_display_start(); bsp_display_backlight_on(); show_placeholder_face(); play_boot_chime(); ESP_LOGI(TAG, "DeskLock up (placeholder face)"); /* TODO(face): full LVGL face state machine per docs/architecture.md * TODO(net): Wi-Fi via ESP-Hosted (C6), WebSocket to gateway * TODO(voice): ES7210 capture upstream, ES8311 playback downstream */ }