Files
banban/ql-application/threadx/interface/factory_test/factory_audio.c
T

262 lines
7.5 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ql_audio.h"
#include "ql_fs.h"
#include "ql_gpio.h"
#include "ql_power.h"
#include "ql_rtos.h"
#include "factory_audio.h"
#include "factory_test.h"
#define ES8311_ADDR 0x18
#define ES8311_DEVICE_ID_REG 0xFD
#define ES8311_DEVICE_ID 0x83
#define ES8311_VOLUME_100 0x8E
#define FT_PCM_CHUNK_BYTES 640
#define FT_MP3_TIMEOUT_TICKS (15000 / 5)
extern void sw_i2c_init(void);
extern int8 sw_i2c_start(void);
extern void sw_i2c_stop(void);
extern int8 sw_i2c_write_byte(uint8_t data);
extern uint8_t sw_i2c_read_byte(uint8_t ack);
static const uint16_t g_es8311_init_regs[] = {
0x0045, 0x3001, 0x1002, 0x0002, 0x1003, 0x2416, 0x2004, 0x0005,
0x2006, 0x0007, 0xff08, 0x0f09, 0x0f0a, 0x000b, 0x000c, 0x1310,
0x7f11, 0x3f01, 0x8000, 0x010d, 0x1014, 0x2812, 0x1013, 0x020e,
0x440f, 0x0015, 0x0a1b, 0x6a1c, 0x0837, 0x0044, 0xa717, 0x8e32,
0x0018
};
static ql_sem_t g_mp3_sem;
static volatile int g_mp3_result;
static Mp3PlaybackHandle g_mp3_handle;
static int es8311_write(uint8_t reg, uint8_t value)
{
if (sw_i2c_start() != 0) return -1;
if (sw_i2c_write_byte((uint8_t)(ES8311_ADDR << 1)) != 0 ||
sw_i2c_write_byte(reg) != 0 || sw_i2c_write_byte(value) != 0) {
sw_i2c_stop();
return -1;
}
sw_i2c_stop();
return 0;
}
static int es8311_read(uint8_t reg, uint8_t *value)
{
if (!value || sw_i2c_start() != 0) return -1;
if (sw_i2c_write_byte((uint8_t)(ES8311_ADDR << 1)) != 0 ||
sw_i2c_write_byte(reg) != 0 || sw_i2c_start() != 0 ||
sw_i2c_write_byte((uint8_t)((ES8311_ADDR << 1) | 1)) != 0) {
sw_i2c_stop();
return -1;
}
*value = sw_i2c_read_byte(0);
sw_i2c_stop();
return 0;
}
static void factory_pa_control(unsigned int on)
{
ql_gpio_init(FT_PA_PIN, PIN_DIRECTION_OUT, PIN_PULL_DISABLE,
on ? PIN_LEVEL_HIGH : PIN_LEVEL_LOW);
}
static void factory_mp3_callback(Mp3PlayEventType event, int value)
{
if (event != MP3_PLAYBACK_EVENT_STATUS) return;
if (value == MP3_PLAYBACK_STATUS_STARTED) {
g_mp3_result = 1;
} else if (value == MP3_PLAYBACK_STATUS_ENDED) {
g_mp3_result = 2;
if (g_mp3_sem) ql_rtos_semaphore_release(g_mp3_sem);
} else if (value == MP3_PLAYBACK_STATUS_TIMEOUT) {
g_mp3_result = -1;
if (g_mp3_sem) ql_rtos_semaphore_release(g_mp3_sem);
}
}
static void factory_track_callback(audio_track_handle handle,
acm_audio_track_event_t event)
{
(void)handle;
(void)event;
}
static void factory_record_callback(audio_record_handle handle,
acm_audio_record_event_t event)
{
(void)handle;
(void)event;
}
int factory_audio_init(void)
{
uint8_t id = 0;
unsigned int i;
u32 start = ft_now_ms();
ql_codecpcm_config pcm_config[] = {
PCM_FS_256, PCM_CODEC_SAMPLE_16000, 0
};
while (!ql_get_audio_state()) {
if (ft_now_ms() - start > 10000) return -1;
ql_rtos_task_sleep_ms(50);
}
sw_i2c_init();
if (es8311_read(ES8311_DEVICE_ID_REG, &id) != 0 || id != ES8311_DEVICE_ID) {
return -1;
}
ql_bind_speakerpa_cb(factory_pa_control);
ql_codec_choose(AUD_EXTERNAL_CODEC, pcm_config);
for (i = 0; i < sizeof(g_es8311_init_regs) / sizeof(g_es8311_init_regs[0]); ++i) {
if (es8311_write((uint8_t)(g_es8311_init_regs[i] & 0xff),
(uint8_t)(g_es8311_init_regs[i] >> 8)) != 0) {
return -1;
}
}
ql_set_audio_path_speaker();
ql_set_volume(AUDIOHAL_SPK_VOL_11);
es8311_write(0x32, ES8311_VOLUME_100);
factory_pa_control(0);
if (!g_mp3_sem && ql_rtos_semaphore_create(&g_mp3_sem, 0) != 0) {
return -1;
}
return 0;
}
int factory_audio_play_prompt(const char *path)
{
Mp3PlayConfigInfo config;
int ret;
if (!path || ql_access(path, 0) != 0) return -2;
while (ql_rtos_semaphore_wait(g_mp3_sem, QL_NO_WAIT) == 0) { }
memset(&config, 0, sizeof(config));
config.listener = factory_mp3_callback;
config.sync_mode = 0;
g_mp3_result = 0;
es8311_write(0x32, ES8311_VOLUME_100);
ql_set_volume(AUDIOHAL_SPK_VOL_11);
factory_pa_control(1);
ret = ql_play_mp3((char *)path, &g_mp3_handle, &config);
if (ret != 0) {
factory_pa_control(0);
return -1;
}
ret = ql_rtos_semaphore_wait(g_mp3_sem, FT_MP3_TIMEOUT_TICKS);
if (ret != 0 || g_mp3_result != 2) {
ql_stop_mp3_play(g_mp3_handle, 0);
factory_pa_control(0);
return -1;
}
factory_pa_control(0);
return 0;
}
static int wait_pwrkey_level(unsigned char expected, u32 timeout_ms)
{
u32 start = ft_now_ms();
while (ql_get_pwrkey_status() != expected) {
if (ft_now_ms() - start >= timeout_ms) return -1;
ql_rtos_task_sleep_ms(10);
}
ql_rtos_task_sleep_ms(40);
return ql_get_pwrkey_status() == expected ? 0 : -1;
}
int factory_audio_wait_and_loopback(u32 wait_timeout_ms, u32 *recorded_ms)
{
unsigned char *buffer = NULL;
unsigned int total = 0;
unsigned int request;
unsigned int offset;
audio_record_handle record_handle = 0;
audio_track_handle track_handle = 0;
int ret = -1;
if (recorded_ms) *recorded_ms = 0;
if (wait_pwrkey_level(0, 10000) != 0 ||
wait_pwrkey_level(1, wait_timeout_ms) != 0) {
return -4;
}
buffer = (unsigned char *)malloc(FT_AUDIO_BUFFER_BYTES);
if (!buffer) return -1;
record_handle = ql_audio_record_open(FT_AUDIO_RATE_HZ, FT_AUDIO_CHANNELS,
0, factory_record_callback);
if (!record_handle) goto cleanup;
while (ql_get_pwrkey_status() && total < FT_AUDIO_BUFFER_BYTES) {
request = FT_PCM_CHUNK_BYTES;
if (request > FT_AUDIO_BUFFER_BYTES - total) {
request = FT_AUDIO_BUFFER_BYTES - total;
}
if (ql_audio_record_read(record_handle, (char *)(buffer + total), &request) == 0 &&
request > 0) {
total += request;
}
ql_rtos_task_sleep_ms(10);
}
ql_audio_record_close(record_handle, 0);
record_handle = 0;
if (total == FT_AUDIO_BUFFER_BYTES && ql_get_pwrkey_status()) {
if (wait_pwrkey_level(0, 30000) != 0) goto cleanup;
} else if (wait_pwrkey_level(0, 3000) != 0) {
goto cleanup;
}
if (total < FT_PCM_CHUNK_BYTES) {
ret = -2;
goto cleanup;
}
if (recorded_ms) {
*recorded_ms = total * 1000U / (FT_AUDIO_RATE_HZ * 2U * FT_AUDIO_CHANNELS);
}
es8311_write(0x32, ES8311_VOLUME_100);
ql_set_volume(AUDIOHAL_SPK_VOL_11);
factory_pa_control(1);
track_handle = ql_audio_track_open(FT_AUDIO_RATE_HZ, FT_AUDIO_CHANNELS,
0, factory_track_callback);
if (!track_handle) {
ret = -3;
goto cleanup;
}
for (offset = 0; offset < total; offset += FT_PCM_CHUNK_BYTES) {
unsigned int size = total - offset;
if (size > FT_PCM_CHUNK_BYTES) size = FT_PCM_CHUNK_BYTES;
if (ql_audio_track_write(track_handle, (char *)(buffer + offset), size) != 0) {
ret = -3;
goto cleanup;
}
}
ql_rtos_task_sleep_ms(total * 1000U /
(FT_AUDIO_RATE_HZ * 2U * FT_AUDIO_CHANNELS) + 300U);
ret = 0;
cleanup:
if (record_handle) ql_audio_record_close(record_handle, 1);
if (track_handle) ql_audio_track_close(track_handle, ret == 0 ? 0 : 1);
factory_pa_control(0);
if (buffer) free(buffer);
return ret;
}