sdk-hwV1.3/lichee/xr806/appos/project/common/cmd/cmd_i2s.c

333 lines
9.9 KiB
C
Executable File

/*
* Copyright (C) 2017 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* 3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "cmd_util.h"
#include "cmd_i2s.h"
#include "driver/chip/hal_gpio.h"
#include "driver/chip/hal_snd_card.h"
#include "audio/pcm/audio_pcm.h"
#include "audio/manager/audio_manager.h"
//CMD I2S Test config
#define CMD_I2S_SND_CARD SND_CARD_3
#define CMD_I2S_LOOP_BACK_EN 0
#define CMD_I2S_BUF_SIZE 3360//128
static unsigned char tx_sample_res, rx_sample_res;
#if 0
static const uint8_t tx_data_8bit[128] = {
0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
};
static const uint16_t tx_data_16bit[64] = {
0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234,
0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234,
0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234,
0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234, 0x1234,
};
static const uint32_t tx_data_32bit[32] = {
0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678,
0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678,
0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678,
0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678, 0x12345678,
};
#endif
static enum cmd_status cmd_i2s_open_exec(char *cmd)
{
int cnt;
uint32_t direction, channels, resolution, sampleRate, cmd_param[3];
cnt = cmd_sscanf(cmd, "d=%u c=%u r=%u s=%u", &direction, &channels,
&resolution, &sampleRate);
if (cnt != 4) {
CMD_ERR("cmd_sscanf return: cnt = %d\n", cnt);
return CMD_STATUS_INVALID_ARG;
}
if (direction != 0 && direction != 1) {
CMD_ERR("invalid direction %u\n", direction);
return CMD_STATUS_INVALID_ARG;
}
if (channels < 1 || channels > 8) {
CMD_ERR("invalid channels %u\n", channels);
return CMD_STATUS_INVALID_ARG;
}
switch (sampleRate) {
case 8000:
case 16000:
case 32000:
case 12000:
case 24000:
case 48000:
break;
case 11025:
case 22050:
case 44100:
CMD_ERR("I2S don't support 44100 series sample rate\n");
default:
CMD_ERR("invalid sample rate %u\n", sampleRate);
return CMD_STATUS_INVALID_ARG;
}
if (!direction) {
tx_sample_res = resolution;
} else {
rx_sample_res = resolution;
}
switch (resolution) {
case 8:
resolution = PCM_FORMAT_S8;
break;
case 12:
resolution = PCM_FORMAT_S12_LE;
break;
case 16:
resolution = PCM_FORMAT_S16_LE;
break;
case 20:
resolution = PCM_FORMAT_S20_LE;
break;
case 24:
resolution = PCM_FORMAT_S24_LE;
break;
case 28:
resolution = PCM_FORMAT_S28_LE;
break;
case 32:
resolution = PCM_FORMAT_S32_LE;
break;
default:
CMD_ERR("Invalid resolution(%u) failed...\n", resolution);
return HAL_INVALID;
}
struct pcm_config pcm_cfg;
pcm_cfg.rate = sampleRate;
pcm_cfg.channels = channels;
pcm_cfg.format = resolution;
pcm_cfg.period_count = 1;
pcm_cfg.period_size = CMD_I2S_BUF_SIZE
/ (pcm_format_to_bits(pcm_cfg.format) / 8 * channels)
/ pcm_cfg.period_count;
cmd_param[0] = !!CMD_I2S_LOOP_BACK_EN << 24 | 0x0 << 16 | 0x20 << 8 | 0x2;
cmd_param[1] = (channels + 1) / 2 * 32;
cmd_param[2] = 24576000;
audio_maneger_ioctl(CMD_I2S_SND_CARD, PLATFORM_IOCTL_HW_CONFIG, cmd_param, 3);
cmd_param[0] = 256<<16 | 256;
audio_maneger_ioctl(CMD_I2S_SND_CARD, PLATFORM_IOCTL_SW_CONFIG, cmd_param, 1);
if (snd_pcm_open(CMD_I2S_SND_CARD, (Audio_Stream_Dir)direction, &pcm_cfg)) {
CMD_ERR("snd pcm open Fail..\n");
return CMD_STATUS_FAIL;
}
return CMD_STATUS_OK;
}
static enum cmd_status cmd_i2s_close_exec(char *cmd)
{
int cnt;
uint32_t direction;
cnt = cmd_sscanf(cmd, "d=%u", &direction);
if (cnt != 1) {
CMD_ERR("cmd_sscanf return: cnt = %d\n", cnt);
return CMD_STATUS_INVALID_ARG;
}
if (direction != 0 && direction != 1) {
CMD_ERR("invalid direction %u\n", direction);
return CMD_STATUS_INVALID_ARG;
}
if (snd_pcm_close(CMD_I2S_SND_CARD, (Audio_Stream_Dir)direction)) {
CMD_ERR("Snd pcm close Fail..\n");
return CMD_STATUS_FAIL;
}
return CMD_STATUS_OK;
}
static enum cmd_status cmd_i2s_pcm_write_exec(char *cmd)
{
uint32_t i, *buf_32, bit_map;
uint16_t *buf_16;
uint8_t *buf, *buf_8;
int32_t size;
//malloc tx buffer
buf = (uint8_t *)cmd_malloc(CMD_I2S_BUF_SIZE);
if (buf == NULL) {
CMD_ERR("cmd_malloc return NULL.\n");
return CMD_STATUS_FAIL;
}
//copy tx data
if (tx_sample_res > 16) {
buf_32 = (unsigned int *)buf;
for (i = 0; i < CMD_I2S_BUF_SIZE / 4; i++) {
buf_32[i] = 0x12345678;
}
//cmd_memcpy(buf, tx_data_32bit, CMD_I2S_BUF_SIZE);
} else if (tx_sample_res > 8) {
buf_16 = (uint16_t *)buf;
for (i = 0; i < CMD_I2S_BUF_SIZE / 2; i++) {
buf_16[i] = 0x1234;
}
//cmd_memcpy(buf, tx_data_16bit, CMD_I2S_BUF_SIZE);
} else {
buf_8 = (uint8_t *)buf;
for (i = 0; i < CMD_I2S_BUF_SIZE / 1; i++) {
buf_8[i] = 0x12;
}
//cmd_memcpy(buf, tx_data_8bit, CMD_I2S_BUF_SIZE);
}
//write pcm data
size = snd_pcm_write(CMD_I2S_SND_CARD, buf, CMD_I2S_BUF_SIZE);
if (size != CMD_I2S_BUF_SIZE) {
CMD_ERR("len = %u, but I2S WRITE size = %d\n", CMD_I2S_BUF_SIZE, size);
cmd_free(buf);
cmd_write_respond(CMD_STATUS_FAIL, "FAIL");
return CMD_STATUS_ACKED;
}
cmd_write_respond(CMD_STATUS_OK, "OK");
//printf tx data for debug
CMD_LOG(1, "\nwrite buf:\n");
if (tx_sample_res > 16) {
bit_map = ((1 << tx_sample_res) - 1) << (32 - tx_sample_res);
buf_32 = (unsigned int *)buf;
for (i = 0; i < CMD_I2S_BUF_SIZE / 4 / 8; i++) {
CMD_LOG(1, "0x%08x ", buf_32[i] & bit_map);
}
} else if (tx_sample_res > 8) {
bit_map = (1 << tx_sample_res) - 1;
buf_16 = (uint16_t *)buf;
for (i = 0; i < CMD_I2S_BUF_SIZE / 2 / 16; i++) {
CMD_LOG(1, "0x%04x ", buf_16[i] & bit_map);
}
} else {
bit_map = (1 << tx_sample_res) - 1;
buf_8 = (uint8_t *)buf;
for (i = 0; i < CMD_I2S_BUF_SIZE / 1 / 32; i++) {
CMD_LOG(1, "0x%02x ", buf_8[i] & bit_map);
}
}
CMD_LOG(1, "\n\n");
//free tx buffer
cmd_free(buf);
return CMD_STATUS_ACKED;
}
static enum cmd_status cmd_i2s_pcm_read_exec(char *cmd)
{
uint32_t i, *buf_32;
uint16_t *buf_16;
uint8_t *buf, *buf_8;
int32_t size;
//malloc rx buffer
buf = (uint8_t *)cmd_malloc(CMD_I2S_BUF_SIZE);
if (buf == NULL) {
CMD_ERR("cmd_malloc return NULL.\n");
return CMD_STATUS_FAIL;
}
cmd_memset(buf, 0, CMD_I2S_BUF_SIZE);
//read pcm_data
size = snd_pcm_read(CMD_I2S_SND_CARD, buf, CMD_I2S_BUF_SIZE);
if (size != CMD_I2S_BUF_SIZE) {
CMD_ERR("len = %u, but I2S read size = %d\n", CMD_I2S_BUF_SIZE, size);
cmd_free(buf);
return CMD_STATUS_FAIL;
}
cmd_write_respond(CMD_STATUS_OK, "OK");
//printf rx_data for debug
CMD_LOG(1, "\nread buf:\n");
if (rx_sample_res > 16) {
buf_32 = (unsigned int *)buf;
for (i = 0; i < CMD_I2S_BUF_SIZE / 4 / 8; i++) {
printf("0x%08x ", buf_32[i]);
}
} else if (rx_sample_res > 8) {
buf_16 = (uint16_t *)buf;
for (i = 0; i < CMD_I2S_BUF_SIZE / 2 / 16; i++) {
printf("0x%04x ", buf_16[i]);
}
} else {
buf_8 = (uint8_t *)buf;
for (i = 0; i < CMD_I2S_BUF_SIZE / 1 / 32; i++) {
printf("0x%02x ", buf_8[i]);
}
}
CMD_LOG(1, "\n");
//free rx buffer
cmd_free(buf);
return CMD_STATUS_ACKED;
}
static const struct cmd_data g_i2s_cmds[] = {
{ "open", cmd_i2s_open_exec },
{ "close", cmd_i2s_close_exec },
{ "pcm_read", cmd_i2s_pcm_read_exec },
{ "pcm_write", cmd_i2s_pcm_write_exec },
};
enum cmd_status cmd_i2s_exec(char *cmd)
{
return cmd_exec(cmd, g_i2s_cmds, cmd_nitems(g_i2s_cmds));
}