pd working using low-level i2s audio driver, output only so far.
This commit is contained in:
parent
44c02f82ac
commit
fc1c3bce26
8 changed files with 395 additions and 660 deletions
|
|
@ -4,4 +4,4 @@ cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
include($ENV{ADF_PATH}/CMakeLists.txt)
|
include($ENV{ADF_PATH}/CMakeLists.txt)
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
project(bt_spp_acceptor_demo)
|
project(espd)
|
||||||
|
|
|
||||||
17
README.rst
17
README.rst
|
|
@ -1,16 +1,3 @@
|
||||||
qESP-IDF BT-SPP-ACCEPTOR demo
|
enter menuconfig "Component config", choose "Bluetooth"
|
||||||
======================
|
enter menu Bluetooth, choose "Classic Bluetooth" and "SPP Profile"
|
||||||
|
|
||||||
Demo of SPP acceptor role
|
|
||||||
|
|
||||||
This is the demo for user to use ESP_APIs to create a SPP acceptor.
|
|
||||||
|
|
||||||
Options choose step:
|
|
||||||
1. make menuconfig.
|
|
||||||
2. enter menuconfig "Component config", choose "Bluetooth"
|
|
||||||
3. enter menu Bluetooth, choose "Classic Bluetooth" and "SPP Profile"
|
|
||||||
4. choose your options.
|
|
||||||
|
|
||||||
Then set SPP_SHOW_MODE as SPP_SHOW_DATA or SPP_SHOW_SPEED in code(should be same with bt_spp_initator).
|
|
||||||
|
|
||||||
After the program started, bt_spp_initator will connect it and send data.
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
set(COMPONENT_SRCS "weasel.c fifostream.c pdmain.c \
|
set(COMPONENT_SRCS "espd.c pdmain.c \
|
||||||
../pd/src/g_canvas.c \
|
../pd/src/g_canvas.c \
|
||||||
../pd/src/g_graph.c \
|
../pd/src/g_graph.c \
|
||||||
../pd/src/g_text.c \
|
../pd/src/g_text.c \
|
||||||
|
|
@ -25,7 +25,12 @@ set(COMPONENT_SRCS "weasel.c fifostream.c pdmain.c \
|
||||||
../pd/src/d_osc.c \
|
../pd/src/d_osc.c \
|
||||||
../pd/src/d_ctl.c \
|
../pd/src/d_ctl.c \
|
||||||
../pd/src/d_arithmetic.c \
|
../pd/src/d_arithmetic.c \
|
||||||
|
../pd/src/d_array.c \
|
||||||
../pd/src/d_dac.c \
|
../pd/src/d_dac.c \
|
||||||
|
../pd/src/d_delay.c \
|
||||||
|
../pd/src/d_filter.c \
|
||||||
|
../pd/src/d_math.c \
|
||||||
|
../pd/src/d_misc.c \
|
||||||
../pd/src/x_arithmetic.c \
|
../pd/src/x_arithmetic.c \
|
||||||
../pd/src/x_connective.c \
|
../pd/src/x_connective.c \
|
||||||
../pd/src/x_interface.c \
|
../pd/src/x_interface.c \
|
||||||
|
|
@ -37,6 +42,9 @@ set(COMPONENT_SRCS "weasel.c fifostream.c pdmain.c \
|
||||||
../pd/src/x_scalar.c \
|
../pd/src/x_scalar.c \
|
||||||
../pd/src/x_text.c \
|
../pd/src/x_text.c \
|
||||||
../pd/src/x_list.c \
|
../pd/src/x_list.c \
|
||||||
|
../pd/src/x_vexp.c \
|
||||||
|
../pd/src/x_vexp_fun.c \
|
||||||
|
../pd/src/x_vexp_if.c \
|
||||||
")
|
")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
317
main/espd.c
Normal file
317
main/espd.c
Normal file
|
|
@ -0,0 +1,317 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, this
|
||||||
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "audio_element.h"
|
||||||
|
#include "audio_pipeline.h"
|
||||||
|
#include "audio_event_iface.h"
|
||||||
|
#include "audio_mem.h"
|
||||||
|
#include "audio_common.h"
|
||||||
|
#include "i2s_stream.h"
|
||||||
|
#include "mp3_decoder.h"
|
||||||
|
#include "filter_resample.h"
|
||||||
|
#include "board.h"
|
||||||
|
#include "esp_bt.h"
|
||||||
|
#include "esp_bt_main.h"
|
||||||
|
#include "esp_gap_bt_api.h"
|
||||||
|
#include "esp_bt_device.h"
|
||||||
|
#include "esp_spp_api.h"
|
||||||
|
#include "esp_peripherals.h"
|
||||||
|
#include "periph_sdcard.h"
|
||||||
|
#include "nvs.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
|
||||||
|
static const char *TAG = "ESPD";
|
||||||
|
#define TEST_I2S_NUM I2S_NUM_0
|
||||||
|
|
||||||
|
extern void pdmain_tick( void);
|
||||||
|
void pdmain_init( void);
|
||||||
|
|
||||||
|
void bt_init( void);
|
||||||
|
void sd_init( void);
|
||||||
|
|
||||||
|
#define INCHANS 1
|
||||||
|
#define OUTCHANS 1
|
||||||
|
#define BLKSIZE 64
|
||||||
|
float soundin[OUTCHANS * BLKSIZE], soundout[OUTCHANS * BLKSIZE];
|
||||||
|
|
||||||
|
void senddacs( void)
|
||||||
|
{
|
||||||
|
int i, ret;
|
||||||
|
size_t written;
|
||||||
|
short poodle[OUTCHANS * BLKSIZE];
|
||||||
|
|
||||||
|
for (i = 0; i < BLKSIZE; i+= OUTCHANS)
|
||||||
|
{
|
||||||
|
int ch1 = 32767*soundout[i];
|
||||||
|
if (ch1 > 32767)
|
||||||
|
ch1 = 32767;
|
||||||
|
else if (ch1 < -32768)
|
||||||
|
ch1 = -32768;
|
||||||
|
poodle[i] = ch1;
|
||||||
|
/*
|
||||||
|
ch1 = 32767*soundout[BLKSIZE+i];
|
||||||
|
if (ch1 > 32767)
|
||||||
|
ch1 = 32767;
|
||||||
|
else if (ch1 < -32768)
|
||||||
|
ch1 = -32768;
|
||||||
|
poodle[i+1] = ch2; */
|
||||||
|
|
||||||
|
soundout[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i2s_write(TEST_I2S_NUM, poodle, sizeof(poodle), &written,
|
||||||
|
portMAX_DELAY);
|
||||||
|
if (ret != ESP_OK)
|
||||||
|
ESP_LOGE(TAG, "error writing");
|
||||||
|
}
|
||||||
|
|
||||||
|
void pdmain_print( const char *s)
|
||||||
|
{
|
||||||
|
char y[80];
|
||||||
|
strncpy(y, s, 79);
|
||||||
|
y[79]=0;
|
||||||
|
ESP_LOGI(TAG, "%s", y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void trymem(int foo);
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
i2s_config_t i2s_cfg = {
|
||||||
|
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX,
|
||||||
|
.sample_rate = 48000,
|
||||||
|
.bits_per_sample = 16,
|
||||||
|
/* .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, */
|
||||||
|
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
|
||||||
|
.communication_format = I2S_COMM_FORMAT_I2S,
|
||||||
|
.dma_buf_count = 3,
|
||||||
|
.dma_buf_len = 300,
|
||||||
|
.use_apll = 1,
|
||||||
|
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL2,
|
||||||
|
};
|
||||||
|
i2s_pin_config_t i2s_pin_cfg = {0};
|
||||||
|
int zz = 0, ret;
|
||||||
|
|
||||||
|
pdmain_init();
|
||||||
|
|
||||||
|
esp_log_level_set("*", ESP_LOG_WARN);
|
||||||
|
esp_log_level_set(TAG, ESP_LOG_INFO);
|
||||||
|
ESP_LOGI(TAG, "[ 1 ] Start audio codec chip");
|
||||||
|
|
||||||
|
audio_board_handle_t board_handle = audio_board_init();
|
||||||
|
audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);
|
||||||
|
|
||||||
|
i2s_driver_install(I2S_NUM_0, &i2s_cfg, 0, NULL);
|
||||||
|
get_i2s_pins(I2S_NUM_0, &i2s_pin_cfg);
|
||||||
|
i2s_set_pin(I2S_NUM_0, &i2s_pin_cfg);
|
||||||
|
i2s_mclk_gpio_select(I2S_NUM_0, GPIO_NUM_0);
|
||||||
|
|
||||||
|
bt_init();
|
||||||
|
sd_init();
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "[ 2 ] now write some shit");
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* if (!((zz++)%1000))
|
||||||
|
{
|
||||||
|
trymem(5);
|
||||||
|
ESP_LOGI(TAG, "tick");
|
||||||
|
} */
|
||||||
|
pdmain_tick();
|
||||||
|
senddacs();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------- bluetooth and SD card ------------------ */
|
||||||
|
|
||||||
|
void pd_dispatch_bt(char *data, size_t size);
|
||||||
|
|
||||||
|
static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_CB;
|
||||||
|
static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_AUTHENTICATE;
|
||||||
|
static const esp_spp_role_t role_slave = ESP_SPP_ROLE_SLAVE;
|
||||||
|
|
||||||
|
static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
||||||
|
{
|
||||||
|
switch (event) {
|
||||||
|
case ESP_SPP_INIT_EVT:
|
||||||
|
ESP_LOGI(TAG, "ESP_SPP_INIT_EVT");
|
||||||
|
esp_bt_dev_set_device_name("pure_data");
|
||||||
|
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
|
||||||
|
esp_spp_start_srv(sec_mask,role_slave, 0, "pd_server");
|
||||||
|
break;
|
||||||
|
case ESP_SPP_DISCOVERY_COMP_EVT:
|
||||||
|
ESP_LOGI(TAG, "ESP_SPP_DISCOVERY_COMP_EVT");
|
||||||
|
break;
|
||||||
|
case ESP_SPP_OPEN_EVT:
|
||||||
|
ESP_LOGI(TAG, "ESP_SPP_OPEN_EVT");
|
||||||
|
break;
|
||||||
|
case ESP_SPP_CLOSE_EVT:
|
||||||
|
ESP_LOGI(TAG, "ESP_SPP_CLOSE_EVT");
|
||||||
|
break;
|
||||||
|
case ESP_SPP_START_EVT:
|
||||||
|
ESP_LOGI(TAG, "ESP_SPP_START_EVT");
|
||||||
|
break;
|
||||||
|
case ESP_SPP_CL_INIT_EVT:
|
||||||
|
ESP_LOGI(TAG, "ESP_SPP_CL_INIT_EVT");
|
||||||
|
break;
|
||||||
|
case ESP_SPP_DATA_IND_EVT:
|
||||||
|
|
||||||
|
if (param->data_ind.len > 2)
|
||||||
|
ESP_LOGI(TAG, "ESP_SPP_DATA_IND_EVT len=%d handle=%d",
|
||||||
|
param->data_ind.len, param->data_ind.handle);
|
||||||
|
|
||||||
|
pd_dispatch_bt((char *)(param->data_ind.data), param->data_ind.len);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ESP_SPP_CONG_EVT:
|
||||||
|
ESP_LOGI(TAG, "ESP_SPP_CONG_EVT");
|
||||||
|
break;
|
||||||
|
case ESP_SPP_WRITE_EVT:
|
||||||
|
ESP_LOGI(TAG, "ESP_SPP_WRITE_EVT");
|
||||||
|
break;
|
||||||
|
case ESP_SPP_SRV_OPEN_EVT:
|
||||||
|
ESP_LOGI(TAG, "ESP_SPP_SRV_OPEN_EVT");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
|
||||||
|
{
|
||||||
|
switch (event) {
|
||||||
|
case ESP_BT_GAP_AUTH_CMPL_EVT:{
|
||||||
|
if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
|
||||||
|
ESP_LOGI(TAG, "authentication success: %s", param->auth_cmpl.device_name);
|
||||||
|
esp_log_buffer_hex(TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ESP_BT_GAP_PIN_REQ_EVT:{
|
||||||
|
ESP_LOGI(TAG, "ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
|
||||||
|
if (param->pin_req.min_16_digit) {
|
||||||
|
ESP_LOGI(TAG, "Input pin code: 0000 0000 0000 0000");
|
||||||
|
esp_bt_pin_code_t pin_code = {0};
|
||||||
|
esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "Input pin code: 1234");
|
||||||
|
esp_bt_pin_code_t pin_code;
|
||||||
|
pin_code[0] = '1';
|
||||||
|
pin_code[1] = '2';
|
||||||
|
pin_code[2] = '3';
|
||||||
|
pin_code[3] = '4';
|
||||||
|
esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (CONFIG_BT_SSP_ENABLED == true)
|
||||||
|
case ESP_BT_GAP_CFM_REQ_EVT:
|
||||||
|
ESP_LOGI(TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
|
||||||
|
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
|
||||||
|
break;
|
||||||
|
case ESP_BT_GAP_KEY_NOTIF_EVT:
|
||||||
|
ESP_LOGI(TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
|
||||||
|
break;
|
||||||
|
case ESP_BT_GAP_KEY_REQ_EVT:
|
||||||
|
ESP_LOGI(TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default: {
|
||||||
|
ESP_LOGI(TAG, "event: %d", event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_init( void)
|
||||||
|
{
|
||||||
|
esp_err_t ret = nvs_flash_init();
|
||||||
|
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
ret = nvs_flash_init();
|
||||||
|
}
|
||||||
|
ESP_ERROR_CHECK( ret );
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
|
||||||
|
|
||||||
|
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||||
|
if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = esp_bluedroid_init()) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = esp_bluedroid_enable()) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = esp_bt_gap_register_callback(esp_bt_gap_cb)) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s gap register failed: %s\n", __func__, esp_err_to_name(ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = esp_spp_register_callback(esp_spp_cb)) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s spp register failed: %s\n", __func__, esp_err_to_name(ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = esp_spp_init(esp_spp_mode)) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "%s spp init failed: %s\n", __func__, esp_err_to_name(ret));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (CONFIG_BT_SSP_ENABLED == true)
|
||||||
|
/* Set default parameters for Secure Simple Pairing */
|
||||||
|
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
|
||||||
|
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
|
||||||
|
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set default parameters for Legacy Pairing
|
||||||
|
* Use variable pin, input pin code when pairing
|
||||||
|
*/
|
||||||
|
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
|
||||||
|
esp_bt_pin_code_t pin_code;
|
||||||
|
esp_bt_gap_set_pin(pin_type, 0, pin_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sd_init( void)
|
||||||
|
{
|
||||||
|
/* initialize SD card */
|
||||||
|
ESP_LOGI(TAG, "[ 1 ] Mount sdcard");
|
||||||
|
// Initialize peripherals management
|
||||||
|
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
|
||||||
|
esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg);
|
||||||
|
|
||||||
|
// Initialize SD Card peripheral
|
||||||
|
audio_board_sdcard_init(set, SD_MODE_1_LINE);
|
||||||
|
}
|
||||||
|
|
@ -1,200 +0,0 @@
|
||||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "audio_error.h"
|
|
||||||
#include "audio_mem.h"
|
|
||||||
#include "audio_element.h"
|
|
||||||
#include "fifostream.h"
|
|
||||||
#include "audio_type_def.h"
|
|
||||||
static const char *TAG = "fifostream";
|
|
||||||
|
|
||||||
#define CHANS 2
|
|
||||||
#define INCHANS CHANS
|
|
||||||
#define OUTCHANS CHANS
|
|
||||||
#define BLKSIZE 64
|
|
||||||
#define BLK_BYTES (BLKSIZE*CHANS*sizeof(short))
|
|
||||||
|
|
||||||
extern void pdmain_tick( void);
|
|
||||||
|
|
||||||
typedef struct fifostream {
|
|
||||||
int samplerate;
|
|
||||||
int channel;
|
|
||||||
short *s_buf;
|
|
||||||
int byte_num;
|
|
||||||
int at_eof;
|
|
||||||
} fifostream_t;
|
|
||||||
|
|
||||||
static esp_err_t fifostream_destroy(audio_element_handle_t self)
|
|
||||||
{
|
|
||||||
fifostream_t *fifostream = (fifostream_t *)audio_element_getdata(self);
|
|
||||||
audio_free(fifostream);
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static esp_err_t fifostream_open(audio_element_handle_t self)
|
|
||||||
{
|
|
||||||
ESP_LOGD(TAG, "fifostream_open");
|
|
||||||
fifostream_t *fifostream = (fifostream_t *)audio_element_getdata(self);
|
|
||||||
audio_element_info_t info = {0};
|
|
||||||
audio_element_getinfo(self, &info);
|
|
||||||
if (info.sample_rates
|
|
||||||
&& info.channels) {
|
|
||||||
fifostream->samplerate = info.sample_rates;
|
|
||||||
fifostream->channel = info.channels;
|
|
||||||
}
|
|
||||||
fifostream->at_eof = 0;
|
|
||||||
fifostream->s_buf = (short *)calloc(sizeof(short), BLK_BYTES/sizeof(short));
|
|
||||||
if (fifostream->s_buf == NULL) {
|
|
||||||
ESP_LOGE(TAG, "calloc buffer failed. (line %d)", __LINE__);
|
|
||||||
return ESP_ERR_NO_MEM;
|
|
||||||
}
|
|
||||||
memset(fifostream->s_buf, 0, BLK_BYTES);
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static esp_err_t fifostream_close(audio_element_handle_t self)
|
|
||||||
{
|
|
||||||
ESP_LOGD(TAG, "fifostream_close");
|
|
||||||
fifostream_t *fifostream = (fifostream_t *)audio_element_getdata(self);
|
|
||||||
if (fifostream->s_buf == NULL) {
|
|
||||||
audio_free(fifostream->s_buf);
|
|
||||||
fifostream->s_buf = NULL;
|
|
||||||
}
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
float soundin[OUTCHANS * BLKSIZE], soundout[OUTCHANS * BLKSIZE];
|
|
||||||
|
|
||||||
#if 0 /* better one that doesn't work for some reason */
|
|
||||||
static int fifostream_process(audio_element_handle_t self, char *in_buffer,
|
|
||||||
int in_len)
|
|
||||||
{
|
|
||||||
static int cumsamps = 0;
|
|
||||||
fifostream_t *fifostream = (fifostream_t *)audio_element_getdata(self);
|
|
||||||
int ret = 0;
|
|
||||||
int r_size = (fifostream->at_eof ? 0 :
|
|
||||||
audio_element_input(self, (char *)fifostream->s_buf, BLK_BYTES));
|
|
||||||
if (r_size >= BLK_BYTES)
|
|
||||||
{
|
|
||||||
int i, nsamps = BLKSIZE;
|
|
||||||
fifostream->byte_num += BLK_BYTES;
|
|
||||||
|
|
||||||
for (i = 0; i < BLKSIZE; i+= 2)
|
|
||||||
{
|
|
||||||
soundin[i] = fifostream->s_buf[i]/32768;;
|
|
||||||
soundin[BLKSIZE+i] = fifostream->s_buf[i+1]/32768;
|
|
||||||
}
|
|
||||||
pdmain_tick();
|
|
||||||
for (i = 0; i < BLKSIZE; i+= 2)
|
|
||||||
{
|
|
||||||
int ch1 = 32767*soundout[i], ch2 = 32767*soundout[BLKSIZE+i];
|
|
||||||
if (ch1 > 32767)
|
|
||||||
ch1 = 32767;
|
|
||||||
else if (ch1 < -32768)
|
|
||||||
ch1 = -32768;
|
|
||||||
if (ch2 > 32767)
|
|
||||||
ch2 = 32767;
|
|
||||||
else if (ch2 < -32768)
|
|
||||||
ch2 = -32768;
|
|
||||||
fifostream->s_buf[i] = (short)ch1;
|
|
||||||
fifostream->s_buf[i+1] = (short)ch2;
|
|
||||||
}
|
|
||||||
ret = audio_element_output(self, (char *)fifostream->s_buf, BLK_BYTES);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fifostream->at_eof = 1;
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
static int fifostream_process(audio_element_handle_t self, char *in_buffer, int in_len)
|
|
||||||
{
|
|
||||||
static int cumsamps = 0;
|
|
||||||
fifostream_t *fifostream = (fifostream_t *)audio_element_getdata(self);
|
|
||||||
int ret = 0;
|
|
||||||
int r_size = 0;
|
|
||||||
if (fifostream->at_eof == 0) {
|
|
||||||
r_size = audio_element_input(self, (char *)fifostream->s_buf, BLK_BYTES);
|
|
||||||
}
|
|
||||||
if (r_size > 0) {
|
|
||||||
if (r_size != BLK_BYTES) {
|
|
||||||
fifostream->at_eof = 1;
|
|
||||||
}
|
|
||||||
fifostream->byte_num += r_size;
|
|
||||||
{
|
|
||||||
int i, nsamps = r_size/(2*sizeof(short));
|
|
||||||
static int phase;
|
|
||||||
if (nsamps * 2 * sizeof(short) != r_size)
|
|
||||||
ESP_LOGE("WOMBAT", "odd sample frame size %d", r_size);
|
|
||||||
for (i = 0; i < nsamps; i++)
|
|
||||||
{
|
|
||||||
int ch1 = 32767*soundout[i], ch2 = 32767*soundout[BLKSIZE+i];
|
|
||||||
if (ch1 > 32767)
|
|
||||||
ch1 = 32767;
|
|
||||||
else if (ch1 < -32768)
|
|
||||||
ch1 = -32768;
|
|
||||||
if (ch2 > 32767)
|
|
||||||
ch2 = 32767;
|
|
||||||
else if (ch2 < -32768)
|
|
||||||
ch2 = -32768;
|
|
||||||
soundin[phase] = fifostream->s_buf[2*i]/32768;
|
|
||||||
fifostream->s_buf[2*i] = ch1;
|
|
||||||
soundin[BLKSIZE+phase] = fifostream->s_buf[2*i+1]/32768;
|
|
||||||
fifostream->s_buf[2*i+1] = ch2;
|
|
||||||
phase++;
|
|
||||||
if (phase == BLKSIZE)
|
|
||||||
{
|
|
||||||
pdmain_tick();
|
|
||||||
phase = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = audio_element_output(self, (char *)fifostream->s_buf, BLK_BYTES);
|
|
||||||
} else {
|
|
||||||
ret = r_size;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
audio_element_handle_t fifostream_init(fifostream_cfg_t *config)
|
|
||||||
{
|
|
||||||
if (config == NULL) {
|
|
||||||
ESP_LOGE(TAG, "config is NULL. (line %d)", __LINE__);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
fifostream_t *fifostream = audio_calloc(1, sizeof(fifostream_t));
|
|
||||||
AUDIO_MEM_CHECK(TAG, fifostream, return NULL);
|
|
||||||
if (fifostream == NULL) {
|
|
||||||
ESP_LOGE(TAG, "audio_calloc failed for fifostream. (line %d)", __LINE__);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
audio_element_cfg_t cfg = DEFAULT_AUDIO_ELEMENT_CONFIG();
|
|
||||||
cfg.destroy = fifostream_destroy;
|
|
||||||
cfg.process = fifostream_process;
|
|
||||||
cfg.open = fifostream_open;
|
|
||||||
cfg.close = fifostream_close;
|
|
||||||
cfg.buffer_len = 0;
|
|
||||||
cfg.tag = "fifostream";
|
|
||||||
cfg.task_stack = config->task_stack;
|
|
||||||
cfg.task_prio = config->task_prio;
|
|
||||||
cfg.task_core = config->task_core;
|
|
||||||
cfg.out_rb_size = config->out_rb_size;
|
|
||||||
cfg.stack_in_ext = config->stack_in_ext;
|
|
||||||
audio_element_handle_t el = audio_element_init(&cfg);
|
|
||||||
AUDIO_MEM_CHECK(TAG, el, {audio_free(fifostream); return NULL;});
|
|
||||||
fifostream->samplerate = config->samplerate;
|
|
||||||
fifostream->channel = config->channel;
|
|
||||||
audio_element_setdata(el, fifostream);
|
|
||||||
audio_element_info_t info = {0};
|
|
||||||
audio_element_setinfo(el, &info);
|
|
||||||
ESP_LOGD(TAG, "fifostream_init");
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
#ifndef _FIFOSTREAM_H_
|
|
||||||
#define _FIFOSTREAM_H_
|
|
||||||
|
|
||||||
#include "esp_err.h"
|
|
||||||
#include "audio_element.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Configuration
|
|
||||||
*/
|
|
||||||
typedef struct fifostream_cfg {
|
|
||||||
int samplerate; /*!< Audio sample rate (in Hz)*/
|
|
||||||
int channel; /*!< Number of audio channels (Mono=1, Dual=2) */
|
|
||||||
int *set_gain; /*!< Equalizer gain */
|
|
||||||
int out_rb_size; /*!< Size of output ring buffer */
|
|
||||||
int task_stack; /*!< Task stack size */
|
|
||||||
int task_core; /*!< Task running in core...*/
|
|
||||||
int task_prio; /*!< Task priority*/
|
|
||||||
bool stack_in_ext; /*!< Try to allocate stack in external memory */
|
|
||||||
} fifostream_cfg_t;
|
|
||||||
|
|
||||||
#define FIFOSTREAM_TASK_STACK (20000)
|
|
||||||
#define FIFOSTREAM_TASK_CORE (0)
|
|
||||||
#define FIFOSTREAM_TASK_PRIO (5)
|
|
||||||
#define FIFOSTREAM_RINGBUFFER_SIZE (8 * 1024)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @note `set_value_gain` is defined in c file.
|
|
||||||
* values is {-13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13};
|
|
||||||
*/
|
|
||||||
extern int set_value_gain[];
|
|
||||||
|
|
||||||
#define DEFAULT_FIFOSTREAM_CONFIG() { \
|
|
||||||
.samplerate = 48000, \
|
|
||||||
.channel = 1, \
|
|
||||||
.set_gain = set_value_gain, \
|
|
||||||
.out_rb_size = FIFOSTREAM_RINGBUFFER_SIZE, \
|
|
||||||
.task_stack = FIFOSTREAM_TASK_STACK, \
|
|
||||||
.task_core = FIFOSTREAM_TASK_CORE, \
|
|
||||||
.task_prio = FIFOSTREAM_TASK_PRIO, \
|
|
||||||
.stack_in_ext = true, \
|
|
||||||
}
|
|
||||||
|
|
||||||
audio_element_handle_t fifostream_init(fifostream_cfg_t *config);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
void pd_init(void);
|
void pd_init(void);
|
||||||
void glob_open(t_pd *ignore, t_symbol *name, t_symbol *dir, t_floatarg f);
|
void glob_open(t_pd *ignore, t_symbol *name, t_symbol *dir, t_floatarg f);
|
||||||
|
|
@ -29,22 +30,18 @@ canvas 274 279 752 643 12;\n\
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char patchfile[] = "\
|
static const char patchfile[] = "\
|
||||||
canvas 0 50 604 482 12;\n\
|
canvas 0 50 450 300 12;\n\
|
||||||
#X obj 179 99 r foo;\n\
|
#X obj 190 104 loadbang;\n\
|
||||||
#X obj 179 124 osc~ 880;\n\
|
#X msg 190 129 \; pd dsp 1;\n\
|
||||||
#X obj 179 149 dac~ 1;\n\
|
#X obj 118 123 dac~ 1;\n\
|
||||||
#X obj 257 127 osc~ 880;\n\
|
#X obj 118 98 osc~ 440;\n\
|
||||||
#X obj 257 102 r foo2;\n\
|
|
||||||
#X obj 257 151 dac~ 2;\n\
|
|
||||||
#X connect 0 0 1 0;\n\
|
#X connect 0 0 1 0;\n\
|
||||||
#X connect 1 0 2 0;\n\
|
#X connect 3 0 2 0;\n\
|
||||||
#X connect 3 0 5 0;\n\
|
|
||||||
#X connect 4 0 3 0;\n\
|
|
||||||
";
|
";
|
||||||
|
|
||||||
static void trymem(int foo)
|
void trymem(int foo)
|
||||||
{
|
{
|
||||||
#if 0
|
#if 1
|
||||||
int i;
|
int i;
|
||||||
char msg[80];
|
char msg[80];
|
||||||
for (i = 1; i < 500; i++)
|
for (i = 1; i < 500; i++)
|
||||||
|
|
@ -74,10 +71,19 @@ void pd_dispatch_bt(char *data, size_t size)
|
||||||
|
|
||||||
void pd_poll_bt( void)
|
void pd_poll_bt( void)
|
||||||
{
|
{
|
||||||
|
int lastchar;
|
||||||
static t_binbuf *b;
|
static t_binbuf *b;
|
||||||
if (!b)
|
if (!b)
|
||||||
|
{
|
||||||
b = binbuf_new();
|
b = binbuf_new();
|
||||||
if (pd_bt_size)
|
post("new binbuf %x", b);
|
||||||
|
}
|
||||||
|
/* only interpret this text if terminated by a semicolon */
|
||||||
|
lastchar = pd_bt_size-1;
|
||||||
|
while (lastchar >= 0 && isspace((int)(pd_bt_buf[lastchar])))
|
||||||
|
lastchar--;
|
||||||
|
if (lastchar >= 3 && pd_bt_buf[lastchar] == ';' &&
|
||||||
|
pd_bt_buf[lastchar-1] != '\\')
|
||||||
{
|
{
|
||||||
binbuf_text(b, pd_bt_buf, pd_bt_size);
|
binbuf_text(b, pd_bt_buf, pd_bt_size);
|
||||||
binbuf_eval(b, 0, 0, 0);
|
binbuf_eval(b, 0, 0, 0);
|
||||||
|
|
@ -87,41 +93,35 @@ void pd_poll_bt( void)
|
||||||
}
|
}
|
||||||
|
|
||||||
extern float soundin[], soundout[];
|
extern float soundin[], soundout[];
|
||||||
|
void canvas_start_dsp( void);
|
||||||
void pdmain_init( void)
|
void pdmain_init( void)
|
||||||
{
|
{
|
||||||
t_binbuf *b;
|
t_binbuf *b;
|
||||||
|
|
||||||
sys_printhook = pdmain_print;
|
sys_printhook = pdmain_print;
|
||||||
trymem(1); // 111
|
trymem(1);
|
||||||
pd_init();
|
pd_init();
|
||||||
trymem(2); // 47
|
trymem(2);
|
||||||
STUFF->st_dacsr = sys_getsr();
|
STUFF->st_dacsr = sys_getsr();
|
||||||
STUFF->st_soundout = soundout;
|
STUFF->st_soundout = soundout;
|
||||||
STUFF->st_soundin = soundin;
|
STUFF->st_soundin = soundin;
|
||||||
|
|
||||||
|
#if 0
|
||||||
b = binbuf_new();
|
b = binbuf_new();
|
||||||
glob_setfilename(0, gensym("main-patch"), gensym("."));
|
glob_setfilename(0, gensym("main-patch"), gensym("."));
|
||||||
binbuf_text(b, patchfile, strlen(patchfile));
|
binbuf_text(b, patchfile, strlen(patchfile));
|
||||||
binbuf_eval(b, &pd_canvasmaker, 0, 0);
|
binbuf_eval(b, &pd_canvasmaker, 0, 0);
|
||||||
canvas_loadbang((t_canvas *)s__X.s_thing);
|
canvas_loadbang((t_canvas *)s__X.s_thing);
|
||||||
vmess(s__X.s_thing, gensym("pop"), "i", 0);
|
vmess(s__X.s_thing, gensym("pop"), "i", 0);
|
||||||
|
|
||||||
glob_setfilename(0, &s_, &s_);
|
glob_setfilename(0, &s_, &s_);
|
||||||
binbuf_free(b);
|
binbuf_free(b);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void pdmain_tick( void)
|
void pdmain_tick( void)
|
||||||
{
|
{
|
||||||
static int initted;
|
memset(soundout, 0, 64*sizeof(float));
|
||||||
if (!initted)
|
|
||||||
{
|
|
||||||
pdmain_init();
|
|
||||||
initted = 1;
|
|
||||||
}
|
|
||||||
memset(soundout, 0, 128*sizeof(float));
|
|
||||||
pd_poll_bt();
|
pd_poll_bt();
|
||||||
sched_tick();
|
sched_tick();
|
||||||
}
|
}
|
||||||
|
|
@ -132,9 +132,34 @@ t_class *glob_pdobject;
|
||||||
|
|
||||||
static void glob_foo(void *dummy, t_floatarg f)
|
static void glob_foo(void *dummy, t_floatarg f)
|
||||||
{
|
{
|
||||||
post("foo %f", f);
|
trymem(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void glob_beginnew(void *dummy, t_symbol *pname, t_symbol *pdir)
|
||||||
|
{
|
||||||
|
glob_setfilename(0, pname, pdir);
|
||||||
|
pd_bind(&pd_canvasmaker, &s__N);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void glob_endnew(void *dummy)
|
||||||
|
{
|
||||||
|
pd_unbind(&pd_canvasmaker, &s__N);
|
||||||
|
if ((t_canvas *)s__X.s_thing)
|
||||||
|
{
|
||||||
|
canvas_loadbang((t_canvas *)s__X.s_thing);
|
||||||
|
vmess(s__X.s_thing, gensym("pop"), "i", 0);
|
||||||
|
}
|
||||||
|
glob_setfilename(0, &s_, &s_);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void glob_close(void *dummy, t_symbol *pname)
|
||||||
|
{
|
||||||
|
t_pd *c = pd_findbyclass(pname, canvas_class);
|
||||||
|
if (c)
|
||||||
|
pd_free(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv);
|
void glob_dsp(void *dummy, t_symbol *s, int argc, t_atom *argv);
|
||||||
|
|
||||||
void glob_init( void)
|
void glob_init( void)
|
||||||
|
|
@ -145,6 +170,12 @@ void glob_init( void)
|
||||||
A_GIMME, 0);
|
A_GIMME, 0);
|
||||||
class_addmethod(glob_pdobject, (t_method)glob_foo, gensym("foo"),
|
class_addmethod(glob_pdobject, (t_method)glob_foo, gensym("foo"),
|
||||||
A_DEFFLOAT, 0);
|
A_DEFFLOAT, 0);
|
||||||
|
class_addmethod(glob_pdobject, (t_method)glob_beginnew, gensym("begin-new"),
|
||||||
|
A_SYMBOL, A_SYMBOL, 0);
|
||||||
|
class_addmethod(glob_pdobject, (t_method)glob_close, gensym("close"),
|
||||||
|
A_SYMBOL, 0);
|
||||||
|
class_addmethod(glob_pdobject, (t_method)glob_endnew, gensym("end-new"),
|
||||||
|
0);
|
||||||
pd_bind(&glob_pdobject, gensym("pd"));
|
pd_bind(&glob_pdobject, gensym("pd"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,7 +240,6 @@ void conf_init(void)
|
||||||
g_guiconnect_setup();
|
g_guiconnect_setup();
|
||||||
g_scalar_setup();
|
g_scalar_setup();
|
||||||
g_template_setup();
|
g_template_setup();
|
||||||
clone_setup();
|
|
||||||
m_pd_setup();
|
m_pd_setup();
|
||||||
x_acoustics_setup();
|
x_acoustics_setup();
|
||||||
x_interface_setup();
|
x_interface_setup();
|
||||||
|
|
@ -228,23 +258,25 @@ void conf_init(void)
|
||||||
d_dac_setup();
|
d_dac_setup();
|
||||||
d_ctl_setup();
|
d_ctl_setup();
|
||||||
d_osc_setup();
|
d_osc_setup();
|
||||||
trymem(11);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
d_arithmetic_setup();
|
d_arithmetic_setup();
|
||||||
d_array_setup();
|
d_array_setup();
|
||||||
|
clone_setup();
|
||||||
d_delay_setup();
|
d_delay_setup();
|
||||||
d_filter_setup();
|
d_filter_setup();
|
||||||
d_math_setup();
|
d_math_setup();
|
||||||
d_misc_setup();
|
d_misc_setup();
|
||||||
|
expr_setup();
|
||||||
|
trymem(11);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
g_traversal_setup();
|
g_traversal_setup();
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ------- STUBS that do nothing ------------- */
|
/* ------- STUBS that do nothing ------------- */
|
||||||
int sys_get_outchannels(void) {return(2); }
|
int sys_get_outchannels(void) {return(2); }
|
||||||
int sys_get_inchannels(void) {return(2); }
|
int sys_get_inchannels(void) {return(2); }
|
||||||
float sys_getsr( void) {return (44100);}
|
float sys_getsr( void) {return (48000);}
|
||||||
int sys_getblksize(void) { return (DEFDACBLKSIZE); }
|
int sys_getblksize(void) { return (DEFDACBLKSIZE); }
|
||||||
|
|
||||||
int pd_compatibilitylevel = 100;
|
int pd_compatibilitylevel = 100;
|
||||||
|
|
@ -323,6 +355,8 @@ void x_midi_newpdinstance( void) {}
|
||||||
t_symbol *iemgui_raute2dollar(t_symbol *s) {return(s);}
|
t_symbol *iemgui_raute2dollar(t_symbol *s) {return(s);}
|
||||||
t_symbol *iemgui_dollar2raute(t_symbol *s) {return(s);}
|
t_symbol *iemgui_dollar2raute(t_symbol *s) {return(s);}
|
||||||
|
|
||||||
|
t_class *clone_class;
|
||||||
|
|
||||||
/* --------------- m_sched.c -------------------- */
|
/* --------------- m_sched.c -------------------- */
|
||||||
#define TIMEUNITPERMSEC (32. * 441.)
|
#define TIMEUNITPERMSEC (32. * 441.)
|
||||||
#define TIMEUNITPERSECOND (TIMEUNITPERMSEC * 1000.)
|
#define TIMEUNITPERSECOND (TIMEUNITPERMSEC * 1000.)
|
||||||
|
|
|
||||||
354
main/weasel.c
354
main/weasel.c
|
|
@ -1,354 +0,0 @@
|
||||||
/*
|
|
||||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, this
|
|
||||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
||||||
CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "nvs.h"
|
|
||||||
#include "nvs_flash.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "audio_pipeline.h"
|
|
||||||
#include "i2s_stream.h"
|
|
||||||
#include "board.h"
|
|
||||||
#include "fifostream.h"
|
|
||||||
#include "esp_bt.h"
|
|
||||||
#include "esp_bt_main.h"
|
|
||||||
#include "esp_gap_bt_api.h"
|
|
||||||
#include "esp_bt_device.h"
|
|
||||||
#include "esp_spp_api.h"
|
|
||||||
|
|
||||||
#include "time.h"
|
|
||||||
#include "sys/time.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define SPP_TAG "WOMBAT"
|
|
||||||
#define SPP_SERVER_NAME "SPP_SERVER"
|
|
||||||
#define EXCAMPLE_DEVICE_NAME "ESP_SPP_ACCEPTOR"
|
|
||||||
#define SPP_SHOW_DATA 0
|
|
||||||
#define SPP_SHOW_SPEED 1
|
|
||||||
#define SPP_SHOW_MODE SPP_SHOW_DATA /*Choose show mode: show data or speed*/
|
|
||||||
|
|
||||||
void pdmain_print( const char *s)
|
|
||||||
{
|
|
||||||
ESP_LOGI("PD", "%s" , s);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_CB;
|
|
||||||
|
|
||||||
static struct timeval time_new, time_old;
|
|
||||||
static long data_num = 0;
|
|
||||||
|
|
||||||
static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_AUTHENTICATE;
|
|
||||||
static const esp_spp_role_t role_slave = ESP_SPP_ROLE_SLAVE;
|
|
||||||
|
|
||||||
static void print_speed(void)
|
|
||||||
{
|
|
||||||
float time_old_s = time_old.tv_sec + time_old.tv_usec / 1000000.0;
|
|
||||||
float time_new_s = time_new.tv_sec + time_new.tv_usec / 1000000.0;
|
|
||||||
float time_interval = time_new_s - time_old_s;
|
|
||||||
float speed = data_num * 8 / time_interval / 1000.0;
|
|
||||||
ESP_LOGI(SPP_TAG, "speed(%fs ~ %fs): %f kbit/s" , time_old_s, time_new_s, speed);
|
|
||||||
data_num = 0;
|
|
||||||
time_old.tv_sec = time_new.tv_sec;
|
|
||||||
time_old.tv_usec = time_new.tv_usec;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern int phaseinc;
|
|
||||||
void pd_dispatch_bt(char *data, size_t size);
|
|
||||||
|
|
||||||
static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
|
||||||
{
|
|
||||||
switch (event) {
|
|
||||||
case ESP_SPP_INIT_EVT:
|
|
||||||
ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
|
|
||||||
esp_bt_dev_set_device_name(EXCAMPLE_DEVICE_NAME);
|
|
||||||
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
|
|
||||||
esp_spp_start_srv(sec_mask,role_slave, 0, SPP_SERVER_NAME);
|
|
||||||
break;
|
|
||||||
case ESP_SPP_DISCOVERY_COMP_EVT:
|
|
||||||
ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT");
|
|
||||||
break;
|
|
||||||
case ESP_SPP_OPEN_EVT:
|
|
||||||
ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT");
|
|
||||||
break;
|
|
||||||
case ESP_SPP_CLOSE_EVT:
|
|
||||||
ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT");
|
|
||||||
break;
|
|
||||||
case ESP_SPP_START_EVT:
|
|
||||||
ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
|
|
||||||
break;
|
|
||||||
case ESP_SPP_CL_INIT_EVT:
|
|
||||||
ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT");
|
|
||||||
break;
|
|
||||||
case ESP_SPP_DATA_IND_EVT:
|
|
||||||
|
|
||||||
ESP_LOGI(SPP_TAG, "ESP_SPP_DATA_IND_EVT len=%d handle=%d",
|
|
||||||
param->data_ind.len, param->data_ind.handle);
|
|
||||||
esp_log_buffer_hex("",param->data_ind.data,param->data_ind.len);
|
|
||||||
{
|
|
||||||
#if 1
|
|
||||||
pd_dispatch_bt((char *)(param->data_ind.data),
|
|
||||||
param->data_ind.len);
|
|
||||||
#else
|
|
||||||
char foo[80];
|
|
||||||
int nfoo = (param->data_ind.len > 78 ? 78 : param->data_ind.len), i;
|
|
||||||
for (i = 0; i < nfoo; i++)
|
|
||||||
foo[i] = param->data_ind.data[i];
|
|
||||||
foo[i] = 0;
|
|
||||||
ESP_LOGI(SPP_TAG, "%s", foo);
|
|
||||||
sscanf(foo, "%d%d", &i, &phaseinc);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case ESP_SPP_CONG_EVT:
|
|
||||||
ESP_LOGI(SPP_TAG, "ESP_SPP_CONG_EVT");
|
|
||||||
break;
|
|
||||||
case ESP_SPP_WRITE_EVT:
|
|
||||||
ESP_LOGI(SPP_TAG, "ESP_SPP_WRITE_EVT");
|
|
||||||
break;
|
|
||||||
case ESP_SPP_SRV_OPEN_EVT:
|
|
||||||
ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
|
|
||||||
gettimeofday(&time_old, NULL);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
|
|
||||||
{
|
|
||||||
switch (event) {
|
|
||||||
case ESP_BT_GAP_AUTH_CMPL_EVT:{
|
|
||||||
if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
|
|
||||||
ESP_LOGI(SPP_TAG, "authentication success: %s", param->auth_cmpl.device_name);
|
|
||||||
esp_log_buffer_hex(SPP_TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
|
|
||||||
} else {
|
|
||||||
ESP_LOGE(SPP_TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ESP_BT_GAP_PIN_REQ_EVT:{
|
|
||||||
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
|
|
||||||
if (param->pin_req.min_16_digit) {
|
|
||||||
ESP_LOGI(SPP_TAG, "Input pin code: 0000 0000 0000 0000");
|
|
||||||
esp_bt_pin_code_t pin_code = {0};
|
|
||||||
esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
|
|
||||||
} else {
|
|
||||||
ESP_LOGI(SPP_TAG, "Input pin code: 1234");
|
|
||||||
esp_bt_pin_code_t pin_code;
|
|
||||||
pin_code[0] = '1';
|
|
||||||
pin_code[1] = '2';
|
|
||||||
pin_code[2] = '3';
|
|
||||||
pin_code[3] = '4';
|
|
||||||
esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (CONFIG_BT_SSP_ENABLED == true)
|
|
||||||
case ESP_BT_GAP_CFM_REQ_EVT:
|
|
||||||
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
|
|
||||||
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
|
|
||||||
break;
|
|
||||||
case ESP_BT_GAP_KEY_NOTIF_EVT:
|
|
||||||
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
|
|
||||||
break;
|
|
||||||
case ESP_BT_GAP_KEY_REQ_EVT:
|
|
||||||
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
default: {
|
|
||||||
ESP_LOGI(SPP_TAG, "event: %d", event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
void audio_main(void)
|
|
||||||
{
|
|
||||||
audio_pipeline_handle_t pipeline;
|
|
||||||
audio_element_handle_t i2s_stream_writer, i2s_stream_reader, fifostream;
|
|
||||||
|
|
||||||
esp_log_level_set("*", ESP_LOG_INFO);
|
|
||||||
esp_log_level_set(SPP_TAG, ESP_LOG_DEBUG);
|
|
||||||
|
|
||||||
|
|
||||||
ESP_LOGI(SPP_TAG, "[ 1 ] Start codec chip");
|
|
||||||
audio_board_handle_t board_handle = audio_board_init();
|
|
||||||
|
|
||||||
audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START);
|
|
||||||
|
|
||||||
|
|
||||||
ESP_LOGI(SPP_TAG, "[ 2 ] Create audio pipeline for playback");
|
|
||||||
audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
|
|
||||||
pipeline = audio_pipeline_init(&pipeline_cfg);
|
|
||||||
|
|
||||||
ESP_LOGI(SPP_TAG, "[3.1] Create i2s stream to write data to codec chip");
|
|
||||||
i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
|
|
||||||
i2s_cfg.type = AUDIO_STREAM_WRITER;
|
|
||||||
i2s_stream_writer = i2s_stream_init(&i2s_cfg);
|
|
||||||
|
|
||||||
|
|
||||||
ESP_LOGI(SPP_TAG, "[3.1b] fifostream");
|
|
||||||
fifostream_cfg_t eq_cfg = DEFAULT_FIFOSTREAM_CONFIG();
|
|
||||||
int set_gain[] = {0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
|
|
||||||
0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,};
|
|
||||||
eq_cfg.set_gain = set_gain;
|
|
||||||
fifostream = fifostream_init(&eq_cfg);
|
|
||||||
|
|
||||||
ESP_LOGI(SPP_TAG, "[3.2] Create i2s stream to read data from codec chip");
|
|
||||||
i2s_stream_cfg_t i2s_cfg_read = I2S_STREAM_CFG_DEFAULT();
|
|
||||||
i2s_cfg_read.type = AUDIO_STREAM_READER;
|
|
||||||
i2s_stream_reader = i2s_stream_init(&i2s_cfg_read);
|
|
||||||
|
|
||||||
ESP_LOGI(SPP_TAG, "[3.3] Register all elements to audio pipeline");
|
|
||||||
audio_pipeline_register(pipeline, i2s_stream_reader, "i2s_read");
|
|
||||||
audio_pipeline_register(pipeline, fifostream, "wombat");
|
|
||||||
audio_pipeline_register(pipeline, i2s_stream_writer, "i2s_write");
|
|
||||||
|
|
||||||
ESP_LOGI(SPP_TAG, "[3.4] Link it together [codec_chip]-->i2s_stream_reader-->i2s_stream_writer-->[codec_chip]");
|
|
||||||
const char *link_tag[3] = {"i2s_read", "wombat", "i2s_write"};
|
|
||||||
audio_pipeline_link(pipeline, &link_tag[0], 3);
|
|
||||||
|
|
||||||
ESP_LOGI(SPP_TAG, "[ 4 ] Set up event listener");
|
|
||||||
audio_event_iface_cfg_t evt_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();
|
|
||||||
audio_event_iface_handle_t evt = audio_event_iface_init(&evt_cfg);
|
|
||||||
|
|
||||||
ESP_LOGI(SPP_TAG, "[4.1] Listening event from all elements of pipeline");
|
|
||||||
audio_pipeline_set_listener(pipeline, evt);
|
|
||||||
|
|
||||||
ESP_LOGI(SPP_TAG, "[ 5 ] Start audio_pipeline");
|
|
||||||
audio_pipeline_run(pipeline);
|
|
||||||
|
|
||||||
ESP_LOGI(SPP_TAG, "[ 7 ] Listen for all pipeline events");
|
|
||||||
while (1) {
|
|
||||||
audio_event_iface_msg_t msg;
|
|
||||||
esp_err_t ret = audio_event_iface_listen(evt, &msg, portMAX_DELAY);
|
|
||||||
if (ret != ESP_OK) {
|
|
||||||
ESP_LOGE(SPP_TAG, "[ * ] Event interface error : %d", ret);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop when the last pipeline element (i2s_stream_writer in this case) receives stop event */
|
|
||||||
if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *) i2s_stream_writer
|
|
||||||
&& msg.cmd == AEL_MSG_CMD_REPORT_STATUS
|
|
||||||
&& (((int)msg.data == AEL_STATUS_STATE_STOPPED) || ((int)msg.data == AEL_STATUS_STATE_FINISHED))) {
|
|
||||||
ESP_LOGW(SPP_TAG, "[ * ] Stop event received");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGI(SPP_TAG, "[ 8 ] Stop audio_pipeline");
|
|
||||||
audio_pipeline_stop(pipeline);
|
|
||||||
audio_pipeline_wait_for_stop(pipeline);
|
|
||||||
audio_pipeline_terminate(pipeline);
|
|
||||||
|
|
||||||
audio_pipeline_unregister(pipeline, i2s_stream_reader);
|
|
||||||
audio_pipeline_unregister(pipeline, i2s_stream_writer);
|
|
||||||
|
|
||||||
/* Terminate the pipeline before removing the listener */
|
|
||||||
audio_pipeline_remove_listener(pipeline);
|
|
||||||
|
|
||||||
/* Make sure audio_pipeline_remove_listener & audio_event_iface_remove_listener are called before destroying event_iface */
|
|
||||||
audio_event_iface_destroy(evt);
|
|
||||||
|
|
||||||
/* Release all resources */
|
|
||||||
audio_pipeline_deinit(pipeline);
|
|
||||||
audio_element_deinit(i2s_stream_reader);
|
|
||||||
audio_element_deinit(i2s_stream_writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_main()
|
|
||||||
{
|
|
||||||
esp_err_t ret = nvs_flash_init();
|
|
||||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
|
||||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
|
||||||
ret = nvs_flash_init();
|
|
||||||
}
|
|
||||||
ESP_ERROR_CHECK( ret );
|
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
|
|
||||||
|
|
||||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
|
||||||
if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
|
|
||||||
ESP_LOGE(SPP_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(ret));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
|
|
||||||
ESP_LOGE(SPP_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret = esp_bluedroid_init()) != ESP_OK) {
|
|
||||||
ESP_LOGE(SPP_TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret = esp_bluedroid_enable()) != ESP_OK) {
|
|
||||||
ESP_LOGE(SPP_TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret = esp_bt_gap_register_callback(esp_bt_gap_cb)) != ESP_OK) {
|
|
||||||
ESP_LOGE(SPP_TAG, "%s gap register failed: %s\n", __func__, esp_err_to_name(ret));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret = esp_spp_register_callback(esp_spp_cb)) != ESP_OK) {
|
|
||||||
ESP_LOGE(SPP_TAG, "%s spp register failed: %s\n", __func__, esp_err_to_name(ret));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret = esp_spp_init(esp_spp_mode)) != ESP_OK) {
|
|
||||||
ESP_LOGE(SPP_TAG, "%s spp init failed: %s\n", __func__, esp_err_to_name(ret));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (CONFIG_BT_SSP_ENABLED == true)
|
|
||||||
/* Set default parameters for Secure Simple Pairing */
|
|
||||||
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
|
|
||||||
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
|
|
||||||
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set default parameters for Legacy Pairing
|
|
||||||
* Use variable pin, input pin code when pairing
|
|
||||||
*/
|
|
||||||
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
|
|
||||||
esp_bt_pin_code_t pin_code;
|
|
||||||
esp_bt_gap_set_pin(pin_type, 0, pin_code);
|
|
||||||
|
|
||||||
audio_main();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0 /* this will be more work than I thought */
|
|
||||||
void gettaskinfo(char *where)
|
|
||||||
{
|
|
||||||
TaskStatus_t xTaskDetails;
|
|
||||||
vTaskGetInfo( /* The handle of the task being queried. */
|
|
||||||
0,
|
|
||||||
/* The TaskStatus_t structure to complete with information
|
|
||||||
on xTask. */
|
|
||||||
&xTaskDetails,
|
|
||||||
/* Include the stack high water mark value in the
|
|
||||||
TaskStatus_t structure. */
|
|
||||||
pdTRUE,
|
|
||||||
/* Include the task state in the TaskStatus_t structure. */
|
|
||||||
eInvalid );
|
|
||||||
ESP_LOGE("PROC", "where: proc %s: %d %d", xTaskDetails.pcTaskName,
|
|
||||||
(int)((char *)(&xTaskDetails) - (char *)(pxStackBase)),
|
|
||||||
(int)usStackHighWaterMark);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
Loading…
Reference in a new issue