Moved software into seperate folder

This commit is contained in:
2022-05-26 03:34:25 +02:00
parent 7907e16701
commit 6bcf0e0f39
24 changed files with 1 additions and 1 deletions

4
software/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
tools
build
.cache
sdkconfig.old

8
software/CMakeLists.txt Normal file
View File

@@ -0,0 +1,8 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(main)

1
software/esp-idf Submodule

Submodule software/esp-idf added at 31b7694551

View File

@@ -0,0 +1,3 @@
idf_component_register(SRCS "src/main.cpp" "src/helper.cpp" "src/wav.cpp" "src/storage.cpp" "src/i2s.cpp" "src/bluetooth.cpp" "src/avrcp.cpp" "src/a2dp.cpp"
INCLUDE_DIRS "include"
EMBED_FILES "assets/connect.wav" "assets/disconnect.wav")

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,7 @@
#pragma once
#include <cstdint>
namespace a2dp {
void init();
void connect_to_last();
}

View File

@@ -0,0 +1,5 @@
#pragma once
namespace avrcp {
void init();
}

View File

@@ -0,0 +1,6 @@
#pragma once
namespace bluetooth {
void init();
void set_scan_mode(bool connectable);
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include "esp_bt_device.h"
#include "esp_a2dp_api.h"
const char* addr_to_str(esp_bd_addr_t bda);
const char* connection_state_to_str(esp_a2d_connection_state_t state);

View File

@@ -0,0 +1,12 @@
#pragma once
#include <cstdint>
#define I2S_PORT I2S_NUM_0
namespace i2s {
void init();
uint32_t get_sample_rate();
void set_sample_rate(uint32_t sample_rate);
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "esp_bt_device.h"
namespace nvs {
void init();
void get_last_connection(esp_bd_addr_t last_connection);
void set_last_connection(esp_bd_addr_t last_connection);
bool has_last_connection();
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include <cstdint>
#define WAV_PLAY_HELPER(str) #str
#define WAV_PLAY(NAME) {\
extern const uint8_t _binary_ ## NAME ## _wav_start[]; \
extern const uint8_t _binary_ ## NAME ## _wav_end[]; \
wav::play(_binary_ ## NAME ## _wav_start, _binary_ ## NAME ## _wav_end); \
}
namespace wav {
void play(const uint8_t* start, const uint8_t* end);
}

168
software/main/src/a2dp.cpp Normal file
View File

@@ -0,0 +1,168 @@
#include "esp_log.h"
#include "esp_gap_bt_api.h"
#include "esp_a2dp_api.h"
#include "driver/i2s.h"
#include "a2dp.h"
#include "helper.h"
#include "wav.h"
#include "storage.h"
#include "i2s.h"
#include "bluetooth.h"
#define A2DP_TAG "APP_A2DP"
static void handle_connection_state(uint16_t event, esp_a2d_cb_param_t* a2d) {
ESP_LOGI(A2DP_TAG, "partner address: %s", addr_to_str(a2d->conn_stat.remote_bda));
ESP_LOGI(A2DP_TAG, "A2DP connection state: %s, [%s]", connection_state_to_str(a2d->conn_stat.state), addr_to_str(a2d->conn_stat.remote_bda));
static int retry_count = 0;
static bool was_connected = false;
if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_DISCONNECTED) {
ESP_LOGI(A2DP_TAG, "ESP_A2D_CONNECTION_STATE_DISCONNECTED");
if (a2d->conn_stat.disc_rsn == ESP_A2D_DISC_RSN_ABNORMAL && retry_count < 3) {
ESP_LOGI(A2DP_TAG,"Connection try number: %d", retry_count);
a2dp::connect_to_last();
} else {
bluetooth::set_scan_mode(true);
if (was_connected) {
vTaskDelay(300 / portTICK_PERIOD_MS);
WAV_PLAY(disconnect);
}
}
} else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTED){
ESP_LOGI(A2DP_TAG, "ESP_A2D_CONNECTION_STATE_CONNECTED");
bluetooth::set_scan_mode(false);
retry_count = 0;
was_connected = true;
WAV_PLAY(connect);
// record current connection
nvs::set_last_connection(a2d->conn_stat.remote_bda);
if (esp_bt_gap_read_remote_name(a2d->conn_stat.remote_bda) != ESP_OK) {
ESP_LOGE(A2DP_TAG, "esp_bt_gap_read_remote_name failed");
}
} else if (a2d->conn_stat.state == ESP_A2D_CONNECTION_STATE_CONNECTING){
ESP_LOGI(A2DP_TAG, "ESP_A2D_CONNECTION_STATE_CONNECTING");
retry_count++;
}
}
static void handle_audio_cfg(uint16_t event, esp_a2d_cb_param_t* a2d) {
ESP_LOGI(A2DP_TAG, "a2dp audio_cfg_cb , codec type %d", a2d->audio_cfg.mcc.type);
char oct0 = a2d->audio_cfg.mcc.cie.sbc[0];
if (oct0 & (0x01 << 6)) {
i2s::set_sample_rate(32000);
} else if (oct0 & (0x01 << 5)) {
i2s::set_sample_rate(44100);
} else if (oct0 & (0x01 << 4)) {
i2s::set_sample_rate(48000);
} else {
i2s::set_sample_rate(16000);
}
ESP_LOGI(A2DP_TAG, "a2dp audio_cfg_cb , sample_rate %d", i2s::get_sample_rate());
}
static void a2d_callback(esp_a2d_cb_event_t event, esp_a2d_cb_param_t* a2d) {
switch (event) {
case ESP_A2D_CONNECTION_STATE_EVT:
ESP_LOGD(A2DP_TAG, "%s ESP_A2D_CONNECTION_STATE_EVT", __func__);
handle_connection_state(event, a2d);
break;
case ESP_A2D_AUDIO_STATE_EVT:
ESP_LOGD(A2DP_TAG, "%s ESP_A2D_AUDIO_STATE_EVT", __func__);
break;
case ESP_A2D_AUDIO_CFG_EVT:
ESP_LOGD(A2DP_TAG, "%s ESP_A2D_AUDIO_CFG_EVT", __func__);
handle_audio_cfg(event, a2d);
break;
case ESP_A2D_PROF_STATE_EVT:
if (ESP_A2D_INIT_SUCCESS == a2d->a2d_prof_stat.init_state) {
ESP_LOGI(A2DP_TAG,"A2DP PROF STATE: Init Compl\n");
} else {
ESP_LOGI(A2DP_TAG,"A2DP PROF STATE: Deinit Compl\n");
}
break;
default:
ESP_LOGE(A2DP_TAG, "%s unhandled evt %d", __func__, event);
break;
}
}
/**
* @brief Utility structure that can be used to split a int32_t up into 2 separate channels with int16_t data.
* @author Phil Schatzmann
* @copyright Apache License Version 2
*/
struct __attribute__((packed)) Frame {
int16_t channel1;
int16_t channel2;
Frame(int v=0){
channel1 = channel2 = v;
}
Frame(int ch1, int ch2){
channel1 = ch1;
channel2 = ch2;
}
};
static void audio_data_callback(const uint8_t* data, uint32_t len) {
Frame* frame = (Frame*)data;
for (int i = 0; i < len/4; i++) {
int16_t temp = frame[i].channel1;
frame[i].channel1 = frame[i].channel2;
frame[i].channel2 = temp;
}
size_t bytes_written;
if (i2s_write(I2S_PORT, data, len, &bytes_written, portMAX_DELAY) != ESP_OK) {
ESP_LOGE(A2DP_TAG, "i2s_write has failed");
}
if (bytes_written < len) {
ESP_LOGE(A2DP_TAG, "Timeout: not all bytes were written to I2S");
}
}
void a2dp::init() {
ESP_LOGI(A2DP_TAG, "Initializing A2DP");
// Initialize A2DP sink
if (esp_a2d_register_callback(a2d_callback) != ESP_OK){
ESP_LOGE(A2DP_TAG,"esp_a2d_register_callback failed");
}
if (esp_a2d_sink_register_data_callback(audio_data_callback) != ESP_OK){
ESP_LOGE(A2DP_TAG,"esp_a2d_sink_register_data_callback failed");
}
if (esp_a2d_sink_init() != ESP_OK){
ESP_LOGE(A2DP_TAG,"esp_a2d_sink_init failed");
}
}
void a2dp::connect_to_last() {
if (nvs::has_last_connection()) {
esp_bd_addr_t last_connection = {0,0,0,0,0,0};
nvs::get_last_connection(last_connection);
if (esp_a2d_sink_connect(last_connection) == ESP_FAIL) {
ESP_LOGE(A2DP_TAG, "Failed connecting to device!");
}
} else {
bluetooth::set_scan_mode(true);
}
}

View File

@@ -0,0 +1,56 @@
#include "esp_log.h"
#include "esp_avrc_api.h"
#include "avrcp.h"
#include "helper.h"
#define AVRCP_TAG "APP_AVRCP"
static void rc_tg_callback(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_param_t* param) {
ESP_LOGD(AVRCP_TAG, "%s evt %d", __func__, event);
switch (event) {
case ESP_AVRC_TG_SET_ABSOLUTE_VOLUME_CMD_EVT:
ESP_LOGI(AVRCP_TAG, "AVRC set absolute volume: %d%%", (int)param->set_abs_vol.volume * 100/ 0x7f);
// The phone want to change the volume
break;
case ESP_AVRC_TG_REGISTER_NOTIFICATION_EVT:
ESP_LOGI(AVRCP_TAG, "AVRC register event notification: %d, param: 0x%x", param->reg_ntf.event_id, param->reg_ntf.event_parameter);
if (param->reg_ntf.event_id == ESP_AVRC_RN_VOLUME_CHANGE) {
ESP_LOGI(AVRCP_TAG, "AVRC Volume Changes Supported");
// Notify the phone of the current volume
// @TODO This does not appear to set the volume correctly on my OnePlus 7T Pro
// However for now it is not really relevant as the volume control is doen by the car
// In the future however it might be nice to sync the value on the phone, the esp and the car
// This will require some sort of CAN bus access
esp_avrc_rn_param_t rn_param;
rn_param.volume = 127;
esp_avrc_tg_send_rn_rsp(ESP_AVRC_RN_VOLUME_CHANGE, ESP_AVRC_RN_RSP_INTERIM, &rn_param);
} else {
ESP_LOGW(AVRCP_TAG, "AVRC Volume Changes NOT Supported");
}
break;
default:
ESP_LOGE(AVRCP_TAG, "%s unhandled evt %d", __func__, event);
break;
}
}
void avrcp::init() {
ESP_LOGI(AVRCP_TAG, "Initializing AVRCP");
// Initialize AVRCP target
if (esp_avrc_tg_init() == ESP_OK) {
esp_avrc_tg_register_callback(rc_tg_callback);
esp_avrc_rn_evt_cap_mask_t evt_set = {0};
esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_VOLUME_CHANGE);
if (esp_avrc_tg_set_rn_evt_cap(&evt_set) != ESP_OK) {
ESP_LOGE(AVRCP_TAG, "esp_avrc_tg_set_rn_evt_cap failed");
}
} else {
ESP_LOGE(AVRCP_TAG, "esp_avrc_tg_init failed");
}
}

