Pass recorder and usb.

This commit is contained in:
Colin 2026-01-08 22:47:29 +08:00
parent 11186066c7
commit f962fb78ec
9 changed files with 293 additions and 147 deletions

View File

@ -1,2 +1 @@
idf_component_register(SRCS "main.c" "app_sr.c" "usb_msc.c"
INCLUDE_DIRS ".")
idf_component_register(SRCS "main.c" "sr.c" "record.c" "usb_msc.c" "asr.c" INCLUDE_DIRS ".")

View File

@ -73,7 +73,7 @@ static void wifi_event_handler(void* arg, esp_event_base_t event_base,
}
}
static void wifi_init_sta(void) {
void wifi_init_sta(void) {
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
@ -267,7 +267,6 @@ cleanup:
return body;
}
// 发送音频转录请求
static void send_audio_transcription(const char* filepath) {
uint8_t* file_data = NULL;
size_t file_size = 0;
@ -282,7 +281,7 @@ static void send_audio_transcription(const char* filepath) {
// 构建multipart请求体
size_t body_len = 0;
char* body =
build_multipart_body(file_data, file_size, AUDIO_FILE_NAME, &body_len);
build_multipart_body(file_data, file_size, "audio.wav", &body_len);
if (!body) {
ESP_LOGE(TAG, "Failed to build request body");
free(file_data);
@ -341,7 +340,6 @@ static void send_audio_transcription(const char* filepath) {
free(file_data);
}
// 创建一个简单的测试,先确认网络和证书工作
static void debug_network_test(void) {
ESP_LOGI(TAG, "Starting network debug test...");
@ -436,14 +434,7 @@ void initTime(void) {
timeinfo.tm_sec);
}
void sendHttpsRequest(const uint8_t* audioData, size_t audioSize) {
// This function is not used in ESP-IDF context, so we'll leave it as a
// placeholder The actual HTTPS request is handled by send_audio_transcription
// function
ESP_LOGI(TAG, "sendHttpsRequest is not used in ESP-IDF implementation");
}
void app_main(void) {
void asr(void) {
// 初始化NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||

24
main/asr.h Normal file
View File

@ -0,0 +1,24 @@
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/unistd.h>
#include "driver/sdmmc_host.h"
#include "esp_crt_bundle.h"
#include "esp_err.h"
#include "esp_event.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
#include "esp_log.h"
#include "esp_sntp.h"
#include "esp_tls.h"
#include "esp_vfs_fat.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "netdb.h"
#include "nvs_flash.h"
#include "sdmmc_cmd.h"
#include "time.h"
void wifi_init_sta(void);

83
main/base.h Normal file
View File

@ -0,0 +1,83 @@
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include "driver/i2c.h"
#include "driver/i2s_std.h"
#include "driver/i2s_tdm.h"
#include "driver/sdmmc_host.h"
#include "es7210.h"
#include "esp_assert.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_netif_sntp.h"
#include "esp_pm.h"
#include "esp_private/esp_clk.h"
#include "esp_sleep.h"
#include "esp_sntp.h"
#include "esp_system.h"
#include "esp_timer.h"
#include "esp_vfs_fat.h"
#include "esp_wifi.h"
#include "format_wav.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
#include "sdmmc_cmd.h"
#include "time.h"
/* I2C port and GPIOs */
#define I2C_NUM (0)
#define I2C_SDA_IO (1)
#define I2C_SCL_IO (2)
/* ES7210 configurations */
#define ES7210_I2C_ADDR (0x41)
#define ES7210_I2C_CLK (100000)
#define ES7210_MIC_GAIN (ES7210_MIC_GAIN_30DB)
#define ES7210_MIC_BIAS (ES7210_MIC_BIAS_2V87)
#define ES7210_ADC_VOLUME (32)
/* I2S port and GPIOs */
#define I2S_NUM (0)
#define I2S_MCK_IO (38)
#define I2S_BCK_IO (14)
#define I2S_WS_IO (13)
#define I2S_DI_IO (12)
/* SD card GPIOs */
#define SD_CMD_IO (48)
#define SD_CLK_IO (47)
#define SD_DAT0_IO (21)
/* SD card & recording configurations */
#define RECORD_TIME_SEC (20)
#define SD_MOUNT_POINT "/sdcard"
/* I2S configurations */
#define I2S_TDM_FORMAT (ES7210_I2S_FMT_I2S)
#define I2S_CHAN_NUM (2)
#define I2S_SAMPLE_RATE (16000)
#define I2S_MCLK_MULTIPLE (I2S_MCLK_MULTIPLE_256)
#define I2S_SAMPLE_BITS (I2S_DATA_BIT_WIDTH_16BIT)
#define I2S_TDM_SLOT_MASK (I2S_TDM_SLOT0 | I2S_TDM_SLOT1)
// 配置参数
#define SAMPLE_RATE 16000
#define I2S_PORT I2S_NUM_0
#define DMA_BUF_COUNT 8
#define DMA_BUF_LEN 512
#define SAMPLE_BITS I2S_DATA_BIT_WIDTH_16BIT
// 引脚定义
#define I2S_BCK_PIN 14
#define I2S_WS_PIN 13
#define I2S_DATA_PIN 12
#define LED_PIN 48 // 用于指示中断触发

View File

@ -1,77 +1,11 @@
#include <stdio.h>
#include <string.h>
#include "app_sr.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "driver/i2s_std.h"
#include "driver/i2s_tdm.h"
#include "driver/i2s_types.h"
#include "driver/sdmmc_host.h"
#include "es7210.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_pm.h"
#include "esp_private/esp_clk.h"
#include "esp_sleep.h"
#include "esp_timer.h"
#include "esp_vfs_fat.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include "asr.h"
#include "base.h"
#include "record.h"
#include "sr.h"
/* I2C port and GPIOs */
#define I2C_NUM (0)
#define I2C_SDA_IO (1)
#define I2C_SCL_IO (2)
/* ES7210 configurations */
#define ES7210_I2C_ADDR (0x41)
#define ES7210_I2C_CLK (100000)
#define ES7210_MIC_GAIN (ES7210_MIC_GAIN_30DB)
#define ES7210_MIC_BIAS (ES7210_MIC_BIAS_2V87)
#define ES7210_ADC_VOLUME (32)
/* I2S port and GPIOs */
#define I2S_NUM (0)
#define I2S_MCK_IO (38)
#define I2S_BCK_IO (14)
#define I2S_WS_IO (13)
#define I2S_DI_IO (12)
/* SD card GPIOs */
#define SD_CMD_IO (48)
#define SD_CLK_IO (47)
#define SD_DAT0_IO (21)
/* SD card & recording configurations */
#define RECORD_TIME_SEC (20)
#define SD_MOUNT_POINT "/sdcard"
/* I2S configurations */
#define I2S_TDM_FORMAT (ES7210_I2S_FMT_I2S)
#define I2S_CHAN_NUM (2)
#define I2S_SAMPLE_RATE (16000)
#define I2S_MCLK_MULTIPLE (I2S_MCLK_MULTIPLE_256)
#define I2S_SAMPLE_BITS (I2S_DATA_BIT_WIDTH_16BIT)
#define I2S_TDM_SLOT_MASK (I2S_TDM_SLOT0 | I2S_TDM_SLOT1)
// 配置参数
#define SAMPLE_RATE 16000
#define I2S_PORT I2S_NUM_0
#define DMA_BUF_COUNT 8
#define DMA_BUF_LEN 512
#define SAMPLE_BITS I2S_DATA_BIT_WIDTH_16BIT
// 引脚定义
#define I2S_BCK_PIN 14
#define I2S_WS_PIN 13
#define I2S_DATA_PIN 12
#define LED_PIN 48 // 用于指示中断触发
// 全局变量
static const char* TAG = "I2S_DMA_ISR";
static i2s_chan_handle_t rx_chan = NULL;
@ -86,38 +20,6 @@ typedef struct {
size_t size;
} i2s_queue_data_t;
static i2s_chan_handle_t es7210_i2s_init(void) {
ESP_LOGI(TAG, "Create I2S receive channel");
i2s_chan_config_t i2s_rx_conf = I2S_CHANNEL_DEFAULT_CONFIG(
I2S_NUM_AUTO, I2S_ROLE_MASTER); // 配置接收通道
i2s_rx_conf.dma_desc_num = DMA_BUF_COUNT;
i2s_rx_conf.dma_frame_num = DMA_BUF_LEN;
i2s_rx_conf.auto_clear = true;
ESP_ERROR_CHECK(
i2s_new_channel(&i2s_rx_conf, NULL, &rx_chan)); // 创建i2s通道
ESP_LOGI(TAG, "Configure I2S receive channel to TDM mode");
// 定义接收通道为I2S TDM模式 并配置
i2s_tdm_config_t i2s_tdm_rx_conf = {
.slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(
I2S_SAMPLE_BITS, I2S_SLOT_MODE_STEREO, I2S_TDM_SLOT_MASK),
.clk_cfg = {.clk_src = I2S_CLK_SRC_DEFAULT,
.sample_rate_hz = I2S_SAMPLE_RATE,
.mclk_multiple = I2S_MCLK_MULTIPLE},
.gpio_cfg = {.mclk = I2S_MCK_IO,
.bclk = I2S_BCK_IO,
.ws = I2S_WS_IO,
.dout = -1, // ES7210 only has ADC capability
.din = I2S_DI_IO},
};
ESP_ERROR_CHECK(i2s_channel_init_tdm_mode(
rx_chan, &i2s_tdm_rx_conf)); // 初始化I2S通道为TDM模式
ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));
return rx_chan;
}
sdmmc_card_t* mount_sdcard(void) {
sdmmc_card_t* sdmmc_card = NULL;
@ -349,8 +251,6 @@ static esp_err_t i2s_init(void) {
// ESP_ERROR_CHECK(
// i2s_channel_register_event_callback(rx_chan, &callbacks, NULL));
ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));
ESP_LOGI(TAG, "I2S初始化完成使用DMA中断");
return ESP_OK;
}
@ -389,48 +289,44 @@ void app_main(void) {
sdmmc_card_t* sdmmc_card = mount_sdcard();
// if (i2s_init() != ESP_OK) {
// ESP_LOGE(TAG, "I2S初始化失败");
// return;
// }
es7210_i2s_init();
wifi_init_sta();
es7210_codec_init();
ESP_LOGI(TAG, "启动I2S DMA接收示例");
afe_sr_data = sr_init();
get_time_init();
wait_for_time_sync(10);
get_current_time();
config_power_manager();
record_start1();
record_start2();
es7210_codec_init();
ESP_ERROR_CHECK(i2s_init());
BaseType_t task_ret = xTaskCreate(i2s_rx_task, "i2s_rx_task", 4096, NULL,
tskIDLE_PRIORITY + 2, &rx_task_handle);
afe_sr_data = sr_init();
if (task_ret != pdTRUE) {
ESP_LOGE(TAG, "创建I2S数据处理任务失败");
return;
}
ESP_LOGI(TAG, "系统启动完成I2S使用DMA处理数据");
// 主循环可以执行其他任务
// while (1) {
// // 这里可以执行其他非I2S相关的任务
// ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));
// record_start1();
// record_start2();
// BaseType_t task_ret = xTaskCreate(i2s_rx_task, "i2s_rx_task", 4096, NULL,
// tskIDLE_PRIORITY + 2, &rx_task_handle);
// if (task_ret != pdTRUE) {
// ESP_LOGE(TAG, "创建I2S数据处理任务失败");
// return;
// }
// ESP_LOGI(TAG, "系统启动完成I2S使用DMA处理数据");
// while (!record_end1() || !record_end2()) {
// vTaskDelay(pdMS_TO_TICKS(1000));
// }
while (!record_end1() || !record_end2()) {
vTaskDelay(pdMS_TO_TICKS(1000));
for (int i = 0; i < 2; i++) {
ESP_ERROR_CHECK(record_wav(rx_chan));
}
esp_pm_config_esp32_t pm_config = {
.max_freq_mhz = 240, .min_freq_mhz = 240, .light_sleep_enable = false};
ret = esp_pm_configure(&pm_config);
init_msc(sdmmc_card);
esp_vfs_fat_sdcard_unmount(SD_MOUNT_POINT, sdmmc_card);
}
// 应用程序结束时的清理函数
void app_cleanup(void) {
if (rx_chan) {
i2s_channel_disable(rx_chan);

146
main/record.c Normal file
View File

@ -0,0 +1,146 @@
#include "record.h"
time_t now;
struct tm timeinfo;
static const char* TAG = "record";
// static char* record_file_name = NULL;
static char record_file_name[48];
void get_time_init() {
ESP_LOGI(TAG, "初始化SNTP...");
// 配置时区(东八区)
setenv("TZ", "CST-8", 1);
tzset();
// 配置NTP服务器
esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
esp_sntp_setservername(0, "ntp.aliyun.com");
esp_sntp_setservername(1, "cn.ntp.org.cn");
esp_sntp_setservername(2, "pool.ntp.org");
// 初始化SNTP
esp_sntp_init();
ESP_LOGI(TAG, "SNTP初始化完成");
}
esp_err_t get_current_time() {
char strftime_buf[64];
// 获取时间
time(&now);
localtime_r(&now, &timeinfo);
// 检查时间是否有效1970年之后
if (timeinfo.tm_year < 70) {
ESP_LOGW(TAG, "时间未同步正在等待NTP...");
return ESP_ERR_TIMEOUT;
}
// 格式化输出时间
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
ESP_LOGI(TAG, "当前时间: %s", strftime_buf);
ESP_LOGI(TAG, "详细: %04d-%02d-%02d %02d:%02d:%02d", timeinfo.tm_year + 1900,
timeinfo.tm_mon + 1, timeinfo.tm_mday, timeinfo.tm_hour,
timeinfo.tm_min, timeinfo.tm_sec);
return ESP_OK;
}
esp_err_t wait_for_time_sync(int timeout_seconds) {
int retry = 0;
const int max_retry = timeout_seconds;
while (esp_sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET &&
retry < max_retry) {
ESP_LOGI(TAG, "等待NTP时间同步... (%d/%d)", retry + 1, max_retry);
vTaskDelay(pdMS_TO_TICKS(1000));
retry++;
// 可选:检查是否已经同步
if (get_current_time() == ESP_OK) {
return ESP_OK;
}
}
if (retry >= max_retry) {
ESP_LOGE(TAG, "NTP同步超时");
return ESP_ERR_TIMEOUT;
}
ESP_LOGI(TAG, "NTP同步完成");
return ESP_OK;
}
void time_example_task(void* pvParameters) {
get_time_init();
// 等待首次同步
if (wait_for_time_sync(15) != ESP_OK) {
ESP_LOGW(TAG, "首次同步失败,将继续重试");
}
while (1) {
// 每隔一段时间获取时间
if (get_current_time() == ESP_OK) {
// 时间有效,执行你的业务逻辑
} else {
// 时间无效,可能需要重新同步
ESP_LOGW(TAG, "时间无效,尝试重新同步...");
}
vTaskDelay(pdMS_TO_TICKS(60000)); // 每分钟获取一次
}
}
char* get_file_name_from_time(void) {
wait_for_time_sync(10);
localtime_r(&now, &timeinfo);
strftime(record_file_name, 48, "/sdcard/Record_%Y%m%d%H%M%S.wav", &timeinfo);
return record_file_name;
}
esp_err_t record_wav(i2s_chan_handle_t i2s_rx_chan) {
esp_err_t ret = ESP_OK;
uint32_t byte_rate = I2S_SAMPLE_RATE * I2S_CHAN_NUM * I2S_SAMPLE_BITS / 8;
uint32_t wav_size = byte_rate * RECORD_TIME_SEC;
const wav_header_t wav_header = WAV_HEADER_PCM_DEFAULT(
wav_size, I2S_SAMPLE_BITS, I2S_SAMPLE_RATE, I2S_CHAN_NUM);
get_file_name_from_time();
ESP_LOGI(TAG, "Opening file %s", record_file_name);
FILE* f = fopen(record_file_name, "w");
ESP_LOGI(TAG, "fopen error: %s", strerror(errno));
ESP_RETURN_ON_FALSE(f, ESP_FAIL, TAG, "error while opening wav file");
ESP_RETURN_ON_FALSE(fwrite(&wav_header, sizeof(wav_header_t), 1, f), ESP_FAIL,
TAG, "error while writing wav header");
/* Start recording */
size_t wav_written = 0;
static int16_t i2s_readraw_buff[DMA_BUF_LEN * sizeof(int16_t)];
ESP_ERROR_CHECK(i2s_channel_enable(i2s_rx_chan));
while (wav_written < wav_size) {
if (wav_written % byte_rate < sizeof(i2s_readraw_buff)) {
ESP_LOGI(TAG, "Recording: %" PRIu32 "/%ds", wav_written / byte_rate + 1,
RECORD_TIME_SEC);
}
size_t bytes_read = 0;
ESP_ERROR_CHECK(i2s_channel_read(i2s_rx_chan, i2s_readraw_buff,
sizeof(i2s_readraw_buff), &bytes_read,
pdMS_TO_TICKS(100)));
/* Write the samples to the WAV file */
ESP_RETURN_ON_FALSE(fwrite(i2s_readraw_buff, bytes_read, 1, f), ESP_FAIL,
TAG, "error while writing samples to wav file");
wav_written += bytes_read;
}
i2s_channel_disable(i2s_rx_chan);
ESP_LOGI(TAG, "Recording done! Flushing file buffer");
fclose(f);
return ret;
}

7
main/record.h Normal file
View File

@ -0,0 +1,7 @@
#include "base.h"
esp_err_t record_wav(i2s_chan_handle_t i2s_rx_chan);
void get_time_init();
esp_err_t get_current_time();
esp_err_t wait_for_time_sync(int timeout_seconds);

View File

@ -1,5 +1,5 @@
#include "app_sr.h"
#include "sr.h"
#include <errno.h>
@ -24,7 +24,7 @@
#include "freertos/task.h"
#include "model_path.h"
static const char* TAG = "app_sr";
static const char* TAG = "sr";
srmodel_list_t* models = NULL;
static esp_afe_sr_iface_t* afe_handle = NULL;