diff options
Diffstat (limited to 'fw/esp32/components/eos/cell_pcm.c')
-rw-r--r-- | fw/esp32/components/eos/cell_pcm.c | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/fw/esp32/components/eos/cell_pcm.c b/fw/esp32/components/eos/cell_pcm.c new file mode 100644 index 0000000..3f5089d --- /dev/null +++ b/fw/esp32/components/eos/cell_pcm.c @@ -0,0 +1,137 @@ +#include <stdint.h> +#include <stdlib.h> + +#include <freertos/FreeRTOS.h> +#include <freertos/task.h> +#include <driver/i2s_tdm.h> +#include <esp_log.h> + +#include "eos.h" +#include "net.h" +#include "cell.h" + +#define PCM_GPIO_BCK 1 +#define PCM_GPIO_WS 41 +#define PCM_GPIO_DIN 2 +#define PCM_GPIO_DOUT 42 + +#define PCM_RX_WM 256 /* receive watermark, must be less than NET_SIZE_MTU */ + +static i2s_chan_handle_t tx_chan; +static i2s_chan_handle_t rx_chan; + +static const char *TAG = "EOS CELL PCM"; + +static void pcm_rcvr_task(void *pvParameters) { + unsigned char *buffer; + size_t size_r; + esp_err_t ret; + int done = 0; + int rv; + + while (!done) { + buffer = eos_net_alloc(); + buffer[0] = EOS_CELL_MTYPE_VOICE | EOS_CELL_MTYPE_VOICE_PCM; + ret = i2s_channel_read(rx_chan, buffer + 1, PCM_RX_WM, &size_r, 1000); + switch (ret) { + case ESP_OK: { + assert(size_r == PCM_RX_WM); + break; + } + + case ESP_ERR_INVALID_STATE: { + done = 1; + break; + } + + default: { + done = 1; + ESP_LOGE(TAG, "CHAN READ ERR:%d", ret); + break; + } + } + if (ret == ESP_OK) { + rv = eos_net_send(EOS_NET_MTYPE_CELL, buffer, size_r + 1); + if (rv) ESP_LOGE(TAG, "NET SEND ERR:%d", rv); + } else { + eos_net_free(buffer); + } + } + vTaskDelete(NULL); +} + +void eos_cell_pcm_start(void) { + BaseType_t rv; + esp_err_t ret; + + ret = i2s_channel_enable(tx_chan); + if (ret) { + ESP_LOGE(TAG, "TX CHAN ENABLE ERR:%d", ret); + return; + } + + ret = i2s_channel_enable(rx_chan); + if (ret) { + ESP_LOGE(TAG, "RX CHAN ENABLE ERR:%d", ret); + return; + } + + rv = xTaskCreate(&pcm_rcvr_task, "pcm_rcvr", EOS_TASK_SSIZE_PCM, NULL, EOS_TASK_PRIORITY_PCM, NULL); + assert(rv == pdPASS); +} + +void eos_cell_pcm_stop(void) { + esp_err_t ret; + + ret = i2s_channel_disable(tx_chan); + if (ret) ESP_LOGE(TAG, "TX CHAN DISABLE ERR:%d", ret); + + ret = i2s_channel_disable(rx_chan); + if (ret) ESP_LOGE(TAG, "RX CHAN DISABLE ERR:%d", ret); +} + +void eos_cell_pcm_push(unsigned char *data, size_t size) { + esp_err_t ret; + size_t size_w; + + ret = i2s_channel_write(tx_chan, data, size, &size_w, 1000); + if (ret == ESP_OK) { + assert(size_w == size); + } else { + ESP_LOGE(TAG, "CHAN WRITE ERR:%d", ret); + } +} + +void eos_cell_pcm_init(void) { + i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_SLAVE); + i2s_tdm_config_t tdm_cfg = { + .clk_cfg = I2S_TDM_CLK_DEFAULT_CONFIG(8000), + .slot_cfg = I2S_TDM_PCM_SHORT_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO, + I2S_TDM_SLOT0), + .gpio_cfg = { + .mclk = I2S_GPIO_UNUSED, + .bclk = PCM_GPIO_BCK, + .ws = PCM_GPIO_WS, + .din = PCM_GPIO_DIN, + .dout = PCM_GPIO_DOUT, + .invert_flags = { + .mclk_inv = false, + .bclk_inv = false, + .ws_inv = false, + }, + }, + }; + esp_err_t ret; + + tdm_cfg.slot_cfg.total_slot = 16; + ret = i2s_new_channel(&chan_cfg, &tx_chan, &rx_chan); + assert(ret == ESP_OK); + + ret = i2s_channel_init_tdm_mode(tx_chan, &tdm_cfg); + assert(ret == ESP_OK); + + ret = i2s_channel_init_tdm_mode(rx_chan, &tdm_cfg); + assert(ret == ESP_OK); + + ESP_LOGI(TAG, "INIT"); +} |