summaryrefslogtreecommitdiff
path: root/fw/esp32/components/eos/cell_pcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'fw/esp32/components/eos/cell_pcm.c')
-rw-r--r--fw/esp32/components/eos/cell_pcm.c137
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");
+}