View File

@@ -0,0 +1,155 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_gap_bt_api.h"
#include "esp_spp_api.h"
#include "bluetooth.h"
#include "helper.h"
#include <cstring>
#define BT_TAG "APP_BT"
static bool start() {
ESP_LOGI(BT_TAG, "BT Start");
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED) {
ESP_LOGI(BT_TAG, "Already enabled");
return true;
}
esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) {
ESP_LOGI(BT_TAG, "Idle");
esp_bt_controller_init(&cfg);
while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) {}
}
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED) {
if (esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) {
ESP_LOGE(BT_TAG, "BT Enable failed");
return false;
}
}
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_ENABLED) {
ESP_LOGI(BT_TAG, "Enabled");
return true;
}
ESP_LOGE(BT_TAG, "BT Start failed");
return false;
}
static void app_gap_callback(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(BT_TAG, "authentication success: %s", param->auth_cmpl.device_name);
} else {
ESP_LOGE(BT_TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
}
break;
}
case ESP_BT_GAP_PIN_REQ_EVT: {
esp_bd_addr_t peer_bd_addr = {0,0,0,0,0,0};
memcpy(peer_bd_addr, param->pin_req.bda, ESP_BD_ADDR_LEN);
ESP_LOGI(BT_TAG, "partner address: %s", addr_to_str(peer_bd_addr));
break;
}
case ESP_BT_GAP_CFM_REQ_EVT: {
esp_bd_addr_t peer_bd_addr = {0,0,0,0,0,0};
memcpy(peer_bd_addr, param->cfm_req.bda, ESP_BD_ADDR_LEN);
ESP_LOGI(BT_TAG, "partner address: %s", addr_to_str(peer_bd_addr));
ESP_LOGI(BT_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please confirm the passkey: %d", param->cfm_req.num_val);
break;
}
case ESP_BT_GAP_KEY_NOTIF_EVT: {
ESP_LOGI(BT_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
break;
}
case ESP_BT_GAP_KEY_REQ_EVT: {
ESP_LOGI(BT_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
break;
}
case ESP_BT_GAP_READ_REMOTE_NAME_EVT: {
ESP_LOGI(BT_TAG, "ESP_BT_GAP_READ_REMOTE_NAME_EVT stat:%d", param->read_rmt_name.stat);
if (param->read_rmt_name.stat == ESP_BT_STATUS_SUCCESS ) {
ESP_LOGI(BT_TAG, "ESP_BT_GAP_READ_REMOTE_NAME_EVT remote name:%s", param->read_rmt_name.rmt_name);
char remote_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
memcpy(remote_name, param->read_rmt_name.rmt_name, ESP_BT_GAP_MAX_BDNAME_LEN );
}
break;
}
default: {
ESP_LOGI(BT_TAG, "%s invalid event: %d", __func__, event);
break;
}
}
return;
}
void bluetooth::init() {
ESP_LOGI(BT_TAG, "Initializing bluetooth");
if (!start()) {
ESP_LOGE(BT_TAG, "Failed to initialize controller");
return;
}
ESP_LOGI(BT_TAG, "Controller initialized");
esp_bluedroid_status_t bt_stack_status = esp_bluedroid_get_status();
if (bt_stack_status == ESP_BLUEDROID_STATUS_UNINITIALIZED) {
if (esp_bluedroid_init() != ESP_OK) {
ESP_LOGE(BT_TAG, "Failed to initialize bluedroid");
return;
}
ESP_LOGI(BT_TAG, "Bluedroid initialized");
}
while (bt_stack_status != ESP_BLUEDROID_STATUS_ENABLED) {
if (esp_bluedroid_enable() != ESP_OK) {
ESP_LOGE(BT_TAG, "Failed to enable bluedroid");
vTaskDelay(100 / portTICK_PERIOD_MS);
} else {
ESP_LOGI(BT_TAG, "Bluedroid enabled");
}
bt_stack_status = esp_bluedroid_get_status();
}
if (esp_bt_gap_register_callback(app_gap_callback) != ESP_OK) {
ESP_LOGE(BT_TAG,"gap register failed");
return;
}
esp_bt_dev_set_device_name("207 Music");
esp_bt_pin_code_t pin_code;
pin_code[0] = '6';
pin_code[1] = '9';
pin_code[2] = '4';
pin_code[3] = '2';
pin_code[4] = '0';
esp_bt_gap_set_pin(ESP_BT_PIN_TYPE_FIXED, 5, pin_code);
}
void bluetooth::set_scan_mode(bool connectable) {
if (esp_bt_gap_set_scan_mode(connectable ? ESP_BT_CONNECTABLE : ESP_BT_NON_CONNECTABLE, connectable ? ESP_BT_GENERAL_DISCOVERABLE : ESP_BT_NON_DISCOVERABLE)) {
ESP_LOGE(BT_TAG,"esp_bt_gap_set_scan_mode failed");
}
}

View File

@@ -0,0 +1,14 @@
#include "esp_log.h"
#include "helper.h"
const char* addr_to_str(esp_bd_addr_t bda) {
static char bda_str[18];
sprintf(bda_str, "%02x:%02x:%02x:%02x:%02x:%02x", bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
return (const char*)bda_str;
}
const char* connection_state_to_str(esp_a2d_connection_state_t state) {
const char* states[4] = {"Disconnected", "Connecting", "Connected", "Disconnecting"};
return states[state];
}

56
software/main/src/i2s.cpp Normal file
View File

@@ -0,0 +1,56 @@
#include "esp_log.h"
#include "driver/i2s.h"
#include "i2s.h"
#define I2S_TAG "APP_I2S"
void i2s::init() {
ESP_LOGI(I2S_TAG, "Initializing i2s");
i2s_port_t i2s_port = I2S_PORT;
i2s_config_t i2s_config = {
.mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = get_sample_rate(),
.bits_per_sample = (i2s_bits_per_sample_t)16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = (i2s_comm_format_t) (I2S_COMM_FORMAT_STAND_I2S),
.intr_alloc_flags = 0, // default interrupt priority
.dma_desc_num = 8,
.dma_frame_num = 64,
.use_apll = false,
.tx_desc_auto_clear = true // avoiding noise in case of data unavailability
};
if (i2s_driver_install(i2s_port, &i2s_config, 0, nullptr) != ESP_OK) {
ESP_LOGE(I2S_TAG, "i2s_driver_install failed");
}
i2s_pin_config_t pin_config = {
.bck_io_num = 26,
.ws_io_num = 25,
.data_out_num = 33,
.data_in_num = I2S_PIN_NO_CHANGE
};
if (i2s_set_pin(i2s_port, &pin_config) != ESP_OK) {
ESP_LOGE(I2S_TAG, "i2s_set_pin failed");
}
}
static uint32_t sample_rate = 44100;
void i2s::set_sample_rate(uint32_t sp) {
sample_rate = sp;
if (i2s_set_clk(I2S_PORT, sample_rate, 16, I2S_CHANNEL_STEREO) != ESP_OK){
ESP_LOGE(I2S_TAG, "i2s_set_clk failed with samplerate=%d", sample_rate);
} else {
ESP_LOGI(I2S_TAG, "samplerate=%d", sample_rate);
}
}
uint32_t i2s::get_sample_rate() {
return sample_rate;
}

View File

@@ -0,0 +1,29 @@
#include "esp_log.h"
#include "esp_system.h"
#include "storage.h"
#include "i2s.h"
#include "bluetooth.h"
#include "avrcp.h"
#include "a2dp.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define APP_TAG "APP"
extern "C" void app_main() {
ESP_LOGI(APP_TAG, "Starting Car Stereo");
ESP_LOGI(APP_TAG, "Available Heap: %u", esp_get_free_heap_size());
nvs::init();
i2s::init();
bluetooth::init();
avrcp::init();
a2dp::init();
a2dp::connect_to_last();
}

View File

@@ -0,0 +1,81 @@
#include <cstring>
#include "esp_log.h"
#include "nvs_flash.h"
#include "storage.h"
#define NVS_TAG "APP_NVS"
void nvs::init() {
ESP_LOGI(NVS_TAG, "Initializing nvs");
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND){
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
}
void nvs::get_last_connection(esp_bd_addr_t last_connection) {
nvs_handle handle;
esp_err_t err = nvs_open("connected_dba", NVS_READWRITE, &handle);
if (err != ESP_OK) {
ESP_LOGE(NVS_TAG, "NVS OPEN ERRRO");
}
esp_bd_addr_t bda;
size_t size = sizeof(bda);
err = nvs_get_blob(handle, "last_bda", bda, &size);
if (err != ESP_OK) {
if (err == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGI(NVS_TAG, "nvs_blob does not exists");
} else {
ESP_LOGE(NVS_TAG, "get_nvs_blob failed");
}
}
nvs_close(handle);
if (err == ESP_OK) {
memcpy(last_connection, bda, size);
}
}
void nvs::set_last_connection(esp_bd_addr_t bda) {
esp_bd_addr_t last_connection = {0,0,0,0,0,0};
get_last_connection(last_connection);
if (memcmp(bda, last_connection, ESP_BD_ADDR_LEN) == 0) {
// Nothing has changed
return;
}
nvs_handle handle;
esp_err_t err = nvs_open("connected_dba", NVS_READWRITE, &handle);
if (err != ESP_OK) {
ESP_LOGE(NVS_TAG, "NVS OPEN ERRRO");
}
err = nvs_set_blob(handle, "last_bda", bda, ESP_BD_ADDR_LEN);
if (err == ESP_OK) {
err = nvs_commit(handle);
} else {
ESP_LOGE(NVS_TAG, "NVS_WRITE_ERROR");
}
if (err != ESP_OK) {
ESP_LOGE(NVS_TAG, "NVS COMMIT ERROR");
}
nvs_close(handle);
}
bool nvs::has_last_connection() {
esp_bd_addr_t empty = {0,0,0,0,0,0};
esp_bd_addr_t last_connection = {0,0,0,0,0,0};
get_last_connection(last_connection);
int result = memcmp(last_connection, empty, ESP_BD_ADDR_LEN);
return result != 0;
}

65
software/main/src/wav.cpp Normal file
View File

@@ -0,0 +1,65 @@
#include "esp_log.h"
#include "driver/i2s.h"
#include "wav.h"
#include "i2s.h"
#define WAV_TAG "APP_WAV"
#define WAV_HEADER_SIZE 44
#define I2S_BUFFER_SIZE 512
struct PlayWavParam {
const uint8_t* data;
uint32_t len;
};
static void task(void* param) {
ESP_LOGI(WAV_TAG, "Playing sample...");
PlayWavParam* p = (PlayWavParam*)param;
// Switch to mono since the samples are all in mono to save space
i2s_zero_dma_buffer(I2S_PORT);
i2s_set_clk(I2S_PORT, 44100, 16, I2S_CHANNEL_MONO);
for (uint32_t index = 0; index < p->len; index += I2S_BUFFER_SIZE) {
int rest = p->len - index;
size_t byte_size = I2S_BUFFER_SIZE;
if (rest < I2S_BUFFER_SIZE) {
byte_size = rest;
}
const unsigned char* current = p->data + WAV_HEADER_SIZE + index;
size_t bytes_written;
if (i2s_write(I2S_PORT, current, byte_size, &bytes_written, portMAX_DELAY) != ESP_OK) {
ESP_LOGE(WAV_TAG, "i2s_write has failed");
}
if (bytes_written < byte_size) {
ESP_LOGE(WAV_TAG, "Timeout: not all bytes were written to I2S");
}
}
// Switch back to stereo with the correct samplerate
i2s_zero_dma_buffer(I2S_PORT);
i2s_set_clk(I2S_PORT, i2s::get_sample_rate(), 16, I2S_CHANNEL_STEREO);
ESP_LOGI(WAV_TAG, "Done");
free(p);
vTaskDelete(nullptr);
}
void wav::play(const uint8_t* start, const uint8_t* end) {
ESP_LOGI(WAV_TAG, "Creating Play Wav Task");
uint32_t len = (end - start - WAV_HEADER_SIZE);
PlayWavParam* param = new PlayWavParam;
param->data = start;
param->len = len;
if (xTaskCreate(task, "PlayWav", 2048, param, configMAX_PRIORITIES - 3, nullptr) != pdPASS) {
ESP_LOGE(WAV_TAG, "Failed to create play wav task");
}
}

1988
software/sdkconfig Normal file

File diff suppressed because it is too large Load Diff

1
software/source.sh Normal file
View File

@@ -0,0 +1 @@
export IDF_TOOLS_PATH=$(dirname $(readlink -f $0))/tools