1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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");
}
|