- completely drop ADF but copy necessary parts

o copy component audio_board from ADF and create custom component from it
  o copy component audio_hal from ADF and create custom component from it
  o copy component audio_sal from ADF and create custom component from it
  o copy component esp_peripherals from ADF and create custom component from it
- add fLaC support through xiph's original repository as a git module
This commit is contained in:
Carlos
2021-09-05 20:20:36 +02:00
Unverified
parent e2fc307451
commit 30d2e54dab
113 changed files with 22735 additions and 1011 deletions

3
.gitmodules vendored
View File

@@ -4,3 +4,6 @@
[submodule "components/esp-dsp"]
path = components/esp-dsp
url = https://github.com/espressif/esp-dsp
[submodule "components/flac/flac"]
path = components/flac/flac
url = https://github.com/xiph/flac.git

View File

@@ -5,10 +5,10 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/codespell-project/codespell
rev: v1.16.0
hooks:
- id: codespell
#- repo: https://github.com/codespell-project/codespell
# rev: v1.16.0
# hooks:
# - id: codespell
- repo: https://github.com/pocc/pre-commit-hooks
rev: v1.1.1

View File

@@ -2,6 +2,6 @@
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{ADF_PATH}/CMakeLists.txt)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(snapclient)

View File

@@ -0,0 +1,76 @@
set(COMPONENT_ADD_INCLUDEDIRS ./include)
# Edit following two lines to set component requirements (see docs)
set(COMPONENT_REQUIRES )
set(COMPONENT_PRIV_REQUIRES audio_sal audio_hal esp_peripherals)
#[[
if (CONFIG_ESP_LYRAT_V4_2_BOARD)
message(STATUS "Current board name is " CONFIG_ESP_LYRAT_V4_2_BOARD)
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./lyrat_v4_2)
set(COMPONENT_SRCS
./lyrat_v4_2/board.c
./lyrat_v4_2/board_pins_config.c
)
endif()
]]
if (CONFIG_ESP_LYRAT_V4_3_BOARD)
message(STATUS "Current board name is " CONFIG_ESP_LYRAT_V4_3_BOARD)
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./lyrat_v4_3)
set(COMPONENT_SRCS
./lyrat_v4_3/board.c
./lyrat_v4_3/board_pins_config.c
)
endif()
#[[
if (CONFIG_ESP_LYRAT_MINI_V1_1_BOARD)
message(STATUS "Current board name is " CONFIG_ESP_LYRAT_MINI_V1_1_BOARD)
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./lyrat_mini_v1_1)
set(COMPONENT_SRCS
./lyrat_mini_v1_1/board.c
./lyrat_mini_v1_1/board_pins_config.c
)
endif()
if (CONFIG_ESP_LYRATD_MSC_V2_1_BOARD)
message(STATUS "Current board name is " CONFIG_ESP_LYRATD_MSC_V2_1_BOARD)
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./lyratd_msc_v2_1)
set(COMPONENT_SRCS
./lyratd_msc_v2_1/board.c
./lyratd_msc_v2_1/board_pins_config.c
)
endif()
if (CONFIG_ESP_LYRATD_MSC_V2_2_BOARD)
message(STATUS "Current board name is " CONFIG_ESP_LYRATD_MSC_V2_2_BOARD)
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./lyratd_msc_v2_2)
set(COMPONENT_SRCS
./lyratd_msc_v2_2/board.c
./lyratd_msc_v2_2/board_pins_config.c
)
endif()
if (CONFIG_ESP32_KORVO_DU1906_BOARD)
message(STATUS "Current board name is " CONFIG_ESP32_KORVO_DU1906_BOARD)
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./esp32_korvo_du1906)
set(COMPONENT_SRCS
./esp32_korvo_du1906/board.c
./esp32_korvo_du1906/board_pins_config.c
./esp32_korvo_du1906/du1906_bar_pattern.c
)
endif()
if (CONFIG_ESP32_S2_KALUGA_1_V1_2_BOARD)
message(STATUS "Current board name is " CONFIG_ESP32_S2_KALUGA_1_V1_2_BOARD)
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./esp32_s2_kaluga_1_v1_2)
set(COMPONENT_SRCS
./esp32_s2_kaluga_1_v1_2/board.c
./esp32_s2_kaluga_1_v1_2/board_pins_config.c
)
endif()
]]
register_component()

View File

@@ -0,0 +1,52 @@
menu "Audio HAL"
choice AUDIO_BOARD
prompt "Audio board"
default ESP_LYRAT_V4_3_BOARD
help
Select an audio board to use with the ESP-ADF
config AUDIO_BOARD_CUSTOM
bool "Custom audio board"
config ESP_LYRAT_V4_3_BOARD
bool "ESP32-Lyrat V4.3"
config ESP_LYRAT_V4_2_BOARD
bool "ESP32-Lyrat V4.2"
config ESP_LYRATD_MSC_V2_1_BOARD
bool "ESP32-LyraTD-MSC V2.1"
config ESP_LYRATD_MSC_V2_2_BOARD
bool "ESP32-LyraTD-MSC V2.2"
config ESP_LYRAT_MINI_V1_1_BOARD
bool "ESP32-Lyrat-Mini V1.1"
config ESP32_KORVO_DU1906_BOARD
bool "ESP32_KORVO_DU1906"
config ESP32_S2_KALUGA_1_V1_2_BOARD
bool "ESP32-S2-Kaluga-1 v1.2"
endchoice
choice ESP32_KORVO_DU1906_DAC
prompt "ESP32 KORVO DU1906 Board DAC chip"
depends on ESP32_KORVO_DU1906_BOARD
default ESP32_KORVO_DU1906_DAC_TAS5805M
help
Select DAC chip to use on ESP32_KORVO_DU1906 board
config ESP32_KORVO_DU1906_DAC_TAS5805M
bool "ESP32_KORVO_DU1906_DAC_TAS5805M"
config ESP32_KORVO_DU1906_DAC_ES7148
bool "ESP32_KORVO_DU1906_DAC_ES7148"
endchoice
choice ESP32_KORVO_DU1906_ADC
prompt "ESP32 KORVO DU1906 Board ADC chip"
depends on ESP32_KORVO_DU1906_BOARD
default ESP32_KORVO_DU1906_ADC_ES7243
help
Select ADC chip to use on ESP32_KORVO_DU1906 board
config ESP32_KORVO_DU1906_ADC_ES7243
bool "ESP32_KORVO_DU1906_ADC_ES7243"
endchoice
endmenu

View File

@@ -0,0 +1,43 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
COMPONENT_ADD_INCLUDEDIRS := ./include
ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
COMPONENT_ADD_INCLUDEDIRS += ./lyrat_v4_3
COMPONENT_SRCDIRS += ./lyrat_v4_3
endif
ifdef CONFIG_ESP_LYRAT_V4_2_BOARD
COMPONENT_ADD_INCLUDEDIRS += ./lyrat_v4_2
COMPONENT_SRCDIRS += ./lyrat_v4_2
endif
ifdef CONFIG_ESP_LYRATD_MSC_V2_1_BOARD
COMPONENT_ADD_INCLUDEDIRS += ./lyratd_msc_v2_1
COMPONENT_SRCDIRS += ./lyratd_msc_v2_1
COMPONENT_ADD_LDFLAGS += -L$(COMPONENT_PATH)/../audio_hal/driver/zl38063/firmware -lfirmware
endif
ifdef CONFIG_ESP_LYRATD_MSC_V2_2_BOARD
COMPONENT_ADD_INCLUDEDIRS += ./lyratd_msc_v2_2
COMPONENT_SRCDIRS += ./lyratd_msc_v2_2
COMPONENT_ADD_LDFLAGS += -L$(COMPONENT_PATH)/../audio_hal/driver/zl38063/firmware -lfirmware
endif
ifdef CONFIG_ESP_LYRAT_MINI_V1_1_BOARD
COMPONENT_ADD_INCLUDEDIRS += ./lyrat_mini_v1_1
COMPONENT_SRCDIRS += ./lyrat_mini_v1_1
endif
ifdef CONFIG_ESP32_KORVO_DU1906_BOARD
COMPONENT_ADD_INCLUDEDIRS += ./esp32_korvo_du1906
COMPONENT_SRCDIRS += ./esp32_korvo_du1906
endif
ifdef CONFIG_ESP32_S2_KALUGA_1_V1_2_BOARD
COMPONENT_ADD_INCLUDEDIRS += ./esp32_s2_kaluga_1_v1_2
COMPONENT_SRCDIRS += ./esp32_s2_kaluga_1_v1_2
endif

View File

@@ -0,0 +1,237 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _BOARD_PINS_CONFIG_H_
#define _BOARD_PINS_CONFIG_H_
#include "driver/i2c.h"
#include "driver/i2s.h"
#include "driver/spi_common.h"
#include "driver/spi_master.h"
#include "driver/spi_slave.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Get i2c pins configuration
*
* @param port i2c port number to get configuration
* @param i2c_config i2c configuration parameters
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t get_i2c_pins (i2c_port_t port, i2c_config_t *i2c_config);
/**
* @brief Get i2s pins configuration
*
* @param port i2s port number to get configuration
* @param i2s_config i2s configuration parameters
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t get_i2s_pins (i2s_port_t port, i2s_pin_config_t *i2s_config);
/**
* @brief Get spi pins configuration
*
* @param spi_config spi bus configuration parameters
* @param spi_device_interface_config spi device configuration
* parameters
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t
get_spi_pins (spi_bus_config_t *spi_config,
spi_device_interface_config_t *spi_device_interface_config);
/**
* @brief Set i2s mclk output pin
*
* @note GPIO1 and GPIO3 default are UART pins.
*
* @param i2s_num i2s port index
* @param gpio_num gpio number index, only support GPIO0, GPIO1 and
GPIO3.
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_INVALID_STATE Driver state error
* - ESP_ERR_ADF_NOT_SUPPORT Not support
*/
esp_err_t i2s_mclk_gpio_select (i2s_port_t i2s_num, gpio_num_t gpio_num);
/**
* @brief Get the gpio number for sdcard interrupt
*
* @return -1 non-existent
* Others sdcard interrupt gpio number
*/
int8_t get_sdcard_intr_gpio (void);
/**
* @brief Get sdcard maximum number of open files
*
* @return -1 error
* Others max num
*/
int8_t get_sdcard_open_file_num_max (void);
/**
* @brief Get the gpio number for auxin detection
*
* @return -1 non-existent
* Others gpio number
*/
int8_t get_auxin_detect_gpio (void);
/**
* @brief Get the gpio number for headphone detection
*
* @return -1 non-existent
* Others gpio number
*/
int8_t get_headphone_detect_gpio (void);
/**
* @brief Get the gpio number for PA enable
*
* @return -1 non-existent
* Others gpio number
*/
int8_t get_pa_enable_gpio (void);
/**
* @brief Get the gpio number for adc detection
*
* @return -1 non-existent
* Others gpio number
*/
int8_t get_adc_detect_gpio (void);
/**
* @brief Get the mclk gpio number of es7243
*
* @return -1 non-existent
* Others gpio number
*/
int8_t get_es7243_mclk_gpio (void);
/**
* @brief Get the record-button id for adc-button
*
* @return -1 non-existent
* Others button id
*/
int8_t get_input_rec_id (void);
/**
* @brief Get the number for mode-button
*
* @return -1 non-existent
* Others number
*/
int8_t get_input_mode_id (void);
/**
* @brief Get number for set function
*
* @return -1 non-existent
* Others number
*/
int8_t get_input_set_id (void);
/**
* @brief Get number for play function
*
* @return -1 non-existent
* Others number
*/
int8_t get_input_play_id (void);
/**
* @brief number for volume up function
*
* @return -1 non-existent
* Others number
*/
int8_t get_input_volup_id (void);
/**
* @brief Get number for volume down function
*
* @return -1 non-existent
* Others number
*/
int8_t get_input_voldown_id (void);
/**
* @brief Get green led gpio number
*
* @return -1 non-existent
* Others gpio number
*/
int8_t get_reset_codec_gpio (void);
/**
* @brief Get DSP reset gpio number
*
* @return -1 non-existent
* Others gpio number
*/
int8_t get_reset_board_gpio (void);
/**
* @brief Get DSP reset gpio number
*
* @return -1 non-existent
* Others gpio number
*/
int8_t get_green_led_gpio (void);
/**
* @brief Get green led gpio number
*
* @return -1 non-existent
* Others gpio number
*/
int8_t get_blue_led_gpio (void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,155 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "board.h"
#include "audio_mem.h"
#include "esp_log.h"
//#include "periph_sdcard.h"
//#include "led_indicator.h"
//#include "periph_touch.h"
//#include "periph_button.h"
static const char *TAG = "AUDIO_BOARD";
static audio_board_handle_t board_handle = 0;
audio_board_handle_t
audio_board_init (void)
{
if (board_handle)
{
ESP_LOGW (TAG, "The board has already been initialized!");
return board_handle;
}
board_handle = (audio_board_handle_t)audio_calloc (
1, sizeof (struct audio_board_handle));
AUDIO_MEM_CHECK (TAG, board_handle, return NULL);
board_handle->audio_hal = audio_board_codec_init ();
return board_handle;
}
audio_hal_handle_t
audio_board_codec_init (void)
{
audio_hal_codec_config_t audio_codec_cfg = AUDIO_CODEC_DEFAULT_CONFIG ();
audio_hal_handle_t codec_hal
= audio_hal_init (&audio_codec_cfg, &AUDIO_CODEC_ES8388_DEFAULT_HANDLE);
AUDIO_NULL_CHECK (TAG, codec_hal, return NULL);
return codec_hal;
}
/*
display_service_handle_t audio_board_led_init(void)
{
led_indicator_handle_t led =
led_indicator_init((gpio_num_t)get_green_led_gpio()); display_service_config_t
display = { .based_cfg = { .task_stack = 0, .task_prio = 0, .task_core = 0,
.task_func = NULL,
.service_start = NULL,
.service_stop = NULL,
.service_destroy = NULL,
.service_ioctl = led_indicator_pattern,
.service_name = "DISPLAY_serv",
.user_data = NULL,
},
.instance = led,
};
return display_service_create(&display);
}
esp_err_t audio_board_key_init(esp_periph_set_handle_t set)
{
periph_button_cfg_t btn_cfg = {
.gpio_mask = (1ULL << get_input_rec_id()) | (1ULL <<
get_input_mode_id()), //REC BTN & MODE BTN
};
esp_periph_handle_t button_handle = periph_button_init(&btn_cfg);
AUDIO_NULL_CHECK(TAG, button_handle, return ESP_ERR_ADF_MEMORY_LACK);
esp_err_t ret = ESP_OK;
ret = esp_periph_start(set, button_handle);
if (ret != ESP_OK) {
return ret;
}
periph_touch_cfg_t touch_cfg = {
.touch_mask = TOUCH_PAD_SEL4 | TOUCH_PAD_SEL7 | TOUCH_PAD_SEL8 |
TOUCH_PAD_SEL9, .tap_threshold_percent = 70,
};
esp_periph_handle_t touch_periph = periph_touch_init(&touch_cfg);
AUDIO_NULL_CHECK(TAG, touch_periph, return ESP_ERR_ADF_MEMORY_LACK);
ret = esp_periph_start(set, touch_periph);
return ret;
}
esp_err_t audio_board_sdcard_init(esp_periph_set_handle_t set,
periph_sdcard_mode_t mode)
{
if (mode >= SD_MODE_MAX) {
ESP_LOGE(TAG, "PLease select the correct sd mode!, current mode is %d",
mode); return ESP_FAIL;
}
periph_sdcard_cfg_t sdcard_cfg = {
.root = "/sdcard",
.card_detect_pin = get_sdcard_intr_gpio(), // GPIO_NUM_34
.mode = mode,
};
esp_periph_handle_t sdcard_handle = periph_sdcard_init(&sdcard_cfg);
esp_err_t ret = esp_periph_start(set, sdcard_handle);
int retry_time = 5;
bool mount_flag = false;
while (retry_time --) {
if (periph_sdcard_is_mounted(sdcard_handle)) {
mount_flag = true;
break;
} else {
vTaskDelay(500 / portTICK_PERIOD_MS);
}
}
if (mount_flag == false) {
ESP_LOGE(TAG, "Sdcard mount failed");
return ESP_FAIL;
}
return ret;
}
*/
audio_board_handle_t
audio_board_get_handle (void)
{
return board_handle;
}
esp_err_t
audio_board_deinit (audio_board_handle_t audio_board)
{
esp_err_t ret = ESP_OK;
ret = audio_hal_deinit (audio_board->audio_hal);
audio_free (audio_board);
board_handle = NULL;
return ret;
}

View File

@@ -0,0 +1,117 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _AUDIO_BOARD_H_
#define _AUDIO_BOARD_H_
#include "audio_hal.h"
#include "board_def.h"
#include "board_pins_config.h"
//#include "esp_peripherals.h"
//#include "display_service.h"
//#include "periph_sdcard.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Audio board handle
*/
struct audio_board_handle
{
audio_hal_handle_t audio_hal; /*!< audio hardware abstract layer handle */
};
typedef struct audio_board_handle *audio_board_handle_t;
/**
* @brief Initialize audio board
*
* @return The audio board handle
*/
audio_board_handle_t audio_board_init (void);
/**
* @brief Initialize codec chip
*
* @return The audio hal handle
*/
audio_hal_handle_t audio_board_codec_init (void);
///**
// * @brief Initialize led peripheral and display service
// *
// * @return The audio display service handle
// */
// display_service_handle_t audio_board_led_init(void);
//
///**
// * @brief Initialize key peripheral
// *
// * @param set The handle of esp_periph_set_handle_t
// *
// * @return
// * - ESP_OK, success
// * - Others, fail
// */
// esp_err_t audio_board_key_init(esp_periph_set_handle_t set);
//
///**
// * @brief Initialize sdcard peripheral
// *
// * @param set The handle of esp_periph_set_handle_t
// *
// * @return
// * - ESP_OK, success
// * - Others, fail
// */
// esp_err_t audio_board_sdcard_init(esp_periph_set_handle_t set,
// periph_sdcard_mode_t mode);
/**
* @brief Query audio_board_handle
*
* @return The audio board handle
*/
audio_board_handle_t audio_board_get_handle (void);
/**
* @brief Uninitialize the audio board
*
* @param audio_board The handle of audio board
*
* @return 0 success,
* others fail
*/
esp_err_t audio_board_deinit (audio_board_handle_t audio_board);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,98 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _AUDIO_BOARD_DEFINITION_H_
#define _AUDIO_BOARD_DEFINITION_H_
#include "driver/touch_pad.h"
#define SDCARD_OPEN_FILE_NUM_MAX 5
#define SDCARD_INTR_GPIO GPIO_NUM_34
#define BUTTON_REC_ID GPIO_NUM_36
#define BUTTON_MODE_ID GPIO_NUM_39
#define BUTTON_SET_ID TOUCH_PAD_NUM9
#define BUTTON_PLAY_ID TOUCH_PAD_NUM8
#define BUTTON_VOLUP_ID TOUCH_PAD_NUM7
#define BUTTON_VOLDOWN_ID TOUCH_PAD_NUM4
#define AUXIN_DETECT_GPIO GPIO_NUM_12
#define HEADPHONE_DETECT GPIO_NUM_19
#define PA_ENABLE_GPIO GPIO_NUM_21
#define GREEN_LED_GPIO GPIO_NUM_22
extern audio_hal_func_t AUDIO_CODEC_ES8388_DEFAULT_HANDLE;
#define AUDIO_CODEC_DEFAULT_CONFIG() \
{ \
.adc_input = AUDIO_HAL_ADC_INPUT_LINE1, \
.dac_output = AUDIO_HAL_DAC_OUTPUT_ALL, \
.codec_mode = AUDIO_HAL_CODEC_MODE_BOTH, \
.i2s_iface = { \
.mode = AUDIO_HAL_MODE_SLAVE, \
.fmt = AUDIO_HAL_I2S_NORMAL, \
.samples = AUDIO_HAL_48K_SAMPLES, \
.bits = AUDIO_HAL_BIT_LENGTH_16BITS, \
}, \
};
#define INPUT_KEY_NUM 6
#define INPUT_KEY_DEFAULT_INFO() \
{ \
{ \
.type = PERIPH_ID_BUTTON, \
.user_id = INPUT_KEY_USER_ID_REC, \
.act_id = BUTTON_REC_ID, \
}, \
{ \
.type = PERIPH_ID_BUTTON, \
.user_id = INPUT_KEY_USER_ID_MODE, \
.act_id = BUTTON_MODE_ID, \
}, \
{ \
.type = PERIPH_ID_TOUCH, \
.user_id = INPUT_KEY_USER_ID_SET, \
.act_id = BUTTON_SET_ID, \
}, \
{ \
.type = PERIPH_ID_TOUCH, \
.user_id = INPUT_KEY_USER_ID_PLAY, \
.act_id = BUTTON_PLAY_ID, \
}, \
{ \
.type = PERIPH_ID_TOUCH, \
.user_id = INPUT_KEY_USER_ID_VOLUP, \
.act_id = BUTTON_VOLUP_ID, \
}, \
{ \
.type = PERIPH_ID_TOUCH, .user_id = INPUT_KEY_USER_ID_VOLDOWN, \
.act_id = BUTTON_VOLDOWN_ID, \
} \
}
#endif

View File

@@ -0,0 +1,228 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "audio_error.h"
#include "audio_mem.h"
#include "board.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include <string.h>
static const char *TAG = "LYRAT_V4_3";
esp_err_t
get_i2c_pins (i2c_port_t port, i2c_config_t *i2c_config)
{
AUDIO_NULL_CHECK (TAG, i2c_config, return ESP_FAIL);
if (port == I2C_NUM_0 || port == I2C_NUM_1)
{
i2c_config->sda_io_num = GPIO_NUM_18;
i2c_config->scl_io_num = GPIO_NUM_23;
}
else
{
i2c_config->sda_io_num = -1;
i2c_config->scl_io_num = -1;
ESP_LOGE (TAG, "i2c port %d is not supported", port);
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t
get_i2s_pins (i2s_port_t port, i2s_pin_config_t *i2s_config)
{
AUDIO_NULL_CHECK (TAG, i2s_config, return ESP_FAIL);
if (port == I2S_NUM_0 || port == I2S_NUM_1)
{
i2s_config->bck_io_num = GPIO_NUM_5;
i2s_config->ws_io_num = GPIO_NUM_25;
i2s_config->data_out_num = GPIO_NUM_26;
i2s_config->data_in_num = GPIO_NUM_35;
}
else
{
memset (i2s_config, -1, sizeof (i2s_pin_config_t));
ESP_LOGE (TAG, "i2s port %d is not supported", port);
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t
get_spi_pins (spi_bus_config_t *spi_config,
spi_device_interface_config_t *spi_device_interface_config)
{
AUDIO_NULL_CHECK (TAG, spi_config, return ESP_FAIL);
AUDIO_NULL_CHECK (TAG, spi_device_interface_config, return ESP_FAIL);
spi_config->mosi_io_num = -1;
spi_config->miso_io_num = -1;
spi_config->sclk_io_num = -1;
spi_config->quadwp_io_num = -1;
spi_config->quadhd_io_num = -1;
spi_device_interface_config->spics_io_num = -1;
ESP_LOGW (TAG, "SPI interface is not supported");
return ESP_OK;
}
esp_err_t
i2s_mclk_gpio_select (i2s_port_t i2s_num, gpio_num_t gpio_num)
{
if (i2s_num >= I2S_NUM_MAX)
{
ESP_LOGE (TAG, "Does not support i2s number(%d)", i2s_num);
return ESP_ERR_INVALID_ARG;
}
if (gpio_num != GPIO_NUM_0 && gpio_num != GPIO_NUM_1
&& gpio_num != GPIO_NUM_3)
{
ESP_LOGE (TAG, "Only support GPIO0/GPIO1/GPIO3, gpio_num:%d", gpio_num);
return ESP_ERR_INVALID_ARG;
}
ESP_LOGI (TAG, "I2S%d, MCLK output by GPIO%d", i2s_num, gpio_num);
if (i2s_num == I2S_NUM_0)
{
if (gpio_num == GPIO_NUM_0)
{
PIN_FUNC_SELECT (PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
WRITE_PERI_REG (PIN_CTRL, 0xFFF0);
}
else if (gpio_num == GPIO_NUM_1)
{
PIN_FUNC_SELECT (PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_CLK_OUT3);
WRITE_PERI_REG (PIN_CTRL, 0xF0F0);
}
else
{
PIN_FUNC_SELECT (PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_CLK_OUT2);
WRITE_PERI_REG (PIN_CTRL, 0xFF00);
}
}
else if (i2s_num == I2S_NUM_1)
{
if (gpio_num == GPIO_NUM_0)
{
PIN_FUNC_SELECT (PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
WRITE_PERI_REG (PIN_CTRL, 0xFFFF);
}
else if (gpio_num == GPIO_NUM_1)
{
PIN_FUNC_SELECT (PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_CLK_OUT3);
WRITE_PERI_REG (PIN_CTRL, 0xF0FF);
}
else
{
PIN_FUNC_SELECT (PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_CLK_OUT2);
WRITE_PERI_REG (PIN_CTRL, 0xFF0F);
}
}
return ESP_OK;
}
// sdcard
int8_t
get_sdcard_intr_gpio (void)
{
return SDCARD_INTR_GPIO;
}
int8_t
get_sdcard_open_file_num_max (void)
{
return SDCARD_OPEN_FILE_NUM_MAX;
}
// input-output pins
int8_t
get_auxin_detect_gpio (void)
{
return AUXIN_DETECT_GPIO;
}
int8_t
get_headphone_detect_gpio (void)
{
return HEADPHONE_DETECT;
}
int8_t
get_pa_enable_gpio (void)
{
return PA_ENABLE_GPIO;
}
// button pins
int8_t
get_input_rec_id (void)
{
return BUTTON_REC_ID;
}
int8_t
get_input_mode_id (void)
{
return BUTTON_MODE_ID;
}
// touch pins
int8_t
get_input_set_id (void)
{
return BUTTON_SET_ID;
}
int8_t
get_input_play_id (void)
{
return BUTTON_PLAY_ID;
}
int8_t
get_input_volup_id (void)
{
return BUTTON_VOLUP_ID;
}
int8_t
get_input_voldown_id (void)
{
return BUTTON_VOLDOWN_ID;
}
// led pins
int8_t
get_green_led_gpio (void)
{
return GREEN_LED_GPIO;
}

View File

@@ -0,0 +1,42 @@
set(COMPONENT_ADD_INCLUDEDIRS ./include
./driver/es8388
./driver/es8374
./driver/es8311
./driver/es7243
./driver/es7148
./driver/es7210
./driver/tas5805m
#./driver/zl38063
#./driver/zl38063/api_lib
#./driver/zl38063/example_apps
#./driver/zl38063/firmware
./driver/include
)
# Edit following two lines to set component requirements (see docs)
set(COMPONENT_REQUIRES )
set(COMPONENT_PRIV_REQUIRES audio_sal audio_board mbedtls esp_peripherals)
set(COMPONENT_SRCS ./audio_hal.c
./driver/es8388/es8388.c
./driver/es8388/headphone_detect.c
./driver/es8374/es8374.c
./driver/es8311/es8311.c
./driver/es7243/es7243.c
./driver/es7148/es7148.c
./driver/es7210/es7210.c
./driver/tas5805m/tas5805m.c
#./driver/zl38063/zl38063.c
#./driver/zl38063/api_lib/vprocTwolf_access.c
#./driver/zl38063/api_lib/vproc_common.c
#./driver/zl38063/example_apps/tw_hal_verify.c
#./driver/zl38063/example_apps/tw_ldcfg.c
#./driver/zl38063/example_apps/tw_ldfw.c
#./driver/zl38063/example_apps/tw_ldfwcfg.c
#./driver/zl38063/example_apps/tw_spi_access.c
)
register_component()
#target_link_libraries(${COMPONENT_TARGET} INTERFACE "-L${CMAKE_CURRENT_LIST_DIR}/driver/zl38063/firmware")
#target_link_libraries(${COMPONENT_TARGET} INTERFACE firmware)

View File

@@ -0,0 +1,157 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "audio_hal.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include <string.h>
#include "audio_mem.h"
#include "audio_mutex.h"
static const char *TAG = "AUDIO_HAL";
#define AUDIO_HAL_CHECK_NULL(a, format, b, ...) \
if ((a) == 0) \
{ \
ESP_LOGE (TAG, format, ##__VA_ARGS__); \
return b; \
}
audio_hal_handle_t
audio_hal_init (audio_hal_codec_config_t *audio_hal_conf,
audio_hal_func_t *audio_hal_func)
{
esp_err_t ret = 0;
audio_hal_handle_t audio_hal
= (audio_hal_handle_t)audio_calloc (1, sizeof (audio_hal_func_t));
AUDIO_MEM_CHECK (TAG, audio_hal, return NULL);
memcpy (audio_hal, audio_hal_func, sizeof (audio_hal_func_t));
audio_hal->audio_hal_lock = mutex_create ();
AUDIO_MEM_CHECK (TAG, audio_hal->audio_hal_lock, {
audio_free (audio_hal);
return NULL;
});
mutex_lock (audio_hal->audio_hal_lock);
ret = audio_hal->audio_codec_initialize (audio_hal_conf);
if (ret == ESP_FAIL)
{
audio_free (audio_hal);
if (audio_hal_func->handle)
{
return audio_hal_func->handle;
}
else
{
ESP_LOGE (TAG, "codec init failed!");
return NULL;
}
}
ret |= audio_hal->audio_codec_config_iface (audio_hal_conf->codec_mode,
&audio_hal_conf->i2s_iface);
ret |= audio_hal->audio_codec_set_volume (AUDIO_HAL_VOL_DEFAULT);
audio_hal->handle = audio_hal;
audio_hal_func->handle = audio_hal;
mutex_unlock (audio_hal->audio_hal_lock);
return audio_hal;
}
esp_err_t
audio_hal_deinit (audio_hal_handle_t audio_hal)
{
esp_err_t ret;
AUDIO_HAL_CHECK_NULL (audio_hal, "audio_hal handle is null", -1);
mutex_destroy (audio_hal->audio_hal_lock);
ret = audio_hal->audio_codec_deinitialize ();
audio_hal->audio_hal_lock = NULL;
audio_hal->handle = NULL;
audio_free (audio_hal);
audio_hal = NULL;
return ret;
}
esp_err_t
audio_hal_ctrl_codec (audio_hal_handle_t audio_hal,
audio_hal_codec_mode_t mode,
audio_hal_ctrl_t audio_hal_state)
{
esp_err_t ret;
AUDIO_HAL_CHECK_NULL (audio_hal, "audio_hal handle is null", -1);
mutex_lock (audio_hal->audio_hal_lock);
ESP_LOGI (TAG, "Codec mode is %d, Ctrl:%d", mode, audio_hal_state);
ret = audio_hal->audio_codec_ctrl (mode, audio_hal_state);
mutex_unlock (audio_hal->audio_hal_lock);
return ret;
}
esp_err_t
audio_hal_codec_iface_config (audio_hal_handle_t audio_hal,
audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface)
{
esp_err_t ret = 0;
AUDIO_HAL_CHECK_NULL (audio_hal, "audio_hal handle is null", -1);
AUDIO_HAL_CHECK_NULL (iface, "Get volume para is null", -1);
mutex_lock (audio_hal->audio_hal_lock);
ret = audio_hal->audio_codec_config_iface (mode, iface);
mutex_unlock (audio_hal->audio_hal_lock);
return ret;
}
esp_err_t
audio_hal_set_mute (audio_hal_handle_t audio_hal, bool mute)
{
esp_err_t ret;
AUDIO_HAL_CHECK_NULL (audio_hal, "audio_hal handle is null", -1);
mutex_lock (audio_hal->audio_hal_lock);
ret = audio_hal->audio_codec_set_mute (mute);
mutex_unlock (audio_hal->audio_hal_lock);
return ret;
}
esp_err_t
audio_hal_set_volume (audio_hal_handle_t audio_hal, int volume)
{
esp_err_t ret;
AUDIO_HAL_CHECK_NULL (audio_hal, "audio_hal handle is null", -1);
mutex_lock (audio_hal->audio_hal_lock);
ret = audio_hal->audio_codec_set_volume (volume);
mutex_unlock (audio_hal->audio_hal_lock);
return ret;
}
esp_err_t
audio_hal_get_volume (audio_hal_handle_t audio_hal, int *volume)
{
esp_err_t ret;
AUDIO_HAL_CHECK_NULL (audio_hal, "audio_hal handle is null", -1);
AUDIO_HAL_CHECK_NULL (volume, "Get volume para is null", -1);
mutex_lock (audio_hal->audio_hal_lock);
ret = audio_hal->audio_codec_get_volume (volume);
mutex_unlock (audio_hal->audio_hal_lock);
return ret;
}

View File

@@ -0,0 +1,24 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
COMPONENT_ADD_INCLUDEDIRS := ./include ./driver/include
COMPONENT_SRCDIRS := .
COMPONENT_PRIV_INCLUDEDIRS := ./driver/include
COMPONENT_ADD_INCLUDEDIRS += ./driver/es8388 ./driver/es8374
COMPONENT_SRCDIRS += ./driver/es8388 ./driver/es8374
COMPONENT_ADD_INCLUDEDIRS += ./driver/es8311 ./driver/es7243
COMPONENT_SRCDIRS += ./driver/es8311 ./driver/es7243
COMPONENT_ADD_INCLUDEDIRS += ./driver/zl38063 ./driver/zl38063/api_lib ./driver/zl38063/example_apps ./driver/zl38063/firmware
COMPONENT_SRCDIRS += ./driver/zl38063 ./driver/zl38063/api_lib ./driver/zl38063/example_apps ./driver/zl38063/firmware
COMPONENT_ADD_LDFLAGS += -L$(COMPONENT_PATH)/driver/zl38063/firmware -lfirmware
COMPONENT_ADD_INCLUDEDIRS += ./driver/tas5805m ./driver/es7148
COMPONENT_SRCDIRS += ./driver/tas5805m ./driver/es7148
COMPONENT_ADD_INCLUDEDIRS += ./driver/es7210
COMPONENT_SRCDIRS += ./driver/es7210

View File

@@ -0,0 +1,105 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "es7148.h"
#include "board.h"
#include "driver/gpio.h"
#include "esp_log.h"
static const char *TAG = "es7148";
static bool codec_init_flag = 0;
audio_hal_func_t AUDIO_CODEC_ES7148_DEFAULT_HANDLE = {
.audio_codec_initialize = es7148_codec_init,
.audio_codec_deinitialize = es7148_codec_deinit,
.audio_codec_ctrl = es7148_codec_ctrl_state,
.audio_codec_config_iface = es7148_codec_config_i2s,
.audio_codec_set_mute = es7148_codec_set_voice_mute,
.audio_codec_set_volume = es7148_codec_set_voice_volume,
.audio_codec_get_volume = es7148_codec_get_voice_volume,
.audio_hal_lock = NULL,
.handle = NULL,
};
static bool
es7148_codec_initialized ()
{
return codec_init_flag;
}
esp_err_t
es7148_codec_init (audio_hal_codec_config_t *cfg)
{
if (es7148_codec_initialized ())
{
ESP_LOGW (TAG, "The es7148 codec has been already initialized");
return ESP_OK;
}
codec_init_flag = true;
return ESP_OK;
}
esp_err_t
es7148_codec_deinit (void)
{
codec_init_flag = false;
return ESP_OK;
}
esp_err_t
es7148_codec_ctrl_state (audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state)
{
return ESP_OK;
}
esp_err_t
es7148_codec_config_i2s (audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface)
{
return ESP_OK;
}
esp_err_t
es7148_codec_set_voice_mute (bool mute)
{
return ESP_OK;
}
esp_err_t
es7148_codec_set_voice_volume (int volume)
{
int ret = 0;
return ret;
}
esp_err_t
es7148_codec_get_voice_volume (int *volume)
{
int ret = 0;
return ret;
}

View File

@@ -0,0 +1,124 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef __ES7148_H__
#define __ES7148_H__
#include "audio_hal.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Initialize es7148 chip
*
* @param cfg configuration of es7148
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7148_codec_init (audio_hal_codec_config_t *cfg);
/**
* @brief Deinitialize es7148 chip
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7148_codec_deinit (void);
/**
* The functions es7148_ctrl_state and es7148_config_i2s are not used by this
* driver. They are kept here to maintain the uniformity and convenience of
* the interface of the ADF project. These settings for es7148 are burned in
* firmware and configuration files. Default i2s configuration: 48000Hz,
* 16bit, Left-Right channels. Use resampling to be compatible with different
* file types.
*
* @brief Control es7148 chip
*
* @param mode codec mode
* @param ctrl_state start or stop decode or encode progress
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es7148_codec_ctrl_state (audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state);
/**
* @brief Configure es7148 codec mode and I2S interface
*
* @param mode codec mode
* @param iface I2S config
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es7148_codec_config_i2s (audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface);
/**
* @brief mute or unmute the codec
*
* @param mute: true, false
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7148_codec_set_voice_mute (bool mute);
/**
* @brief Set voice volume
*
* @param volume: voice volume (0~100)
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7148_codec_set_voice_volume (int volume);
/**
* @brief Get voice volume
*
* @param[out] *volume: voice volume (0~100)
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7148_codec_get_voice_volume (int *volume);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,614 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2021 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "es7210.h"
#include "board.h"
#include "esp_log.h"
#include "i2c_bus.h"
#include <string.h>
#define I2S_DSP_MODE 0
#define MCLK_DIV_FRE 256
/* ES7210 address*/
#define ES7210_ADDR ES7210_AD1_AD0_00
#define ES7210_MCLK_SOURCE \
FROM_CLOCK_DOUBLE_PIN /* In master mode, 0 : MCLK from pad 1 : MCLK from \
clock doubler */
#define FROM_PAD_PIN 0
#define FROM_CLOCK_DOUBLE_PIN 1
/*
* Operate function of ADC
*/
audio_hal_func_t AUDIO_CODEC_ES7210_DEFAULT_HANDLE = {
.audio_codec_initialize = es7210_adc_init,
.audio_codec_deinitialize = es7210_adc_deinit,
.audio_codec_ctrl = es7210_adc_ctrl_state,
.audio_codec_config_iface = es7210_adc_config_i2s,
.audio_codec_set_mute = es7210_set_mute,
.audio_codec_set_volume = es7210_adc_set_volume,
.audio_hal_lock = NULL,
.handle = NULL,
};
/*
* Clock coefficient structer
*/
struct _coeff_div
{
uint32_t mclk; /* mclk frequency */
uint32_t lrck; /* lrck */
uint8_t ss_ds;
uint8_t adc_div; /* adcclk divider */
uint8_t dll; /* dll_bypass */
uint8_t doubler; /* doubler enable */
uint8_t osr; /* adc osr */
uint8_t mclk_src; /* select mclk source */
uint32_t lrck_h; /* The high 4 bits of lrck */
uint32_t lrck_l; /* The low 8 bits of lrck */
};
static char *TAG = "ES7210";
static i2c_bus_handle_t i2c_handle;
static es7210_input_mics_t mic_select
= ES7210_INPUT_MIC1 | ES7210_INPUT_MIC2; /* Number of microphones */
/* Codec hifi mclk clock divider coefficients
* MEMBER REG
* mclk: 0x03
* lrck: standard
* ss_ds: --
* adc_div: 0x02
* dll: 0x06
* doubler: 0x02
* osr: 0x07
* mclk_src: 0x03
* lrckh: 0x04
* lrckl: 0x05
*/
static const struct _coeff_div coeff_div[] = {
// mclk lrck ss_ds adc_div dll doubler osr mclk_src lrckh lrckl
/* 8k */
{ 12288000, 8000, 0x00, 0x03, 0x01, 0x00, 0x20, 0x00, 0x06, 0x00 },
{ 16384000, 8000, 0x00, 0x04, 0x01, 0x00, 0x20, 0x00, 0x08, 0x00 },
{ 19200000, 8000, 0x00, 0x1e, 0x00, 0x01, 0x28, 0x00, 0x09, 0x60 },
{ 4096000, 8000, 0x00, 0x01, 0x01, 0x00, 0x20, 0x00, 0x02, 0x00 },
/* 11.025k */
{ 11289600, 11025, 0x00, 0x02, 0x01, 0x00, 0x20, 0x00, 0x01, 0x00 },
/* 12k */
{ 12288000, 12000, 0x00, 0x02, 0x01, 0x00, 0x20, 0x00, 0x04, 0x00 },
{ 19200000, 12000, 0x00, 0x14, 0x00, 0x01, 0x28, 0x00, 0x06, 0x40 },
/* 16k */
{ 4096000, 16000, 0x00, 0x01, 0x01, 0x01, 0x20, 0x00, 0x01, 0x00 },
{ 19200000, 16000, 0x00, 0x0a, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x80 },
{ 16384000, 16000, 0x00, 0x02, 0x01, 0x00, 0x20, 0x00, 0x04, 0x00 },
{ 12288000, 16000, 0x00, 0x03, 0x01, 0x01, 0x20, 0x00, 0x03, 0x00 },
/* 22.05k */
{ 11289600, 22050, 0x00, 0x01, 0x01, 0x00, 0x20, 0x00, 0x02, 0x00 },
/* 24k */
{ 12288000, 24000, 0x00, 0x01, 0x01, 0x00, 0x20, 0x00, 0x02, 0x00 },
{ 19200000, 24000, 0x00, 0x0a, 0x00, 0x01, 0x28, 0x00, 0x03, 0x20 },
/* 32k */
{ 12288000, 32000, 0x00, 0x03, 0x00, 0x00, 0x20, 0x00, 0x01, 0x80 },
{ 16384000, 32000, 0x00, 0x01, 0x01, 0x00, 0x20, 0x00, 0x02, 0x00 },
{ 19200000, 32000, 0x00, 0x05, 0x00, 0x00, 0x1e, 0x00, 0x02, 0x58 },
/* 44.1k */
{ 11289600, 44100, 0x00, 0x01, 0x01, 0x01, 0x20, 0x00, 0x01, 0x00 },
/* 48k */
{ 12288000, 48000, 0x00, 0x01, 0x01, 0x01, 0x20, 0x00, 0x01, 0x00 },
{ 19200000, 48000, 0x00, 0x05, 0x00, 0x01, 0x28, 0x00, 0x01, 0x90 },
/* 64k */
{ 16384000, 64000, 0x01, 0x01, 0x01, 0x00, 0x20, 0x00, 0x01, 0x00 },
{ 19200000, 64000, 0x00, 0x05, 0x00, 0x01, 0x1e, 0x00, 0x01, 0x2c },
/* 88.2k */
{ 11289600, 88200, 0x01, 0x01, 0x01, 0x01, 0x20, 0x00, 0x00, 0x80 },
/* 96k */
{ 12288000, 96000, 0x01, 0x01, 0x01, 0x01, 0x20, 0x00, 0x00, 0x80 },
{ 19200000, 96000, 0x01, 0x05, 0x00, 0x01, 0x28, 0x00, 0x00, 0xc8 },
};
static esp_err_t
es7210_write_reg (uint8_t reg_addr, uint8_t data)
{
return i2c_bus_write_bytes (i2c_handle, ES7210_ADDR, &reg_addr,
sizeof (reg_addr), &data, sizeof (data));
}
static esp_err_t
es7210_update_reg_bit (uint8_t reg_addr, uint8_t update_bits, uint8_t data)
{
uint8_t regv;
regv = es7210_read_reg (reg_addr);
regv = (regv & (~update_bits)) | (update_bits & data);
return es7210_write_reg (reg_addr, regv);
}
static int
i2c_init ()
{
int ret = 0;
i2c_config_t es_i2c_cfg = {
.mode = I2C_MODE_MASTER,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000,
};
ret = get_i2c_pins (I2C_NUM_0, &es_i2c_cfg);
AUDIO_CHECK (TAG, !ret, return ESP_FAIL;, "getting i2c pins error");
i2c_handle = i2c_bus_create (I2C_NUM_0, &es_i2c_cfg);
return ret;
}
static int
get_coeff (uint32_t mclk, uint32_t lrck)
{
for (int i = 0; i < (sizeof (coeff_div) / sizeof (coeff_div[0])); i++)
{
if (coeff_div[i].lrck == lrck && coeff_div[i].mclk == mclk)
return i;
}
return -1;
}
int8_t
get_es7210_mclk_src (void)
{
return ES7210_MCLK_SOURCE;
}
int
es7210_read_reg (uint8_t reg_addr)
{
uint8_t data;
i2c_bus_read_bytes (i2c_handle, ES7210_ADDR, &reg_addr, sizeof (reg_addr),
&data, sizeof (data));
return (int)data;
}
esp_err_t
es7210_config_sample (audio_hal_iface_samples_t sample)
{
uint8_t regv;
int coeff;
int sample_fre = 0;
int mclk_fre = 0;
esp_err_t ret = ESP_OK;
switch (sample)
{
case AUDIO_HAL_08K_SAMPLES:
sample_fre = 8000;
break;
case AUDIO_HAL_11K_SAMPLES:
sample_fre = 11025;
break;
case AUDIO_HAL_16K_SAMPLES:
sample_fre = 16000;
break;
case AUDIO_HAL_22K_SAMPLES:
sample_fre = 22050;
break;
case AUDIO_HAL_24K_SAMPLES:
sample_fre = 24000;
break;
case AUDIO_HAL_32K_SAMPLES:
sample_fre = 32000;
break;
case AUDIO_HAL_44K_SAMPLES:
sample_fre = 44100;
break;
case AUDIO_HAL_48K_SAMPLES:
sample_fre = 48000;
break;
default:
ESP_LOGE (TAG, "Unable to configure sample rate %dHz", sample_fre);
break;
}
mclk_fre = sample_fre * MCLK_DIV_FRE;
coeff = get_coeff (mclk_fre, sample_fre);
if (coeff < 0)
{
ESP_LOGE (TAG, "Unable to configure sample rate %dHz with %dHz MCLK",
sample_fre, mclk_fre);
return ESP_FAIL;
}
/* Set clock parammeters */
if (coeff >= 0)
{
/* Set adc_div & doubler & dll */
regv = es7210_read_reg (ES7210_MAINCLK_REG02) & 0x00;
regv |= coeff_div[coeff].adc_div;
regv |= coeff_div[coeff].doubler << 6;
regv |= coeff_div[coeff].dll << 7;
ret |= es7210_write_reg (ES7210_MAINCLK_REG02, regv);
/* Set osr */
regv = coeff_div[coeff].osr;
ret |= es7210_write_reg (ES7210_OSR_REG07, regv);
/* Set lrck */
regv = coeff_div[coeff].lrck_h;
ret |= es7210_write_reg (ES7210_LRCK_DIVH_REG04, regv);
regv = coeff_div[coeff].lrck_l;
ret |= es7210_write_reg (ES7210_LRCK_DIVL_REG05, regv);
}
return ret;
}
esp_err_t
es7210_mic_select (es7210_input_mics_t mic)
{
esp_err_t ret = ESP_OK;
mic_select = mic;
if (mic_select
& (ES7210_INPUT_MIC1 | ES7210_INPUT_MIC2 | ES7210_INPUT_MIC3
| ES7210_INPUT_MIC4))
{
for (int i = 0; i < 4; i++)
{
ret |= es7210_update_reg_bit (ES7210_MIC1_GAIN_REG43 + i, 0x10,
0x00);
}
ret |= es7210_write_reg (ES7210_MIC12_POWER_REG4B, 0xff);
ret |= es7210_write_reg (ES7210_MIC34_POWER_REG4C, 0xff);
if (mic_select & ES7210_INPUT_MIC1)
{
ESP_LOGI (TAG, "Enable ES7210_INPUT_MIC1");
ret |= es7210_update_reg_bit (ES7210_CLOCK_OFF_REG01, 0x0b, 0x00);
ret |= es7210_write_reg (ES7210_MIC12_POWER_REG4B, 0x00);
ret |= es7210_update_reg_bit (ES7210_MIC1_GAIN_REG43, 0x10, 0x10);
}
if (mic_select & ES7210_INPUT_MIC2)
{
ESP_LOGI (TAG, "Enable ES7210_INPUT_MIC2");
ret |= es7210_update_reg_bit (ES7210_CLOCK_OFF_REG01, 0x0b, 0x00);
ret |= es7210_write_reg (ES7210_MIC12_POWER_REG4B, 0x00);
ret |= es7210_update_reg_bit (ES7210_MIC2_GAIN_REG44, 0x10, 0x10);
}
if (mic_select & ES7210_INPUT_MIC3)
{
ESP_LOGI (TAG, "Enable ES7210_INPUT_MIC3");
ret |= es7210_update_reg_bit (ES7210_CLOCK_OFF_REG01, 0x15, 0x00);
ret |= es7210_write_reg (ES7210_MIC34_POWER_REG4C, 0x00);
ret |= es7210_update_reg_bit (ES7210_MIC3_GAIN_REG45, 0x10, 0x10);
}
if (mic_select & ES7210_INPUT_MIC4)
{
ESP_LOGI (TAG, "Enable ES7210_INPUT_MIC4");
ret |= es7210_update_reg_bit (ES7210_CLOCK_OFF_REG01, 0x15, 0x00);
ret |= es7210_write_reg (ES7210_MIC34_POWER_REG4C, 0x00);
ret |= es7210_update_reg_bit (ES7210_MIC4_GAIN_REG46, 0x10, 0x10);
}
}
else
{
ESP_LOGE (TAG, "Microphone selection error");
return ESP_FAIL;
}
return ret;
}
esp_err_t
es7210_adc_init (audio_hal_codec_config_t *codec_cfg)
{
esp_err_t ret = ESP_OK;
i2c_init ();
ret |= es7210_write_reg (ES7210_RESET_REG00, 0xff);
ret |= es7210_write_reg (ES7210_RESET_REG00, 0x41);
ret |= es7210_write_reg (ES7210_CLOCK_OFF_REG01, 0x1f);
ret |= es7210_write_reg (ES7210_TIME_CONTROL0_REG09,
0x30); /* Set chip state cycle */
ret |= es7210_write_reg (ES7210_TIME_CONTROL1_REG0A,
0x30); /* Set power on state cycle */
ret |= es7210_write_reg (ES7210_ADC12_HPF2_REG23, 0x2a); /* Quick setup */
ret |= es7210_write_reg (ES7210_ADC12_HPF1_REG22, 0x0a);
ret |= es7210_write_reg (ES7210_ADC34_HPF2_REG20, 0x0a);
ret |= es7210_write_reg (ES7210_ADC34_HPF1_REG21, 0x2a);
/* Set master/slave audio interface */
audio_hal_codec_i2s_iface_t *i2s_cfg = &(codec_cfg->i2s_iface);
switch (i2s_cfg->mode)
{
case AUDIO_HAL_MODE_MASTER: /* MASTER MODE */
ESP_LOGI (TAG, "ES7210 in Master mode");
ret |= es7210_update_reg_bit (ES7210_MODE_CONFIG_REG08, 0x01, 0x01);
/* Select clock source for internal mclk */
switch (get_es7210_mclk_src ())
{
case FROM_PAD_PIN:
ret |= es7210_update_reg_bit (ES7210_MASTER_CLK_REG03, 0x80, 0x00);
break;
case FROM_CLOCK_DOUBLE_PIN:
ret |= es7210_update_reg_bit (ES7210_MASTER_CLK_REG03, 0x80, 0x80);
break;
default:
ret |= es7210_update_reg_bit (ES7210_MASTER_CLK_REG03, 0x80, 0x00);
break;
}
break;
case AUDIO_HAL_MODE_SLAVE: /* SLAVE MODE */
ESP_LOGI (TAG, "ES7210 in Slave mode");
ret |= es7210_update_reg_bit (ES7210_MODE_CONFIG_REG08, 0x01, 0x00);
break;
default:
ret |= es7210_update_reg_bit (ES7210_MODE_CONFIG_REG08, 0x01, 0x00);
}
ret |= es7210_write_reg (ES7210_ANALOG_REG40,
0x43); /* Select power off analog, vdda = 3.3V,
close vx20ff, VMID select 5KΩ start */
ret |= es7210_write_reg (ES7210_MIC12_BIAS_REG41, 0x70); /* Select 2.87v */
ret |= es7210_write_reg (ES7210_MIC34_BIAS_REG42, 0x70); /* Select 2.87v */
ret |= es7210_write_reg (ES7210_OSR_REG07, 0x20);
ret |= es7210_write_reg (
ES7210_MAINCLK_REG02,
0xc1); /* Set the frequency division coefficient and use dll except clock
doubler, and need to set 0xc1 to clear the state */
ret |= es7210_config_sample (i2s_cfg->samples);
ret |= es7210_mic_select (mic_select);
ret |= es7210_adc_set_gain (GAIN_30DB);
return ESP_OK;
}
esp_err_t
es7210_adc_deinit ()
{
i2c_bus_delete (i2c_handle);
return ESP_OK;
}
esp_err_t
es7210_config_fmt (audio_hal_iface_format_t fmt)
{
esp_err_t ret = ESP_OK;
uint8_t adc_iface = 0;
adc_iface = es7210_read_reg (ES7210_SDP_INTERFACE1_REG11);
adc_iface &= 0xfc;
switch (fmt)
{
case AUDIO_HAL_I2S_NORMAL:
ESP_LOGD (TAG, "ES7210 in I2S Format");
adc_iface |= 0x00;
break;
case AUDIO_HAL_I2S_LEFT:
case AUDIO_HAL_I2S_RIGHT:
ESP_LOGD (TAG, "ES7210 in LJ Format");
adc_iface |= 0x01;
break;
case AUDIO_HAL_I2S_DSP:
if (I2S_DSP_MODE)
{
ESP_LOGD (TAG, "ES7210 in DSP-A Format");
adc_iface |= 0x13;
}
else
{
ESP_LOGD (TAG, "ES7210 in DSP-B Format");
adc_iface |= 0x03;
}
break;
default:
adc_iface &= 0xfc;
break;
}
ret |= es7210_write_reg (ES7210_SDP_INTERFACE1_REG11, adc_iface);
return ret;
}
esp_err_t
es7210_set_bits (audio_hal_iface_bits_t bits)
{
esp_err_t ret = ESP_OK;
uint8_t adc_iface = 0;
adc_iface = es7210_read_reg (ES7210_SDP_INTERFACE1_REG11);
adc_iface &= 0x1f;
switch (bits)
{
case AUDIO_HAL_BIT_LENGTH_16BITS:
adc_iface |= 0x60;
break;
case AUDIO_HAL_BIT_LENGTH_24BITS:
adc_iface |= 0x00;
break;
case AUDIO_HAL_BIT_LENGTH_32BITS:
adc_iface |= 0x80;
break;
default:
adc_iface |= 0x60;
break;
}
ret |= es7210_write_reg (ES7210_SDP_INTERFACE1_REG11, adc_iface);
return ret;
}
esp_err_t
es7210_adc_config_i2s (audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface)
{
esp_err_t ret = ESP_OK;
ret |= es7210_set_bits (iface->bits);
ret |= es7210_config_fmt (iface->fmt);
ret |= es7210_config_sample (iface->samples);
return ret;
}
esp_err_t
es7210_start (uint8_t clock_reg_value)
{
esp_err_t ret = ESP_OK;
ret |= es7210_write_reg (ES7210_CLOCK_OFF_REG01, clock_reg_value);
ret |= es7210_write_reg (ES7210_POWER_DOWN_REG06, 0x00);
ret |= es7210_write_reg (ES7210_ANALOG_REG40, 0x43);
ret |= es7210_write_reg (ES7210_MIC1_POWER_REG47, 0x00);
ret |= es7210_write_reg (ES7210_MIC2_POWER_REG48, 0x00);
ret |= es7210_write_reg (ES7210_MIC3_POWER_REG49, 0x00);
ret |= es7210_write_reg (ES7210_MIC4_POWER_REG4A, 0x00);
ret |= es7210_mic_select (mic_select);
return ret;
}
esp_err_t
es7210_stop (void)
{
esp_err_t ret = ESP_OK;
ret |= es7210_write_reg (ES7210_MIC1_POWER_REG47, 0xff);
ret |= es7210_write_reg (ES7210_MIC2_POWER_REG48, 0xff);
ret |= es7210_write_reg (ES7210_MIC3_POWER_REG49, 0xff);
ret |= es7210_write_reg (ES7210_MIC4_POWER_REG4A, 0xff);
ret |= es7210_write_reg (ES7210_MIC12_POWER_REG4B, 0xff);
ret |= es7210_write_reg (ES7210_MIC34_POWER_REG4C, 0xff);
ret |= es7210_write_reg (ES7210_ANALOG_REG40, 0xc0);
ret |= es7210_write_reg (ES7210_CLOCK_OFF_REG01, 0x7f);
ret |= es7210_write_reg (ES7210_POWER_DOWN_REG06, 0x07);
return ret;
}
esp_err_t
es7210_adc_ctrl_state (audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state)
{
static uint8_t regv;
esp_err_t ret = ESP_OK;
ESP_LOGW (TAG, "ES7210 only supports ADC mode");
ret = es7210_read_reg (ES7210_CLOCK_OFF_REG01);
if ((ret != 0x7f) && (ret != 0xff))
{
regv = es7210_read_reg (ES7210_CLOCK_OFF_REG01);
}
if (ctrl_state == AUDIO_HAL_CTRL_START)
{
ESP_LOGI (TAG, "The ES7210_CLOCK_OFF_REG01 value before stop is %x",
regv);
ret |= es7210_start (regv);
}
else
{
ESP_LOGW (TAG, "The codec is about to stop");
regv = es7210_read_reg (ES7210_CLOCK_OFF_REG01);
ret |= es7210_stop ();
}
return ret;
}
esp_err_t
es7210_adc_set_gain (es7210_gain_value_t gain)
{
esp_err_t ret = ESP_OK;
uint32_t max_gain_vaule = 14;
if (gain < 0)
{
gain = 0;
}
else if (gain > max_gain_vaule)
{
gain = max_gain_vaule;
}
ESP_LOGD (TAG, "SET: gain:%d", gain);
if (mic_select & ES7210_INPUT_MIC1)
{
ret |= es7210_update_reg_bit (ES7210_MIC1_GAIN_REG43, 0x0f, gain);
}
if (mic_select & ES7210_INPUT_MIC2)
{
ret |= es7210_update_reg_bit (ES7210_MIC2_GAIN_REG44, 0x0f, gain);
}
if (mic_select & ES7210_INPUT_MIC3)
{
ret |= es7210_update_reg_bit (ES7210_MIC3_GAIN_REG45, 0x0f, gain);
}
if (mic_select & ES7210_INPUT_MIC4)
{
ret |= es7210_update_reg_bit (ES7210_MIC4_GAIN_REG46, 0x0f, gain);
}
return ret;
}
esp_err_t
es7210_adc_get_gain (void)
{
int regv = 0;
uint8_t gain_value;
if (mic_select & ES7210_INPUT_MIC1)
{
regv = es7210_read_reg (ES7210_MIC1_GAIN_REG43);
}
else if (mic_select & ES7210_INPUT_MIC2)
{
regv = es7210_read_reg (ES7210_MIC2_GAIN_REG44);
}
else if (mic_select & ES7210_INPUT_MIC3)
{
regv = es7210_read_reg (ES7210_MIC3_GAIN_REG45);
}
else if (mic_select & ES7210_INPUT_MIC4)
{
regv = es7210_read_reg (ES7210_MIC4_GAIN_REG46);
}
else
{
ESP_LOGE (TAG, "No MIC selected");
return ESP_FAIL;
}
if (regv == ESP_FAIL)
{
return regv;
}
gain_value = (regv & 0x0f); /* Retain the last four bits for gain */
ESP_LOGI (TAG, "GET: gain_value:%d", gain_value);
return gain_value;
}
esp_err_t
es7210_adc_set_volume (int volume)
{
esp_err_t ret = ESP_OK;
ESP_LOGD (TAG, "ADC can adjust gain");
return ret;
}
esp_err_t
es7210_set_mute (bool enable)
{
ESP_LOGD (TAG, "ES7210 SetMute :%d", enable);
return ESP_OK;
}
void
es7210_read_all (void)
{
for (int i = 0; i <= 0x4E; i++)
{
uint8_t reg = es7210_read_reg (i);
ets_printf ("REG:%02x, %02x\n", reg, i);
}
}

View File

@@ -0,0 +1,234 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2021 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _ES7210_H
#define _ES7210_H
#include "audio_hal.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define ES7210_RESET_REG00 0x00 /* Reset control */
#define ES7210_CLOCK_OFF_REG01 0x01 /* Used to turn off the ADC clock */
#define ES7210_MAINCLK_REG02 0x02 /* Set ADC clock frequency division */
#define ES7210_MASTER_CLK_REG03 0x03 /* MCLK source $ SCLK division */
#define ES7210_LRCK_DIVH_REG04 0x04 /* lrck_divh */
#define ES7210_LRCK_DIVL_REG05 0x05 /* lrck_divl */
#define ES7210_POWER_DOWN_REG06 0x06 /* power down */
#define ES7210_OSR_REG07 0x07
#define ES7210_MODE_CONFIG_REG08 0x08 /* Set master/slave & channels */
#define ES7210_TIME_CONTROL0_REG09 0x09 /* Set Chip intial state period*/
#define ES7210_TIME_CONTROL1_REG0A 0x0A /* Set Power up state period */
#define ES7210_SDP_INTERFACE1_REG11 0x11 /* Set sample & fmt */
#define ES7210_SDP_INTERFACE2_REG12 0x12 /* Pins state */
#define ES7210_ADC_AUTOMUTE_REG13 0x13 /* Set mute */
#define ES7210_ADC34_MUTERANGE_REG14 0x14 /* Set mute range */
#define ES7210_ADC34_HPF2_REG20 0x20 /* HPF */
#define ES7210_ADC34_HPF1_REG21 0x21
#define ES7210_ADC12_HPF1_REG22 0x22
#define ES7210_ADC12_HPF2_REG23 0x23
#define ES7210_ANALOG_REG40 0x40 /* ANALOG Power */
#define ES7210_MIC12_BIAS_REG41 0x41
#define ES7210_MIC34_BIAS_REG42 0x42
#define ES7210_MIC1_GAIN_REG43 0x43
#define ES7210_MIC2_GAIN_REG44 0x44
#define ES7210_MIC3_GAIN_REG45 0x45
#define ES7210_MIC4_GAIN_REG46 0x46
#define ES7210_MIC1_POWER_REG47 0x47
#define ES7210_MIC2_POWER_REG48 0x48
#define ES7210_MIC3_POWER_REG49 0x49
#define ES7210_MIC4_POWER_REG4A 0x4A
#define ES7210_MIC12_POWER_REG4B 0x4B /* MICBias & ADC & PGA Power */
#define ES7210_MIC34_POWER_REG4C 0x4C
typedef enum
{
ES7210_AD1_AD0_00 = 0x80,
ES7210_AD1_AD0_01 = 0x82,
ES7210_AD1_AD0_10 = 0x84,
ES7210_AD1_AD0_11 = 0x86
} es7210_address_t;
typedef enum
{
ES7210_INPUT_MIC1 = 0x01,
ES7210_INPUT_MIC2 = 0x02,
ES7210_INPUT_MIC3 = 0x04,
ES7210_INPUT_MIC4 = 0x08
} es7210_input_mics_t;
typedef enum gain_value
{
GAIN_0DB = 0,
GAIN_3DB,
GAIN_6DB,
GAIN_9DB,
GAIN_12DB,
GAIN_15DB,
GAIN_18DB,
GAIN_21DB,
GAIN_24DB,
GAIN_27DB,
GAIN_30DB,
GAIN_33DB,
GAIN_34_5DB,
GAIN_36DB,
GAIN_37_5DB,
} es7210_gain_value_t;
/*
* @brief Initialize ES7210 ADC chip
*
* @param[in] codec_cfg: configuration of ES7210
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7210_adc_init (audio_hal_codec_config_t *codec_cfg);
/**
* @brief Deinitialize ES7210 ADC chip
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7210_adc_deinit ();
/**
* @brief Configure ES7210 ADC mode and I2S interface
*
* @param[in] mode: codec mode
* @param[in] iface: I2S config
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es7210_adc_config_i2s (audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface);
/**
* @brief Control ES7210 ADC chip
*
* @param[in] mode: codec mode
* @param[in] ctrl_state: start or stop progress
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es7210_adc_ctrl_state (audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state);
/**
* @brief Set gain (Note: the enabled microphone sets the same gain)
*
* @param[in] gain: gain
*
* gain : value
* GAIN_0DB : 1
* GAIN_3DB : 2
* GAIN_6DB : 3
* ·
* ·
* ·
* GAIN_30DB : 10
* GAIN_33DB : 11
* GAIN_34_5DB : 12
* GAIN_36DB : 13
* GAIN_37_5DB : 14
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7210_adc_set_gain (es7210_gain_value_t gain);
/**
* @brief Get gain
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7210_adc_get_gain (void);
/**
* @brief Set volume
*
* @param[in] volume: volume
*
* @return
* - ESP_OK
*/
esp_err_t es7210_adc_set_volume (int volume);
/**
* @brief Set ES7210 ADC mute status
*
* @return
* - ESP_FAIL
* - ESP_OK
*/
esp_err_t es7210_set_mute (bool enable);
/**
* @brief Select ES7210 mic
*
* @param[in] mic: mics
*
* @return
* - ESP_FAIL
* - ESP_OK
*/
esp_err_t es7210_mic_select (es7210_input_mics_t mic);
/**
* @brief Read regs of ES7210
*
* @param[in] reg_addr: reg_addr
*
* @return
* - ESP_FAIL
* - ESP_OK
*/
int es7210_read_reg (uint8_t reg_addr);
/**
* @brief Read all regs of ES7210
*/
void es7210_read_all (void);
#ifdef __cplusplus
}
#endif
#endif /* _ES7210_H_ */

View File

@@ -0,0 +1,210 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "es7243.h"
#include "board.h"
#include "esp_log.h"
#include "i2c_bus.h"
#include <string.h>
#define MCLK_PULSES_NUMBER (20)
#define ES_ASSERT(a, format, b, ...) \
if ((a) != 0) \
{ \
ESP_LOGE (TAG, format, ##__VA_ARGS__); \
return b; \
}
static char *TAG = "DRV7243";
static i2c_bus_handle_t i2c_handle;
static int es7243_addr = 0x26;
audio_hal_func_t AUDIO_CODEC_ES7243_DEFAULT_HANDLE = {
.audio_codec_initialize = es7243_adc_init,
.audio_codec_deinitialize = es7243_adc_deinit,
.audio_codec_ctrl = es7243_adc_ctrl_state,
.audio_codec_config_iface = es7243_adc_config_i2s,
.audio_codec_set_mute = es7243_adc_set_voice_mute,
.audio_codec_set_volume = es7243_adc_set_voice_volume,
.audio_codec_get_volume = es7243_adc_get_voice_volume,
.audio_hal_lock = NULL,
.handle = NULL,
};
static esp_err_t
es7243_write_reg (uint8_t reg_add, uint8_t data)
{
return i2c_bus_write_bytes (i2c_handle, es7243_addr, &reg_add,
sizeof (reg_add), &data, sizeof (data));
}
static int
i2c_init ()
{
int res = 0;
i2c_config_t es_i2c_cfg = {
.mode = I2C_MODE_MASTER,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000,
};
res = get_i2c_pins (I2C_NUM_0, &es_i2c_cfg);
ES_ASSERT (res, "getting i2c pins error", -1);
i2c_handle = i2c_bus_create (I2C_NUM_0, &es_i2c_cfg);
return res;
}
esp_err_t
es7243_adc_set_addr (int addr)
{
es7243_addr = addr;
return ESP_OK;
}
static esp_err_t
es7243_mclk_active (uint8_t mclk_gpio)
{
gpio_pad_select_gpio (mclk_gpio);
gpio_set_direction (mclk_gpio, GPIO_MODE_OUTPUT);
/*
Before initializing es7243, it is necessary to output
mclk to es7243 to activate the I2C configuration.
So give some clocks to active es7243.
*/
for (int i = 0; i < MCLK_PULSES_NUMBER; ++i)
{
gpio_set_level (mclk_gpio, 0);
vTaskDelay (1 / portTICK_PERIOD_MS);
gpio_set_level (mclk_gpio, 1);
vTaskDelay (1 / portTICK_PERIOD_MS);
}
return ESP_OK;
}
esp_err_t
es7243_adc_init (audio_hal_codec_config_t *codec_cfg)
{
esp_err_t ret = ESP_OK;
es7243_mclk_active (get_es7243_mclk_gpio ());
i2c_init ();
ret |= es7243_write_reg (0x00, 0x01);
ret |= es7243_write_reg (0x06, 0x00);
ret |= es7243_write_reg (0x05, 0x1B);
ret |= es7243_write_reg (0x01, 0x0C);
ret |= es7243_write_reg (0x08, 0x43);
ret |= es7243_write_reg (0x05, 0x13);
if (ret)
{
ESP_LOGE (TAG, "Es7243 initialize failed!");
return ESP_FAIL;
}
return ret;
}
esp_err_t
es7243_adc_deinit (void)
{
return ESP_OK;
}
esp_err_t
es7243_adc_ctrl_state (audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state)
{
return ESP_OK;
}
esp_err_t
es7243_adc_config_i2s (audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface)
{
return ESP_OK;
}
esp_err_t
es7243_adc_set_voice_mute (bool mute)
{
ESP_LOGI (TAG, "Enter into es7243_mute(), mute = %d\n", mute);
if (mute)
{
es7243_write_reg (0x05, 0x1B);
}
else
{
es7243_write_reg (0x05, 0x13);
}
return ESP_OK;
}
esp_err_t
es7243_adc_set_voice_volume (int volume)
{
esp_err_t ret = ESP_OK;
if (volume > 100)
{
volume = 100;
}
if (volume < 0)
{
volume = 0;
}
switch (volume)
{
case 0 ... 12:
ret |= es7243_write_reg (0x08, 0x11); // 1db
break;
case 13 ... 25:
ret |= es7243_write_reg (0x08, 0x13); // 3.5db
break;
case 26 ... 38:
ret |= es7243_write_reg (0x08, 0x21); // 18db
break;
case 39 ... 51:
ret |= es7243_write_reg (0x08, 0x23); // 20.5db
break;
case 52 ... 65:
ret |= es7243_write_reg (0x08, 0x06); // 22.5db
break;
case 66 ... 80:
ret |= es7243_write_reg (0x08, 0x41); // 24.5db
break;
case 81 ... 90:
ret |= es7243_write_reg (0x08, 0x07); // 25db
break;
case 91 ... 100:
ret |= es7243_write_reg (0x08, 0x43); // 27db
break;
default:
break;
}
return ESP_OK;
}
esp_err_t
es7243_adc_get_voice_volume (int *volume)
{
return ESP_OK;
}

View File

@@ -0,0 +1,132 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _ES7243_H_
#define _ES7243_H_
#include "audio_hal.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Initialize ES7243 adc chip
*
* @param codec_cfg configuration of ES7243
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7243_adc_init (audio_hal_codec_config_t *codec_cfg);
/**
* @brief Deinitialize ES7243 adc chip
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7243_adc_deinit (void);
/**
* @brief Control ES7243 adc chip
*
* @param mode adc mode
* @param ctrl_state start or stop decode or encode progress
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es7243_adc_ctrl_state (audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state);
/**
* @brief Configure ES7243 adc mode and I2S interface
*
* @param mode codec mode
* @param iface I2S config
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es7243_adc_config_i2s (audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface);
/**
* @brief Set mute
*
* @param mute true, false
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7243_adc_set_voice_mute (bool mute);
/**
* @brief Set adc gain
*
* @param volume value of gain (0~100)
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7243_adc_set_voice_volume (int volume);
/**
* @brief Get adc gain
*
* @param[out] *volume: value of gain (0~100)
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7243_adc_get_voice_volume (int *volume);
/**
* @brief Set adc I2C address
*
* @param[in] addr: value of I2C address
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7243_adc_set_addr (int addr);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,870 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "es8311.h"
#include "board.h"
#include "esp_log.h"
#include "i2c_bus.h"
#include <string.h>
/* ES8311 address
* 0x32:CE=1;0x30:CE=0
*/
#define ES8311_ADDR 0x30
/*
* to define the clock soure of MCLK
*/
#define FROM_MCLK_PIN 0
#define FROM_SCLK_PIN 1
/*
* to define whether to reverse the clock
*/
#define INVERT_MCLK 0 // do not invert
#define INVERT_SCLK 0
#define IS_DMIC 0 // Is it a digital microphone
#define MCLK_DIV_FRE 256
static i2c_bus_handle_t i2c_handle;
/*
* operate function of codec
*/
audio_hal_func_t AUDIO_CODEC_ES8311_DEFAULT_HANDLE = {
.audio_codec_initialize = es8311_codec_init,
.audio_codec_deinitialize = es8311_codec_deinit,
.audio_codec_ctrl = es8311_codec_ctrl_state,
.audio_codec_config_iface = es8311_codec_config_i2s,
.audio_codec_set_mute = es8311_set_voice_mute,
.audio_codec_set_volume = es8311_codec_set_voice_volume,
.audio_codec_get_volume = es8311_codec_get_voice_volume,
.audio_hal_lock = NULL,
.handle = NULL,
};
/*
* Clock coefficient structer
*/
struct _coeff_div
{
uint32_t mclk; /* mclk frequency */
uint32_t rate; /* sample rate */
uint8_t pre_div; /* the pre divider with range from 1 to 8 */
uint8_t pre_multi; /* the pre multiplier with x1, x2, x4 and x8 selection */
uint8_t adc_div; /* adcclk divider */
uint8_t dac_div; /* dacclk divider */
uint8_t fs_mode; /* double speed or single speed, =0, ss, =1, ds */
uint8_t lrck_h; /* adclrck divider and daclrck divider */
uint8_t lrck_l;
uint8_t bclk_div; /* sclk divider */
uint8_t adc_osr; /* adc osr */
uint8_t dac_osr; /* dac osr */
};
/* codec hifi mclk clock divider coefficients */
static const struct _coeff_div coeff_div[] = {
// mclk rate pre_div mult adc_div dac_div fs_mode lrch lrcl bckdiv
// osr
/* 8k */
{ 12288000, 8000, 0x06, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 18432000, 8000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x05, 0xff, 0x18, 0x10,
0x10 },
{ 16384000, 8000, 0x08, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 8192000, 8000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 6144000, 8000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 4096000, 8000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 3072000, 8000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 2048000, 8000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 1536000, 8000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 1024000, 8000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
/* 11.025k */
{ 11289600, 11025, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 5644800, 11025, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 2822400, 11025, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 1411200, 11025, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
/* 12k */
{ 12288000, 12000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 6144000, 12000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 3072000, 12000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 1536000, 12000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
/* 16k */
{ 12288000, 16000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 18432000, 16000, 0x03, 0x02, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10,
0x10 },
{ 16384000, 16000, 0x04, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 8192000, 16000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 6144000, 16000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 4096000, 16000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 3072000, 16000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 2048000, 16000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 1536000, 16000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 1024000, 16000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
/* 22.05k */
{ 11289600, 22050, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 5644800, 22050, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 2822400, 22050, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 1411200, 22050, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
/* 24k */
{ 12288000, 24000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 18432000, 24000, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 6144000, 24000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 3072000, 24000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 1536000, 24000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
/* 32k */
{ 12288000, 32000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 18432000, 32000, 0x03, 0x04, 0x03, 0x03, 0x00, 0x02, 0xff, 0x0c, 0x10,
0x10 },
{ 16384000, 32000, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 8192000, 32000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 6144000, 32000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 4096000, 32000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 3072000, 32000, 0x03, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 2048000, 32000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 1536000, 32000, 0x03, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10,
0x10 },
{ 1024000, 32000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
/* 44.1k */
{ 11289600, 44100, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 5644800, 44100, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 2822400, 44100, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 1411200, 44100, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
/* 48k */
{ 12288000, 48000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 18432000, 48000, 0x03, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 6144000, 48000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 3072000, 48000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 1536000, 48000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
/* 64k */
{ 12288000, 64000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 18432000, 64000, 0x03, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10,
0x10 },
{ 16384000, 64000, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 8192000, 64000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 6144000, 64000, 0x01, 0x04, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10,
0x10 },
{ 4096000, 64000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 3072000, 64000, 0x01, 0x08, 0x03, 0x03, 0x01, 0x01, 0x7f, 0x06, 0x10,
0x10 },
{ 2048000, 64000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 1536000, 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0xbf, 0x03, 0x18,
0x18 },
{ 1024000, 64000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10,
0x10 },
/* 88.2k */
{ 11289600, 88200, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 5644800, 88200, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 2822400, 88200, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 1411200, 88200, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10,
0x10 },
/* 96k */
{ 12288000, 96000, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 18432000, 96000, 0x03, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 6144000, 96000, 0x01, 0x04, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 3072000, 96000, 0x01, 0x08, 0x01, 0x01, 0x00, 0x00, 0xff, 0x04, 0x10,
0x10 },
{ 1536000, 96000, 0x01, 0x08, 0x01, 0x01, 0x01, 0x00, 0x7f, 0x02, 0x10,
0x10 },
};
static char *TAG = "DRV8311";
#define ES_ASSERT(a, format, b, ...) \
if ((a) != 0) \
{ \
ESP_LOGE (TAG, format, ##__VA_ARGS__); \
return b; \
}
int8_t get_es8311_mclk_src (void);
static esp_err_t
es8311_write_reg (uint8_t reg_addr, uint8_t data)
{
return i2c_bus_write_bytes (i2c_handle, ES8311_ADDR, &reg_addr,
sizeof (reg_addr), &data, sizeof (data));
}
static int
es8311_read_reg (uint8_t reg_addr)
{
uint8_t data;
i2c_bus_read_bytes (i2c_handle, ES8311_ADDR, &reg_addr, sizeof (reg_addr),
&data, sizeof (data));
return (int)data;
}
static int
i2c_init ()
{
int res = 0;
i2c_config_t es_i2c_cfg = {
.mode = I2C_MODE_MASTER,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000,
};
res = get_i2c_pins (I2C_NUM_0, &es_i2c_cfg);
ES_ASSERT (res, "getting i2c pins error", -1);
i2c_handle = i2c_bus_create (I2C_NUM_0, &es_i2c_cfg);
return res;
}
/*
* look for the coefficient in coeff_div[] table
*/
static int
get_coeff (uint32_t mclk, uint32_t rate)
{
for (int i = 0; i < (sizeof (coeff_div) / sizeof (coeff_div[0])); i++)
{
if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
return i;
}
return -1;
}
/*
* set es8311 dac mute or not
* if mute = 0, dac un-mute
* if mute = 1, dac mute
*/
static void
es8311_mute (int mute)
{
uint8_t regv;
ESP_LOGI (TAG, "Enter into es8311_mute(), mute = %d\n", mute);
regv = es8311_read_reg (ES8311_DAC_REG31) & 0x9f;
if (mute)
{
es8311_write_reg (ES8311_SYSTEM_REG12, 0x02);
es8311_write_reg (ES8311_DAC_REG31, regv | 0x60);
es8311_write_reg (ES8311_DAC_REG32, 0x00);
es8311_write_reg (ES8311_DAC_REG37, 0x08);
}
else
{
es8311_write_reg (ES8311_DAC_REG31, regv);
es8311_write_reg (ES8311_SYSTEM_REG12, 0x00);
}
}
/*
* set es8311 into suspend mode
*/
static void
es8311_suspend (void)
{
ESP_LOGI (TAG, "Enter into es8311_suspend()");
es8311_write_reg (ES8311_DAC_REG32, 0x00);
es8311_write_reg (ES8311_ADC_REG17, 0x00);
es8311_write_reg (ES8311_SYSTEM_REG0E, 0xFF);
es8311_write_reg (ES8311_SYSTEM_REG12, 0x02);
es8311_write_reg (ES8311_SYSTEM_REG14, 0x00);
es8311_write_reg (ES8311_SYSTEM_REG0D, 0xFA);
es8311_write_reg (ES8311_ADC_REG15, 0x00);
es8311_write_reg (ES8311_DAC_REG37, 0x08);
es8311_write_reg (ES8311_GP_REG45, 0x01);
}
/*
* enable pa power
*/
void
es8311_pa_power (bool enable)
{
gpio_config_t io_conf;
memset (&io_conf, 0, sizeof (io_conf));
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = BIT64 (get_pa_enable_gpio ());
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
gpio_config (&io_conf);
if (enable)
{
gpio_set_level (get_pa_enable_gpio (), 1);
}
else
{
gpio_set_level (get_pa_enable_gpio (), 0);
}
}
esp_err_t
es8311_codec_init (audio_hal_codec_config_t *codec_cfg)
{
uint8_t datmp, regv;
int coeff;
esp_err_t ret = ESP_OK;
i2c_init (); // ESP32 in master mode
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG01, 0x30);
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG02, 0x00);
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG03, 0x10);
ret |= es8311_write_reg (ES8311_ADC_REG16, 0x24);
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG04, 0x10);
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG05, 0x00);
ret |= es8311_write_reg (ES8311_SYSTEM_REG0B, 0x00);
ret |= es8311_write_reg (ES8311_SYSTEM_REG0C, 0x00);
ret |= es8311_write_reg (ES8311_SYSTEM_REG10, 0x1F);
ret |= es8311_write_reg (ES8311_SYSTEM_REG11, 0x7F);
ret |= es8311_write_reg (ES8311_RESET_REG00, 0x80);
/*
* Set Codec into Master or Slave mode
*/
regv = es8311_read_reg (ES8311_RESET_REG00);
/*
* Set master/slave audio interface
*/
audio_hal_codec_i2s_iface_t *i2s_cfg = &(codec_cfg->i2s_iface);
switch (i2s_cfg->mode)
{
case AUDIO_HAL_MODE_MASTER: /* MASTER MODE */
ESP_LOGI (TAG, "ES8311 in Master mode");
regv |= 0x40;
break;
case AUDIO_HAL_MODE_SLAVE: /* SLAVE MODE */
ESP_LOGI (TAG, "ES8311 in Slave mode");
regv &= 0xBF;
break;
default:
regv &= 0xBF;
}
ret |= es8311_write_reg (ES8311_RESET_REG00, regv);
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG01, 0x3F);
/*
* Select clock source for internal mclk
*/
switch (get_es8311_mclk_src ())
{
case FROM_MCLK_PIN:
regv = es8311_read_reg (ES8311_CLK_MANAGER_REG01);
regv &= 0x7F;
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG01, regv);
break;
case FROM_SCLK_PIN:
regv = es8311_read_reg (ES8311_CLK_MANAGER_REG01);
regv |= 0x80;
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG01, regv);
break;
default:
regv = es8311_read_reg (ES8311_CLK_MANAGER_REG01);
regv &= 0x7F;
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG01, regv);
break;
}
int sample_fre = 0;
int mclk_fre = 0;
switch (i2s_cfg->samples)
{
case AUDIO_HAL_08K_SAMPLES:
sample_fre = 8000;
break;
case AUDIO_HAL_11K_SAMPLES:
sample_fre = 11025;
break;
case AUDIO_HAL_16K_SAMPLES:
sample_fre = 16000;
break;
case AUDIO_HAL_22K_SAMPLES:
sample_fre = 22050;
break;
case AUDIO_HAL_24K_SAMPLES:
sample_fre = 24000;
break;
case AUDIO_HAL_32K_SAMPLES:
sample_fre = 32000;
break;
case AUDIO_HAL_44K_SAMPLES:
sample_fre = 44100;
break;
case AUDIO_HAL_48K_SAMPLES:
sample_fre = 48000;
break;
default:
ESP_LOGE (TAG, "Unable to configure sample rate %dHz", sample_fre);
break;
}
mclk_fre = sample_fre * MCLK_DIV_FRE;
coeff = get_coeff (mclk_fre, sample_fre);
if (coeff < 0)
{
ESP_LOGE (TAG, "Unable to configure sample rate %dHz with %dHz MCLK",
sample_fre, mclk_fre);
return ESP_FAIL;
}
/*
* Set clock parammeters
*/
if (coeff >= 0)
{
regv = es8311_read_reg (ES8311_CLK_MANAGER_REG02) & 0x07;
regv |= (coeff_div[coeff].pre_div - 1) << 5;
datmp = 0;
switch (coeff_div[coeff].pre_multi)
{
case 1:
datmp = 0;
break;
case 2:
datmp = 1;
break;
case 4:
datmp = 2;
break;
case 8:
datmp = 3;
break;
default:
break;
}
if (get_es8311_mclk_src () == FROM_SCLK_PIN)
{
datmp = 3; /* DIG_MCLK = LRCK * 256 = BCLK * 8 */
}
regv |= (datmp) << 3;
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG02, regv);
regv = es8311_read_reg (ES8311_CLK_MANAGER_REG05) & 0x00;
regv |= (coeff_div[coeff].adc_div - 1) << 4;
regv |= (coeff_div[coeff].dac_div - 1) << 0;
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG05, regv);
regv = es8311_read_reg (ES8311_CLK_MANAGER_REG03) & 0x80;
regv |= coeff_div[coeff].fs_mode << 6;
regv |= coeff_div[coeff].adc_osr << 0;
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG03, regv);
regv = es8311_read_reg (ES8311_CLK_MANAGER_REG04) & 0x80;
regv |= coeff_div[coeff].dac_osr << 0;
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG04, regv);
regv = es8311_read_reg (ES8311_CLK_MANAGER_REG07) & 0xC0;
regv |= coeff_div[coeff].lrck_h << 0;
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG07, regv);
regv = es8311_read_reg (ES8311_CLK_MANAGER_REG08) & 0x00;
regv |= coeff_div[coeff].lrck_l << 0;
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG08, regv);
regv = es8311_read_reg (ES8311_CLK_MANAGER_REG06) & 0xE0;
if (coeff_div[coeff].bclk_div < 19)
{
regv |= (coeff_div[coeff].bclk_div - 1) << 0;
}
else
{
regv |= (coeff_div[coeff].bclk_div) << 0;
}
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG06, regv);
}
/*
* mclk inverted or not
*/
if (INVERT_MCLK)
{
regv = es8311_read_reg (ES8311_CLK_MANAGER_REG01);
regv |= 0x40;
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG01, regv);
}
else
{
regv = es8311_read_reg (ES8311_CLK_MANAGER_REG01);
regv &= ~(0x40);
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG01, regv);
}
/*
* sclk inverted or not
*/
if (INVERT_SCLK)
{
regv = es8311_read_reg (ES8311_CLK_MANAGER_REG06);
regv |= 0x20;
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG06, regv);
}
else
{
regv = es8311_read_reg (ES8311_CLK_MANAGER_REG06);
regv &= ~(0x20);
ret |= es8311_write_reg (ES8311_CLK_MANAGER_REG06, regv);
}
ret |= es8311_write_reg (ES8311_SYSTEM_REG13, 0x10);
ret |= es8311_write_reg (ES8311_ADC_REG1B, 0x0A);
ret |= es8311_write_reg (ES8311_ADC_REG1C, 0x6A);
es8311_pa_power (true);
return ESP_OK;
}
esp_err_t
es8311_codec_deinit ()
{
i2c_bus_delete (i2c_handle);
return ESP_OK;
}
esp_err_t
es8311_config_fmt (es_i2s_fmt_t fmt)
{
esp_err_t ret = ESP_OK;
uint8_t adc_iface = 0, dac_iface = 0;
dac_iface = es8311_read_reg (ES8311_SDPIN_REG09);
adc_iface = es8311_read_reg (ES8311_SDPOUT_REG0A);
switch (fmt)
{
case AUDIO_HAL_I2S_NORMAL:
ESP_LOGD (TAG, "ES8311 in I2S Format");
dac_iface &= 0xFC;
adc_iface &= 0xFC;
break;
case AUDIO_HAL_I2S_LEFT:
case AUDIO_HAL_I2S_RIGHT:
ESP_LOGD (TAG, "ES8311 in LJ Format");
adc_iface &= 0xFC;
dac_iface &= 0xFC;
adc_iface |= 0x01;
dac_iface |= 0x01;
break;
case AUDIO_HAL_I2S_DSP:
ESP_LOGD (TAG, "ES8311 in DSP-A Format");
adc_iface &= 0xDC;
dac_iface &= 0xDC;
adc_iface |= 0x03;
dac_iface |= 0x03;
break;
default:
dac_iface &= 0xFC;
adc_iface &= 0xFC;
break;
}
ret |= es8311_write_reg (ES8311_SDPIN_REG09, dac_iface);
ret |= es8311_write_reg (ES8311_SDPOUT_REG0A, adc_iface);
return ret;
}
esp_err_t
es8311_set_bits_per_sample (audio_hal_iface_bits_t bits)
{
esp_err_t ret = ESP_OK;
uint8_t adc_iface = 0, dac_iface = 0;
dac_iface = es8311_read_reg (ES8311_SDPIN_REG09);
adc_iface = es8311_read_reg (ES8311_SDPOUT_REG0A);
switch (bits)
{
case AUDIO_HAL_BIT_LENGTH_16BITS:
dac_iface |= 0x0c;
adc_iface |= 0x0c;
break;
case AUDIO_HAL_BIT_LENGTH_24BITS:
break;
case AUDIO_HAL_BIT_LENGTH_32BITS:
dac_iface |= 0x10;
adc_iface |= 0x10;
break;
default:
dac_iface |= 0x0c;
adc_iface |= 0x0c;
break;
}
ret |= es8311_write_reg (ES8311_SDPIN_REG09, dac_iface);
ret |= es8311_write_reg (ES8311_SDPOUT_REG0A, adc_iface);
return ret;
}
esp_err_t
es8311_codec_config_i2s (audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface)
{
int ret = ESP_OK;
ret |= es8311_set_bits_per_sample (iface->bits);
ret |= es8311_config_fmt (iface->fmt);
return ret;
}
esp_err_t
es8311_codec_ctrl_state (audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state)
{
esp_err_t ret = ESP_OK;
es_module_t es_mode = ES_MODULE_MIN;
switch (mode)
{
case AUDIO_HAL_CODEC_MODE_ENCODE:
es_mode = ES_MODULE_ADC;
break;
case AUDIO_HAL_CODEC_MODE_LINE_IN:
es_mode = ES_MODULE_LINE;
break;
case AUDIO_HAL_CODEC_MODE_DECODE:
es_mode = ES_MODULE_DAC;
break;
case AUDIO_HAL_CODEC_MODE_BOTH:
es_mode = ES_MODULE_ADC_DAC;
break;
default:
es_mode = ES_MODULE_DAC;
ESP_LOGW (TAG, "Codec mode not support, default is decode mode");
break;
}
if (ctrl_state == AUDIO_HAL_CTRL_START)
{
ret |= es8311_start (es_mode);
}
else
{
ESP_LOGW (TAG, "The codec is about to stop");
ret |= es8311_stop (es_mode);
}
return ret;
}
esp_err_t
es8311_start (es_module_t mode)
{
esp_err_t ret = ESP_OK;
uint8_t adc_iface = 0, dac_iface = 0;
dac_iface = es8311_read_reg (ES8311_SDPIN_REG09) & 0xBF;
adc_iface = es8311_read_reg (ES8311_SDPOUT_REG0A) & 0xBF;
adc_iface |= BIT (6);
dac_iface |= BIT (6);
if (mode == ES_MODULE_LINE)
{
ESP_LOGE (TAG, "The codec es8311 doesn't support ES_MODULE_LINE mode");
return ESP_FAIL;
}
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC)
{
adc_iface &= ~(BIT (6));
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC)
{
dac_iface &= ~(BIT (6));
}
ret |= es8311_write_reg (ES8311_SDPIN_REG09, dac_iface);
ret |= es8311_write_reg (ES8311_SDPOUT_REG0A, adc_iface);
ret |= es8311_write_reg (ES8311_ADC_REG17, 0xBF);
ret |= es8311_write_reg (ES8311_SYSTEM_REG0E, 0x02);
ret |= es8311_write_reg (ES8311_SYSTEM_REG12, 0x00);
ret |= es8311_write_reg (ES8311_SYSTEM_REG14, 0x1A);
/*
* pdm dmic enable or disable
*/
int regv = 0;
if (IS_DMIC)
{
regv = es8311_read_reg (ES8311_SYSTEM_REG14);
regv |= 0x40;
ret |= es8311_write_reg (ES8311_SYSTEM_REG14, regv);
}
else
{
regv = es8311_read_reg (ES8311_SYSTEM_REG14);
regv &= ~(0x40);
ret |= es8311_write_reg (ES8311_SYSTEM_REG14, regv);
}
ret |= es8311_write_reg (ES8311_SYSTEM_REG0D, 0x01);
ret |= es8311_write_reg (ES8311_ADC_REG15, 0x40);
ret |= es8311_write_reg (ES8311_DAC_REG37, 0x48);
ret |= es8311_write_reg (ES8311_GP_REG45, 0x00);
return ret;
}
esp_err_t
es8311_stop (es_module_t mode)
{
esp_err_t ret = ESP_OK;
es8311_suspend ();
return ret;
}
esp_err_t
es8311_codec_set_voice_volume (int volume)
{
esp_err_t res = ESP_OK;
if (volume < 0)
{
volume = 0;
}
else if (volume > 100)
{
volume = 100;
}
int vol = (volume)*2550 / 1000;
ESP_LOGD (TAG, "SET: volume:%d", vol);
es8311_write_reg (ES8311_DAC_REG32, vol);
return res;
}
esp_err_t
es8311_codec_get_voice_volume (int *volume)
{
esp_err_t res = ESP_OK;
int regv = 0;
regv = es8311_read_reg (ES8311_DAC_REG32);
if (regv == ESP_FAIL)
{
*volume = 0;
res = ESP_FAIL;
}
else
{
*volume = regv * 100 / 256;
}
ESP_LOGD (TAG, "GET: res:%d, volume:%d", regv, *volume);
return res;
}
esp_err_t
es8311_set_voice_mute (bool enable)
{
ESP_LOGD (TAG, "Es8311SetVoiceMute volume:%d", enable);
es8311_mute (enable);
return ESP_OK;
}
esp_err_t
es8311_get_voice_mute (int *mute)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
res = es8311_read_reg (ES8311_DAC_REG31);
if (res != ESP_FAIL)
{
reg = (res & 0x20) >> 5;
}
*mute = reg;
return res;
}
esp_err_t
es8311_set_mic_gain (es8311_mic_gain_t gain_db)
{
esp_err_t res = ESP_OK;
res = es8311_write_reg (ES8311_ADC_REG16, gain_db); // MIC gain scale
return res;
}
void
es8311_read_all ()
{
for (int i = 0; i < 0x4A; i++)
{
uint8_t reg = es8311_read_reg (i);
ets_printf ("REG:%02x, %02x\n", reg, i);
}
}

View File

@@ -0,0 +1,282 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _ES8311_H
#define _ES8311_H
#include "audio_hal.h"
#include "esp_types.h"
#include "esxxx_common.h"
#ifdef __cplusplus
extern "C"
{
#endif
/*
* ES8311_REGISTER NAME_REG_REGISTER ADDRESS
*/
#define ES8311_RESET_REG00 0x00 /*reset digital,csm,clock manager etc.*/
/*
* Clock Scheme Register definition
*/
#define ES8311_CLK_MANAGER_REG01 \
0x01 /* select clk src for mclk, enable clock for codec */
#define ES8311_CLK_MANAGER_REG02 0x02 /* clk divider and clk multiplier */
#define ES8311_CLK_MANAGER_REG03 0x03 /* adc fsmode and osr */
#define ES8311_CLK_MANAGER_REG04 0x04 /* dac osr */
#define ES8311_CLK_MANAGER_REG05 0x05 /* clk divier for adc and dac */
#define ES8311_CLK_MANAGER_REG06 0x06 /* bclk inverter and divider */
#define ES8311_CLK_MANAGER_REG07 0x07 /* tri-state, lrck divider */
#define ES8311_CLK_MANAGER_REG08 0x08 /* lrck divider */
/*
* SDP
*/
#define ES8311_SDPIN_REG09 0x09 /* dac serial digital port */
#define ES8311_SDPOUT_REG0A 0x0A /* adc serial digital port */
/*
* SYSTEM
*/
#define ES8311_SYSTEM_REG0B 0x0B /* system */
#define ES8311_SYSTEM_REG0C 0x0C /* system */
#define ES8311_SYSTEM_REG0D 0x0D /* system, power up/down */
#define ES8311_SYSTEM_REG0E 0x0E /* system, power up/down */
#define ES8311_SYSTEM_REG0F 0x0F /* system, low power */
#define ES8311_SYSTEM_REG10 0x10 /* system */
#define ES8311_SYSTEM_REG11 0x11 /* system */
#define ES8311_SYSTEM_REG12 0x12 /* system, Enable DAC */
#define ES8311_SYSTEM_REG13 0x13 /* system */
#define ES8311_SYSTEM_REG14 \
0x14 /* system, select DMIC, select analog pga gain */
/*
* ADC
*/
#define ES8311_ADC_REG15 0x15 /* ADC, adc ramp rate, dmic sense */
#define ES8311_ADC_REG16 0x16 /* ADC */
#define ES8311_ADC_REG17 0x17 /* ADC, volume */
#define ES8311_ADC_REG18 0x18 /* ADC, alc enable and winsize */
#define ES8311_ADC_REG19 0x19 /* ADC, alc maxlevel */
#define ES8311_ADC_REG1A 0x1A /* ADC, alc automute */
#define ES8311_ADC_REG1B 0x1B /* ADC, alc automute, adc hpf s1 */
#define ES8311_ADC_REG1C 0x1C /* ADC, equalizer, hpf s2 */
/*
* DAC
*/
#define ES8311_DAC_REG31 0x31 /* DAC, mute */
#define ES8311_DAC_REG32 0x32 /* DAC, volume */
#define ES8311_DAC_REG33 0x33 /* DAC, offset */
#define ES8311_DAC_REG34 0x34 /* DAC, drc enable, drc winsize */
#define ES8311_DAC_REG35 0x35 /* DAC, drc maxlevel, minilevel */
#define ES8311_DAC_REG37 0x37 /* DAC, ramprate */
/*
*GPIO
*/
#define ES8311_GPIO_REG44 0x44 /* GPIO, dac2adc for test */
#define ES8311_GP_REG45 0x45 /* GP CONTROL */
/*
* CHIP
*/
#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */
#define ES8311_CHD2_REGFE 0xFE /* CHIP ID2 */
#define ES8311_CHVER_REGFF 0xFF /* VERSION */
#define ES8311_CHD1_REGFD 0xFD /* CHIP ID1 */
#define ES8311_MAX_REGISTER 0xFF
typedef enum
{
ES8311_MIC_GAIN_MIN = -1,
ES8311_MIC_GAIN_0DB,
ES8311_MIC_GAIN_6DB,
ES8311_MIC_GAIN_12DB,
ES8311_MIC_GAIN_18DB,
ES8311_MIC_GAIN_24DB,
ES8311_MIC_GAIN_30DB,
ES8311_MIC_GAIN_36DB,
ES8311_MIC_GAIN_42DB,
ES8311_MIC_GAIN_MAX
} es8311_mic_gain_t;
/*
* @brief Initialize ES8311 codec chip
*
* @param codec_cfg configuration of ES8311
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8311_codec_init (audio_hal_codec_config_t *codec_cfg);
/**
* @brief Deinitialize ES8311 codec chip
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8311_codec_deinit (void);
/**
* @brief Control ES8311 codec chip
*
* @param mode codec mode
* @param ctrl_state start or stop decode or encode progress
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8311_codec_ctrl_state (audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state);
/**
* @brief Configure ES8311 codec mode and I2S interface
*
* @param mode codec mode
* @param iface I2S config
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8311_codec_config_i2s (audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface);
/**
* @brief Configure ES8311 DAC mute or not. Basically you can use this
* function to mute the output or unmute
*
* @param enable enable(1) or disable(0)
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8311_set_voice_mute (bool enable);
/**
* @brief Set voice volume
*
* @param volume: voice volume (0~100)
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8311_codec_set_voice_volume (int volume);
/**
* @brief Get voice volume
*
* @param[out] *volume: voice volume (0~100)
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8311_codec_get_voice_volume (int *volume);
/**
* @brief Configure ES8311 I2S format
*
* @param mod: set ADC or DAC or both
* @param cfg: ES8388 I2S format
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8311_config_fmt (es_i2s_fmt_t fmt);
/**
* @brief Configure ES8311 data sample bits
*
* @param mode: set ADC or DAC or both
* @param bit_per_sample: bit number of per sample
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8311_set_bits_per_sample (audio_hal_iface_bits_t bits);
/**
* @brief Start ES8311 codec chip
*
* @param mode: set ADC or DAC or both
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8311_start (es_module_t mode);
/**
* @brief Stop ES8311 codec chip
*
* @param mode: set ADC or DAC or both
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8311_stop (es_module_t mode);
/**
* @brief Get ES8311 DAC mute status
*
* @return
* - ESP_FAIL
* - ESP_OK
*/
esp_err_t es8311_get_voice_mute (int *mute);
/**
* @brief Set ES8311 mic gain
*
* @param gain db of mic gain
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8311_set_mic_gain (es8311_mic_gain_t gain_db);
/**
* @brief Print all ES8311 registers
*
* @return
* - void
*/
void es8311_read_all ();
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,904 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "es8374.h"
#include "board_pins_config.h"
#include "esp_log.h"
#include "esp_system.h"
#include "i2c_bus.h"
#include <string.h>
#define ES8374_TAG "ES8374_DRIVER"
#define ES_ASSERT(a, format, b, ...) \
if ((a) != 0) \
{ \
ESP_LOGE (ES8374_TAG, format, ##__VA_ARGS__); \
return b; \
}
#define LOG_8374(fmt, ...) ESP_LOGW (ES8374_TAG, fmt, ##__VA_ARGS__)
static int codec_init_flag = 0;
static i2c_bus_handle_t i2c_handle;
audio_hal_func_t AUDIO_CODEC_ES8374_DEFAULT_HANDLE = {
.audio_codec_initialize = es8374_codec_init,
.audio_codec_deinitialize = es8374_codec_deinit,
.audio_codec_ctrl = es8374_codec_ctrl_state,
.audio_codec_config_iface = es8374_codec_config_i2s,
.audio_codec_set_mute = es8374_set_voice_mute,
.audio_codec_set_volume = es8374_codec_set_voice_volume,
.audio_codec_get_volume = es8374_codec_get_voice_volume,
.audio_hal_lock = NULL,
.handle = NULL,
};
static bool
es8374_codec_initialized ()
{
return codec_init_flag;
}
static esp_err_t
es_write_reg (uint8_t slave_addr, uint8_t reg_add, uint8_t data)
{
return i2c_bus_write_bytes (i2c_handle, slave_addr, &reg_add,
sizeof (reg_add), &data, sizeof (data));
}
static esp_err_t
es_read_reg (uint8_t slave_addr, uint8_t reg_add, uint8_t *p_data)
{
return i2c_bus_read_bytes (i2c_handle, slave_addr, &reg_add,
sizeof (reg_add), p_data, 1);
}
static int
i2c_init ()
{
int res;
i2c_config_t es_i2c_cfg = { .mode = I2C_MODE_MASTER,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000 };
res = get_i2c_pins (I2C_NUM_0, &es_i2c_cfg);
ES_ASSERT (res, "getting i2c pins error", -1);
i2c_handle = i2c_bus_create (I2C_NUM_0, &es_i2c_cfg);
return res;
}
esp_err_t
es8374_write_reg (uint8_t reg_add, uint8_t data)
{
return es_write_reg (ES8374_ADDR, reg_add, data);
}
int
es8374_read_reg (uint8_t reg_add, uint8_t *regv)
{
uint8_t regdata = 0xFF;
uint8_t res = 0;
if (es_read_reg (ES8374_ADDR, reg_add, &regdata) == 0)
{
*regv = regdata;
return res;
}
else
{
LOG_8374 ("Read Audio Codec Register Failed!");
res = -1;
return res;
}
}
void
es8374_read_all ()
{
for (int i = 0; i < 50; i++)
{
uint8_t reg = 0;
es8374_read_reg (i, &reg);
ESP_LOGI (ES8374_TAG, "%x: %x", i, reg);
}
}
esp_err_t
es8374_set_voice_mute (bool enable)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
res |= es8374_read_reg (0x36, &reg);
if (res == 0)
{
reg = reg & 0xdf;
res |= es8374_write_reg (0x36, reg | (((int)enable) << 5));
}
return res;
}
esp_err_t
es8374_get_voice_mute (void)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
res |= es8374_read_reg (0x36, &reg);
if (res == ESP_OK)
{
reg = reg & 0x40;
}
return res == ESP_OK ? reg : res;
}
esp_err_t
es8374_set_bits_per_sample (es_module_t mode, es_bits_length_t bit_per_sample)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
int bits = (int)bit_per_sample & 0x0f;
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC)
{
res |= es8374_read_reg (0x10, &reg);
if (res == 0)
{
reg = reg & 0xe3;
res |= es8374_write_reg (0x10, reg | (bits << 2));
}
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC)
{
res |= es8374_read_reg (0x11, &reg);
if (res == 0)
{
reg = reg & 0xe3;
res |= es8374_write_reg (0x11, reg | (bits << 2));
}
}
return res;
}
esp_err_t
es8374_config_fmt (es_module_t mode, es_i2s_fmt_t fmt)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
int fmt_tmp, fmt_i2s;
fmt_tmp = ((fmt & 0xf0) >> 4);
fmt_i2s = fmt & 0x0f;
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC)
{
res |= es8374_read_reg (0x10, &reg);
if (res == 0)
{
reg = reg & 0xfc;
res |= es8374_write_reg (0x10, reg | fmt_i2s);
res |= es8374_set_bits_per_sample (mode, fmt_tmp);
}
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC)
{
res |= es8374_read_reg (0x11, &reg);
if (res == 0)
{
reg = reg & 0xfc;
res |= es8374_write_reg (0x11, reg | (fmt_i2s));
res |= es8374_set_bits_per_sample (mode, fmt_tmp);
}
}
return res;
}
esp_err_t
es8374_start (es_module_t mode)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
if (mode == ES_MODULE_LINE)
{
res |= es8374_read_reg (0x1a, &reg); // set monomixer
reg |= 0x60;
reg |= 0x20;
reg &= 0xf7;
res |= es8374_write_reg (0x1a, reg);
res |= es8374_read_reg (0x1c, &reg); // set spk mixer
reg |= 0x40;
res |= es8374_write_reg (0x1c, reg);
res |= es8374_write_reg (0x1D, 0x02); // spk set
res |= es8374_write_reg (0x1F, 0x00); // spk set
res |= es8374_write_reg (0x1E, 0xA0); // spk on
}
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC
|| mode == ES_MODULE_LINE)
{
res |= es8374_read_reg (0x21, &reg); // power up adc and input
reg &= 0x3f;
res |= es8374_write_reg (0x21, reg);
res |= es8374_read_reg (0x10, &reg); // power up adc and input
reg &= 0x3f;
res |= es8374_write_reg (0x10, reg);
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC
|| mode == ES_MODULE_LINE)
{
res |= es8374_read_reg (0x1a, &reg); // disable lout
reg |= 0x08;
res |= es8374_write_reg (0x1a, reg);
reg &= 0xdf;
res |= es8374_write_reg (0x1a, reg);
res |= es8374_write_reg (0x1D, 0x12); // mute speaker
res |= es8374_write_reg (0x1E, 0x20); // disable class d
res |= es8374_read_reg (0x15, &reg); // power up dac
reg &= 0xdf;
res |= es8374_write_reg (0x15, reg);
res |= es8374_read_reg (0x1a, &reg); // disable lout
reg |= 0x20;
res |= es8374_write_reg (0x1a, reg);
reg &= 0xf7;
res |= es8374_write_reg (0x1a, reg);
res |= es8374_write_reg (0x1D, 0x02); // mute speaker
res |= es8374_write_reg (0x1E, 0xa0); // disable class d
res |= es8374_set_voice_mute (false);
}
return res;
}
esp_err_t
es8374_stop (es_module_t mode)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
if (mode == ES_MODULE_LINE)
{
res |= es8374_read_reg (0x1a, &reg); // disable lout
reg |= 0x08;
res |= es8374_write_reg (0x1a, reg);
reg &= 0x9f;
res |= es8374_write_reg (0x1a, reg);
res |= es8374_write_reg (0x1D, 0x12); // mute speaker
res |= es8374_write_reg (0x1E, 0x20); // disable class d
res |= es8374_read_reg (0x1c, &reg); // disable spkmixer
reg &= 0xbf;
res |= es8374_write_reg (0x1c, reg);
res |= es8374_write_reg (0x1F, 0x00); // spk set
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC)
{
res |= es8374_set_voice_mute (true);
res |= es8374_read_reg (0x1a, &reg); // disable lout
reg |= 0x08;
res |= es8374_write_reg (0x1a, reg);
reg &= 0xdf;
res |= es8374_write_reg (0x1a, reg);
res |= es8374_write_reg (0x1D, 0x12); // mute speaker
res |= es8374_write_reg (0x1E, 0x20); // disable class d
res |= es8374_read_reg (0x15, &reg); // power up dac
reg |= 0x20;
res |= es8374_write_reg (0x15, reg);
}
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC)
{
res |= es8374_read_reg (0x10, &reg); // power up adc and input
reg |= 0xc0;
res |= es8374_write_reg (0x10, reg);
res |= es8374_read_reg (0x21, &reg); // power up adc and input
reg |= 0xc0;
res |= es8374_write_reg (0x21, reg);
}
return res;
}
esp_err_t
es8374_i2s_config_clock (es_i2s_clock_t cfg)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
res |= es8374_read_reg (0x0f, &reg); // power up adc and input
reg &= 0xe0;
int divratio = 0;
switch (cfg.sclk_div)
{
case MCLK_DIV_1:
divratio = 1;
break;
case MCLK_DIV_2: // = 2,
divratio = 2;
break;
case MCLK_DIV_3: // = 3,
divratio = 3;
break;
case MCLK_DIV_4: // = 4,
divratio = 4;
break;
case MCLK_DIV_5: // = 20,
divratio = 5;
break;
case MCLK_DIV_6: // = 5,
divratio = 6;
break;
case MCLK_DIV_7: // = 29,
divratio = 7;
break;
case MCLK_DIV_8: // = 6,
divratio = 8;
break;
case MCLK_DIV_9: // = 7,
divratio = 9;
break;
case MCLK_DIV_10: // = 21,
divratio = 10;
break;
case MCLK_DIV_11: // = 8,
divratio = 11;
break;
case MCLK_DIV_12: // = 9,
divratio = 12;
break;
case MCLK_DIV_13: // = 30,
divratio = 13;
break;
case MCLK_DIV_14: // = 31
divratio = 14;
break;
case MCLK_DIV_15: // = 22,
divratio = 15;
break;
case MCLK_DIV_16: // = 10,
divratio = 16;
break;
case MCLK_DIV_17: // = 23,
divratio = 17;
break;
case MCLK_DIV_18: // = 11,
divratio = 18;
break;
case MCLK_DIV_20: // = 24,
divratio = 19;
break;
case MCLK_DIV_22: // = 12,
divratio = 20;
break;
case MCLK_DIV_24: // = 13,
divratio = 21;
break;
case MCLK_DIV_25: // = 25,
divratio = 22;
break;
case MCLK_DIV_30: // = 26,
divratio = 23;
break;
case MCLK_DIV_32: // = 27,
divratio = 24;
break;
case MCLK_DIV_33: // = 14,
divratio = 25;
break;
case MCLK_DIV_34: // = 28,
divratio = 26;
break;
case MCLK_DIV_36: // = 15,
divratio = 27;
break;
case MCLK_DIV_44: // = 16,
divratio = 28;
break;
case MCLK_DIV_48: // = 17,
divratio = 29;
break;
case MCLK_DIV_66: // = 18,
divratio = 30;
break;
case MCLK_DIV_72: // = 19,
divratio = 31;
break;
default:
break;
}
reg |= divratio;
res |= es8374_write_reg (0x0f, reg);
int dacratio_l = 0;
int dacratio_h = 0;
switch (cfg.lclk_div)
{
case LCLK_DIV_128:
dacratio_l = 128 % 256;
dacratio_h = 128 / 256;
break;
case LCLK_DIV_192:
dacratio_l = 192 % 256;
dacratio_h = 192 / 256;
break;
case LCLK_DIV_256:
dacratio_l = 256 % 256;
dacratio_h = 256 / 256;
break;
case LCLK_DIV_384:
dacratio_l = 384 % 256;
dacratio_h = 384 / 256;
break;
case LCLK_DIV_512:
dacratio_l = 512 % 256;
dacratio_h = 512 / 256;
break;
case LCLK_DIV_576:
dacratio_l = 576 % 256;
dacratio_h = 576 / 256;
break;
case LCLK_DIV_768:
dacratio_l = 768 % 256;
dacratio_h = 768 / 256;
break;
case LCLK_DIV_1024:
dacratio_l = 1024 % 256;
dacratio_h = 1024 / 256;
break;
case LCLK_DIV_1152:
dacratio_l = 1152 % 256;
dacratio_h = 1152 / 256;
break;
case LCLK_DIV_1408:
dacratio_l = 1408 % 256;
dacratio_h = 1408 / 256;
break;
case LCLK_DIV_1536:
dacratio_l = 1536 % 256;
dacratio_h = 1536 / 256;
break;
case LCLK_DIV_2112:
dacratio_l = 2112 % 256;
dacratio_h = 2112 / 256;
break;
case LCLK_DIV_2304:
dacratio_l = 2304 % 256;
dacratio_h = 2304 / 256;
break;
case LCLK_DIV_125:
dacratio_l = 125 % 256;
dacratio_h = 125 / 256;
break;
case LCLK_DIV_136:
dacratio_l = 136 % 256;
dacratio_h = 136 / 256;
break;
case LCLK_DIV_250:
dacratio_l = 250 % 256;
dacratio_h = 250 / 256;
break;
case LCLK_DIV_272:
dacratio_l = 272 % 256;
dacratio_h = 272 / 256;
break;
case LCLK_DIV_375:
dacratio_l = 375 % 256;
dacratio_h = 375 / 256;
break;
case LCLK_DIV_500:
dacratio_l = 500 % 256;
dacratio_h = 500 / 256;
break;
case LCLK_DIV_544:
dacratio_l = 544 % 256;
dacratio_h = 544 / 256;
break;
case LCLK_DIV_750:
dacratio_l = 750 % 256;
dacratio_h = 750 / 256;
break;
case LCLK_DIV_1000:
dacratio_l = 1000 % 256;
dacratio_h = 1000 / 256;
break;
case LCLK_DIV_1088:
dacratio_l = 1088 % 256;
dacratio_h = 1088 / 256;
break;
case LCLK_DIV_1496:
dacratio_l = 1496 % 256;
dacratio_h = 1496 / 256;
break;
case LCLK_DIV_1500:
dacratio_l = 1500 % 256;
dacratio_h = 1500 / 256;
break;
default:
break;
}
res |= es8374_write_reg (0x06,
dacratio_h); // ADCFsMode,singel SPEED,RATIO=256
res |= es8374_write_reg (0x07,
dacratio_l); // ADCFsMode,singel SPEED,RATIO=256
return res;
}
esp_err_t
es8374_config_dac_output (es_dac_output_t output)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
reg = 0x1d;
res = es8374_write_reg (reg, 0x02);
res |= es8374_read_reg (0x1c, &reg); // set spk mixer
reg |= 0x80;
res |= es8374_write_reg (0x1c, reg);
res |= es8374_write_reg (0x1D, 0x02); // spk set
res |= es8374_write_reg (0x1F, 0x00); // spk set
res |= es8374_write_reg (0x1E, 0xA0); // spk on
return res;
}
esp_err_t
es8374_config_adc_input (es_adc_input_t input)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
res |= es8374_read_reg (0x21, &reg);
if (res == 0)
{
reg = (reg & 0xcf) | 0x14;
res |= es8374_write_reg (0x21, reg);
}
return res;
}
esp_err_t
es8374_set_mic_gain (es_mic_gain_t gain)
{
esp_err_t res = ESP_OK;
if (gain > MIC_GAIN_MIN && gain < MIC_GAIN_24DB)
{
int gain_n = 0;
gain_n = (int)gain / 3;
res = es8374_write_reg (0x22, gain_n | (gain_n << 4)); // MIC PGA
}
else
{
res = -1;
LOG_8374 ("invalid microphone gain!");
}
return res;
}
esp_err_t
es8374_codec_set_voice_volume (int volume)
{
esp_err_t res = ESP_OK;
if (volume < 0)
{
volume = 192;
}
else if (volume > 96)
{
volume = 0;
}
else
{
volume = 192 - volume * 2;
}
res = es8374_write_reg (0x38, volume);
return res;
}
esp_err_t
es8374_codec_get_voice_volume (int *volume)
{
esp_err_t res = 0;
uint8_t reg = 0;
res = es8374_read_reg (0x38, &reg);
if (res == ESP_FAIL)
{
*volume = 0;
}
else
{
*volume = (192 - reg) / 2;
if (*volume > 96)
{
*volume = 100;
}
}
return res;
}
static int
es8374_set_adc_dac_volume (int mode, int volume, int dot)
{
int res = 0;
if (volume < -96 || volume > 0)
{
LOG_8374 ("Warning: volume < -96! or > 0!");
if (volume < -96)
{
volume = -96;
}
else
{
volume = 0;
}
}
dot = (dot >= 5 ? 1 : 0);
volume = (-volume << 1) + dot;
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC)
{
res |= es8374_write_reg (0x25, volume);
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC)
{
res |= es8374_write_reg (0x38, volume);
}
return res;
}
static int
es8374_set_d2se_pga (es_d2se_pga_t gain)
{
int res = 0;
uint8_t reg = 0;
if (gain > D2SE_PGA_GAIN_MIN && gain < D2SE_PGA_GAIN_MAX)
{
res = es8374_read_reg (0x21, &reg);
reg &= 0xfb;
reg |= gain << 2;
res = es8374_write_reg (0x21, reg); // MIC PGA
}
else
{
res = 0xff;
LOG_8374 ("invalid microphone gain!");
}
return res;
}
static int
es8374_init_reg (audio_hal_codec_mode_t ms_mode, es_i2s_fmt_t fmt,
es_i2s_clock_t cfg, es_dac_output_t out_channel,
es_adc_input_t in_channel)
{
int res = 0;
uint8_t reg;
res |= es8374_write_reg (0x00, 0x3F); // IC Rst start
res |= es8374_write_reg (0x00, 0x03); // IC Rst stop
res |= es8374_write_reg (0x01, 0x7F); // IC clk on
res |= es8374_read_reg (0x0F, &reg);
reg &= 0x7f;
reg |= (ms_mode << 7);
res |= es8374_write_reg (0x0f, reg); // CODEC IN I2S SLAVE MODE
res |= es8374_write_reg (0x6F, 0xA0); // pll set:mode enable
res |= es8374_write_reg (0x72, 0x41); // pll set:mode set
res |= es8374_write_reg (0x09, 0x01); // pll set:reset on ,set start
res |= es8374_write_reg (0x0C, 0x22); // pll set:k
res |= es8374_write_reg (0x0D, 0x2E); // pll set:k
res |= es8374_write_reg (0x0E, 0xC6); // pll set:k
res |= es8374_write_reg (0x0A, 0x3A); // pll set:
res |= es8374_write_reg (0x0B, 0x07); // pll set:n
res |= es8374_write_reg (0x09, 0x41); // pll set:reset off ,set stop
res |= es8374_i2s_config_clock (cfg);
res |= es8374_write_reg (0x24, 0x08); // adc set
res |= es8374_write_reg (0x36, 0x00); // dac set
res |= es8374_write_reg (0x12, 0x30); // timming set
res |= es8374_write_reg (0x13, 0x20); // timming set
res |= es8374_config_fmt (ES_MODULE_ADC, fmt);
res |= es8374_config_fmt (ES_MODULE_DAC, fmt);
res |= es8374_write_reg (0x21, 0x50); // adc set: SEL LIN1 CH+PGAGAIN=0DB
res |= es8374_write_reg (0x22, 0xFF); // adc set: PGA GAIN=0DB
res |= es8374_write_reg (0x21, 0x14); // adc set: SEL LIN1 CH+PGAGAIN=18DB
res |= es8374_write_reg (0x22, 0x55); // pga = +15db
res |= es8374_write_reg (0x08,
0x21); // set class d divider = 33, to avoid the
// high frequency tone on laudspeaker
res |= es8374_write_reg (0x00, 0x80); // IC START
res |= es8374_set_adc_dac_volume (ES_MODULE_ADC, 0, 0); // 0db
res |= es8374_set_adc_dac_volume (ES_MODULE_DAC, 0, 0); // 0db
res |= es8374_write_reg (0x14, 0x8A); // IC START
res |= es8374_write_reg (0x15, 0x40); // IC START
res |= es8374_write_reg (0x1A, 0xA0); // monoout set
res |= es8374_write_reg (0x1B, 0x19); // monoout set
res |= es8374_write_reg (0x1C, 0x90); // spk set
res |= es8374_write_reg (0x1D, 0x01); // spk set
res |= es8374_write_reg (0x1F, 0x00); // spk set
res |= es8374_write_reg (0x1E, 0x20); // spk on
res |= es8374_write_reg (0x28, 0x00); // alc set
res |= es8374_write_reg (0x25, 0x00); // ADCVOLUME on
res |= es8374_write_reg (0x38, 0x00); // DACVOLUME on
res |= es8374_write_reg (0x37, 0x30); // dac set
res |= es8374_write_reg (
0x6D, 0x60); // SEL:GPIO1=DMIC CLK OUT+SEL:GPIO2=PLL CLK OUT
res |= es8374_write_reg (0x71, 0x05); // for automute setting
res |= es8374_write_reg (0x73, 0x70);
res |= es8374_config_dac_output (
out_channel); // 0x3c Enable DAC and Enable Lout/Rout/1/2
res |= es8374_config_adc_input (
in_channel); // 0x00 LINSEL & RINSEL, LIN1/RIN1 as ADC Input; DSSEL,use
// one DS Reg11; DSR, LINPUT1-RINPUT1
res |= es8374_codec_set_voice_volume (0);
res |= es8374_write_reg (0x37, 0x00); // dac set
return res;
}
esp_err_t
es8374_codec_init (audio_hal_codec_config_t *cfg)
{
if (es8374_codec_initialized ())
{
ESP_LOGW (ES8374_TAG, "The es8374 codec has already been initialized!");
return ESP_FAIL;
}
esp_err_t res = ESP_OK;
es_i2s_clock_t clkdiv;
clkdiv.lclk_div = LCLK_DIV_256;
clkdiv.sclk_div = MCLK_DIV_4;
i2c_init (); // ESP32 in master mode
res |= es8374_stop (cfg->codec_mode);
res |= es8374_init_reg (cfg->i2s_iface.mode,
(BIT_LENGTH_16BITS << 4) | cfg->i2s_iface.fmt,
clkdiv, cfg->dac_output, cfg->adc_input);
res |= es8374_set_mic_gain (MIC_GAIN_15DB);
res |= es8374_set_d2se_pga (D2SE_PGA_GAIN_EN);
res |= es8374_config_fmt (cfg->codec_mode, cfg->i2s_iface.fmt);
res |= es8374_codec_config_i2s (cfg->codec_mode, &(cfg->i2s_iface));
codec_init_flag = 1;
return res;
}
esp_err_t
es8374_codec_deinit (void)
{
codec_init_flag = 0;
i2c_bus_delete (i2c_handle);
return es8374_write_reg (0x00, 0x7F); // IC Reset and STOP
}
esp_err_t
es8374_codec_config_i2s (audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface)
{
esp_err_t res = ESP_OK;
int tmp = 0;
res |= es8374_config_fmt (ES_MODULE_ADC_DAC, iface->fmt);
if (iface->bits == AUDIO_HAL_BIT_LENGTH_16BITS)
{
tmp = BIT_LENGTH_16BITS;
}
else if (iface->bits == AUDIO_HAL_BIT_LENGTH_24BITS)
{
tmp = BIT_LENGTH_24BITS;
}
else
{
tmp = BIT_LENGTH_32BITS;
}
res |= es8374_set_bits_per_sample (ES_MODULE_ADC_DAC, tmp);
return res;
}
esp_err_t
es8374_codec_ctrl_state (audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state)
{
esp_err_t res = ESP_OK;
int es_mode_t = 0;
switch (mode)
{
case AUDIO_HAL_CODEC_MODE_ENCODE:
es_mode_t = ES_MODULE_ADC;
break;
case AUDIO_HAL_CODEC_MODE_LINE_IN:
es_mode_t = ES_MODULE_LINE;
break;
case AUDIO_HAL_CODEC_MODE_DECODE:
es_mode_t = ES_MODULE_DAC;
break;
case AUDIO_HAL_CODEC_MODE_BOTH:
es_mode_t = ES_MODULE_ADC_DAC;
break;
default:
es_mode_t = ES_MODULE_DAC;
ESP_LOGW (ES8374_TAG, "Codec mode not support, default is decode mode");
break;
}
if (AUDIO_HAL_CTRL_STOP == ctrl_state)
{
res = es8374_stop (es_mode_t);
}
else
{
res = es8374_start (es_mode_t);
ESP_LOGD (ES8374_TAG, "start default is decode mode:%d", es_mode_t);
}
return res;
}
void
es8374_pa_power (bool enable)
{
gpio_config_t io_conf;
memset (&io_conf, 0, sizeof (io_conf));
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = BIT64 (get_pa_enable_gpio ());
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
gpio_config (&io_conf);
if (enable)
{
gpio_set_level (get_pa_enable_gpio (), 1);
}
else
{
gpio_set_level (get_pa_enable_gpio (), 0);
}
}

View File

@@ -0,0 +1,256 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef __ES8374_H__
#define __ES8374_H__
#include "audio_hal.h"
#include "esp_types.h"
#include "esxxx_common.h"
#ifdef __cplusplus
extern "C"
{
#endif
/* ES8374 address */
#define ES8374_ADDR 0x20 // 0x22:CE=1;0x20:CE=0
/**
* @brief Initialize ES8374 codec chip
*
* @param cfg configuration of ES8374
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8374_codec_init (audio_hal_codec_config_t *cfg);
/**
* @brief Deinitialize ES8374 codec chip
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8374_codec_deinit (void);
/**
* @brief Configure ES8374 I2S format
*
* @param mode: set ADC or DAC or both
* @param fmt: ES8374 I2S format
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8374_config_fmt (es_module_t mode, es_i2s_fmt_t fmt);
/**
* @brief Configure I2S clock in MSATER mode
*
* @param cfg: set bits clock and WS clock
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8374_i2s_config_clock (es_i2s_clock_t cfg);
/**
* @brief Configure ES8374 data sample bits
*
* @param mode: set ADC or DAC or both
* @param bit_per_sample: bit number of per sample
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8374_set_bits_per_sample (es_module_t mode,
es_bits_length_t bit_per_sample);
/**
* @brief Start ES8374 codec chip
*
* @param mode: set ADC or DAC or both
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8374_start (es_module_t mode);
/**
* @brief Stop ES8374 codec chip
*
* @param mode: set ADC or DAC or both
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8374_stop (es_module_t mode);
/**
* @brief Set voice volume
*
* @param volume: voice volume (0~100)
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8374_codec_set_voice_volume (int volume);
/**
* @brief Get voice volume
*
* @param[out] *volume: voice volume (0~100)
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8374_codec_get_voice_volume (int *volume);
/**
* @brief Mute or unmute ES8374 DAC. Basically you can use this function to
* mute or unmute the output
*
* @param enable mute(1) or unmute(0)
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8374_set_voice_mute (bool enable);
/**
* @brief Get ES8374 DAC mute status
*
* @return
* - ESP_FAIL
* - ESP_OK
*/
esp_err_t es8374_get_voice_mute (void);
/**
* @brief Set ES8374 mic gain
*
* @param gain db of mic gain
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8374_set_mic_gain (es_mic_gain_t gain);
/**
* @brief Set ES8374 ADC input mode
*
* @param input adc input mode
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8374_config_adc_input (es_adc_input_t input);
/**
* @brief Set ES8374 DAC output mode
*
* @param output dac output mode
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8374_config_dac_output (es_dac_output_t output);
/**
* @brief Write ES8374 register
*
* @param reg_add address of register
* @param data data of register
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8374_write_reg (uint8_t reg_add, uint8_t data);
/**
* @brief Print all ES8374 registers
*
* @return
* - void
*/
void es8374_read_all ();
/**
* @brief Configure ES8374 codec mode and I2S interface
*
* @param mode codec mode
* @param iface I2S config
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8374_codec_config_i2s (audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface);
/**
* @brief Control ES8374 codec chip
*
* @param mode codec mode
* @param ctrl_state start or stop decode or encode progress
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8374_codec_ctrl_state (audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state);
/**
* @brief Set ES8374 PA power
*
* @param enable true for enable PA power, false for disable PA power
*
* @return
* - void
*/
void es8374_pa_power (bool enable);
#ifdef __cplusplus
}
#endif
#endif //__ES8374_H__

View File

@@ -0,0 +1,679 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "es8388.h"
#include "board_pins_config.h"
#include "esp_log.h"
#include "i2c_bus.h"
#include <string.h>
#ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
#include "headphone_detect.h"
#endif
static const char *ES_TAG = "ES8388_DRIVER";
static i2c_bus_handle_t i2c_handle;
#define ES_ASSERT(a, format, b, ...) \
if ((a) != 0) \
{ \
ESP_LOGE (ES_TAG, format, ##__VA_ARGS__); \
return b; \
}
audio_hal_func_t AUDIO_CODEC_ES8388_DEFAULT_HANDLE = {
.audio_codec_initialize = es8388_init,
.audio_codec_deinitialize = es8388_deinit,
.audio_codec_ctrl = es8388_ctrl_state,
.audio_codec_config_iface = es8388_config_i2s,
.audio_codec_set_mute = es8388_set_voice_mute,
.audio_codec_set_volume = es8388_set_voice_volume,
.audio_codec_get_volume = es8388_get_voice_volume,
.audio_hal_lock = NULL,
.handle = NULL,
};
static esp_err_t
es_write_reg (uint8_t slave_addr, uint8_t reg_add, uint8_t data)
{
return i2c_bus_write_bytes (i2c_handle, slave_addr, &reg_add,
sizeof (reg_add), &data, sizeof (data));
}
static esp_err_t
es_read_reg (uint8_t reg_add, uint8_t *p_data)
{
return i2c_bus_read_bytes (i2c_handle, ES8388_ADDR, &reg_add,
sizeof (reg_add), p_data, 1);
}
static int
i2c_init ()
{
int res;
i2c_config_t es_i2c_cfg = { .mode = I2C_MODE_MASTER,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000 };
res = get_i2c_pins (I2C_NUM_0, &es_i2c_cfg);
ES_ASSERT (res, "getting i2c pins error", -1);
i2c_handle = i2c_bus_create (I2C_NUM_0, &es_i2c_cfg);
return res;
}
void
es8388_read_all ()
{
for (int i = 0; i < 50; i++)
{
uint8_t reg = 0;
es_read_reg (i, &reg);
ets_printf ("%x: %x\n", i, reg);
}
}
esp_err_t
es8388_write_reg (uint8_t reg_add, uint8_t data)
{
return es_write_reg (ES8388_ADDR, reg_add, data);
}
/**
* @brief Configure ES8388 ADC and DAC volume. Basicly you can consider this as
* ADC and DAC gain
*
* @param mode: set ADC or DAC or all
* @param volume: -96 ~ 0 for example
* Es8388SetAdcDacVolume(ES_MODULE_ADC, 30, 6); means set ADC volume -30.5db
* @param dot: whether include 0.5. for example
* Es8388SetAdcDacVolume(ES_MODULE_ADC, 30, 4); means set ADC volume -30db
*
* @return
* - (-1) Parameter error
* - (0) Success
*/
static int
es8388_set_adc_dac_volume (int mode, int volume, int dot)
{
int res = 0;
if (volume < -96 || volume > 0)
{
ESP_LOGW (ES_TAG, "Warning: volume < -96! or > 0!\n");
if (volume < -96)
volume = -96;
else
volume = 0;
}
dot = (dot >= 5 ? 1 : 0);
volume = (-volume << 1) + dot;
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC)
{
res |= es_write_reg (ES8388_ADDR, ES8388_ADCCONTROL8, volume);
res |= es_write_reg (ES8388_ADDR, ES8388_ADCCONTROL9,
volume); // ADC Right Volume=0db
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC)
{
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL5, volume);
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL4, volume);
}
return res;
}
/**
* @brief Power Management
*
* @param mod: if ES_POWER_CHIP, the whole chip including ADC and DAC is
* enabled
* @param enable: false to disable true to enable
*
* @return
* - (-1) Error
* - (0) Success
*/
esp_err_t
es8388_start (es_module_t mode)
{
esp_err_t res = ESP_OK;
uint8_t prev_data = 0, data = 0;
es_read_reg (ES8388_DACCONTROL21, &prev_data);
if (mode == ES_MODULE_LINE)
{
res |= es_write_reg (
ES8388_ADDR, ES8388_DACCONTROL16,
0x09); // 0x00 audio on LIN1&RIN1, 0x09 LIN2&RIN2 by pass enable
res |= es_write_reg (
ES8388_ADDR, ES8388_DACCONTROL17,
0x50); // left DAC to left mixer enable and LIN signal to left
// mixer enable 0db : bupass enable
res |= es_write_reg (
ES8388_ADDR, ES8388_DACCONTROL20,
0x50); // right DAC to right mixer enable and LIN signal to right
// mixer enable 0db : bupass enable
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL21,
0xC0); // enable adc
}
else
{
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL21,
0x80); // enable dac
}
es_read_reg (ES8388_DACCONTROL21, &data);
if (prev_data != data)
{
res |= es_write_reg (ES8388_ADDR, ES8388_CHIPPOWER,
0xF0); // start state machine
// res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL1, 0x16);
// res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL2, 0x50);
res |= es_write_reg (ES8388_ADDR, ES8388_CHIPPOWER,
0x00); // start state machine
}
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC
|| mode == ES_MODULE_LINE)
{
res |= es_write_reg (ES8388_ADDR, ES8388_ADCPOWER,
0x00); // power up adc and line in
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC
|| mode == ES_MODULE_LINE)
{
res |= es_write_reg (ES8388_ADDR, ES8388_DACPOWER,
0x3c); // power up dac and line out
res |= es8388_set_voice_mute (false);
ESP_LOGD (ES_TAG, "es8388_start default is mode:%d", mode);
}
return res;
}
/**
* @brief Power Management
*
* @param mod: if ES_POWER_CHIP, the whole chip including ADC and DAC is
* enabled
* @param enable: false to disable true to enable
*
* @return
* - (-1) Error
* - (0) Success
*/
esp_err_t
es8388_stop (es_module_t mode)
{
esp_err_t res = ESP_OK;
if (mode == ES_MODULE_LINE)
{
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL21,
0x80); // enable dac
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL16,
0x00); // 0x00 audio on LIN1&RIN1, 0x09 LIN2&RIN2
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL17,
0x90); // only left DAC to left mixer enable 0db
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL20,
0x90); // only right DAC to right mixer enable 0db
return res;
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC)
{
res |= es_write_reg (ES8388_ADDR, ES8388_DACPOWER, 0x00);
res |= es8388_set_voice_mute (
true); // res |= Es8388SetAdcDacVolume(ES_MODULE_DAC, -96, 5); // 0db
// res |= es_write_reg(ES8388_ADDR, ES8388_DACPOWER, 0xC0); //power down
// dac and line out
}
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC)
{
// res |= Es8388SetAdcDacVolume(ES_MODULE_ADC, -96, 5); // 0db
res |= es_write_reg (ES8388_ADDR, ES8388_ADCPOWER,
0xFF); // power down adc and line in
}
if (mode == ES_MODULE_ADC_DAC)
{
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL21,
0x9C); // disable mclk
// res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL1, 0x00);
// res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL2, 0x58);
// res |= es_write_reg(ES8388_ADDR, ES8388_CHIPPOWER, 0xF3);
// //stop state machine
}
return res;
}
/**
* @brief Config I2s clock in MSATER mode
*
* @param cfg.sclkDiv: generate SCLK by dividing MCLK in MSATER mode
* @param cfg.lclkDiv: generate LCLK by dividing MCLK in MSATER mode
*
* @return
* - (-1) Error
* - (0) Success
*/
esp_err_t
es8388_i2s_config_clock (es_i2s_clock_t cfg)
{
esp_err_t res = ESP_OK;
res |= es_write_reg (ES8388_ADDR, ES8388_MASTERMODE, cfg.sclk_div);
res |= es_write_reg (ES8388_ADDR, ES8388_ADCCONTROL5,
cfg.lclk_div); // ADCFsMode,singel SPEED,RATIO=256
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL2,
cfg.lclk_div); // ADCFsMode,singel SPEED,RATIO=256
return res;
}
esp_err_t
es8388_deinit (void)
{
int res = 0;
res = es_write_reg (ES8388_ADDR, ES8388_CHIPPOWER,
0xFF); // reset and stop es8388
i2c_bus_delete (i2c_handle);
#ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
headphone_detect_deinit ();
#endif
return res;
}
/**
* @return
* - (-1) Error
* - (0) Success
*/
esp_err_t
es8388_init (audio_hal_codec_config_t *cfg)
{
int res = 0;
#ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
headphone_detect_init (get_headphone_detect_gpio ());
#endif
res = i2c_init (); // ESP32 in master mode
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL3,
0x04); // 0x04 mute/0x00 unmute&ramp;DAC unmute and
// disabled digital volume control soft ramp
/* Chip Control and Power Management */
res |= es_write_reg (ES8388_ADDR, ES8388_CONTROL2, 0x50);
res |= es_write_reg (ES8388_ADDR, ES8388_CHIPPOWER,
0x00); // normal all and power up all
res |= es_write_reg (ES8388_ADDR, ES8388_MASTERMODE,
cfg->i2s_iface.mode); // CODEC IN I2S SLAVE MODE
/* dac */
res |= es_write_reg (ES8388_ADDR, ES8388_DACPOWER,
0xC0); // disable DAC and disable Lout/Rout/1/2
res |= es_write_reg (
ES8388_ADDR, ES8388_CONTROL1,
0x12); // Enfr=0,Play&Record Mode,(0x17-both of mic&paly)
// res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL2, 0);
// //LPVrefBuf=0,Pdn_ana=0
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL1,
0x18); // 1a 0x18:16bit iis , 0x00:24
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL2,
0x02); // DACFsMode,SINGLE SPEED; DACFsRatio,256
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL16,
0x00); // 0x00 audio on LIN1&RIN1, 0x09 LIN2&RIN2
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL17,
0x90); // only left DAC to left mixer enable 0db
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL20,
0x90); // only right DAC to right mixer enable 0db
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL21,
0x80); // set internal ADC and DAC use the same LRCK
// clock, ADC LRCK as internal LRCK
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL23, 0x00); // vroi=0
res |= es8388_set_adc_dac_volume (ES_MODULE_DAC, 0, 0); // 0db
int tmp = 0;
if (AUDIO_HAL_DAC_OUTPUT_LINE2 == cfg->dac_output)
{
tmp = DAC_OUTPUT_LOUT1 | DAC_OUTPUT_ROUT1;
}
else if (AUDIO_HAL_DAC_OUTPUT_LINE1 == cfg->dac_output)
{
tmp = DAC_OUTPUT_LOUT2 | DAC_OUTPUT_ROUT2;
}
else
{
tmp = DAC_OUTPUT_LOUT1 | DAC_OUTPUT_LOUT2 | DAC_OUTPUT_ROUT1
| DAC_OUTPUT_ROUT2;
}
res |= es_write_reg (ES8388_ADDR, ES8388_DACPOWER,
tmp); // 0x3c Enable DAC and Enable Lout/Rout/1/2
/* adc */
res |= es_write_reg (ES8388_ADDR, ES8388_ADCPOWER, 0xFF);
res |= es_write_reg (ES8388_ADDR, ES8388_ADCCONTROL1,
0xbb); // MIC Left and Right channel PGA gain
tmp = 0;
if (AUDIO_HAL_ADC_INPUT_LINE1 == cfg->adc_input)
{
tmp = ADC_INPUT_LINPUT1_RINPUT1;
}
else if (AUDIO_HAL_ADC_INPUT_LINE2 == cfg->adc_input)
{
tmp = ADC_INPUT_LINPUT2_RINPUT2;
}
else
{
tmp = ADC_INPUT_DIFFERENCE;
}
res |= es_write_reg (ES8388_ADDR, ES8388_ADCCONTROL2,
tmp); // 0x00 LINSEL & RINSEL, LIN1/RIN1 as ADC Input;
// DSSEL,use one DS Reg11; DSR, LINPUT1-RINPUT1
res |= es_write_reg (ES8388_ADDR, ES8388_ADCCONTROL3, 0x02);
res |= es_write_reg (ES8388_ADDR, ES8388_ADCCONTROL4,
0x0d); // Left/Right data, Left/Right justified mode,
// Bits length, I2S format
res |= es_write_reg (ES8388_ADDR, ES8388_ADCCONTROL5,
0x02); // ADCFsMode,singel SPEED,RATIO=256
// ALC for Microphone
res |= es8388_set_adc_dac_volume (ES_MODULE_ADC, 0, 0); // 0db
res |= es_write_reg (ES8388_ADDR, ES8388_ADCPOWER,
0x09); // Power on ADC, Enable LIN&RIN, Power off
// MICBIAS, set int1lp to low power mode
/* enable es8388 PA */
es8388_pa_power (true);
ESP_LOGI (ES_TAG, "init,out:%02x, in:%02x", cfg->dac_output, cfg->adc_input);
return res;
}
/**
* @brief Configure ES8388 I2S format
*
* @param mode: set ADC or DAC or all
* @param bitPerSample: see Es8388I2sFmt
*
* @return
* - (-1) Error
* - (0) Success
*/
esp_err_t
es8388_config_fmt (es_module_t mode, es_i2s_fmt_t fmt)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC)
{
res = es_read_reg (ES8388_ADCCONTROL4, &reg);
reg = reg & 0xfc;
res |= es_write_reg (ES8388_ADDR, ES8388_ADCCONTROL4, reg | fmt);
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC)
{
res = es_read_reg (ES8388_DACCONTROL1, &reg);
reg = reg & 0xf9;
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL1, reg | (fmt << 1));
}
return res;
}
/**
* @param volume: 0 ~ 100
*
* @return
* - (-1) Error
* - (0) Success
*/
esp_err_t
es8388_set_voice_volume (int volume)
{
esp_err_t res = ESP_OK;
if (volume < 0)
volume = 0;
else if (volume > 100)
volume = 100;
volume /= 3;
res = es_write_reg (ES8388_ADDR, ES8388_DACCONTROL24, volume);
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL25, volume);
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL26, 0);
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL27, 0);
return res;
}
/**
*
* @return
* volume
*/
esp_err_t
es8388_get_voice_volume (int *volume)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
res = es_read_reg (ES8388_DACCONTROL24, &reg);
if (res == ESP_FAIL)
{
*volume = 0;
}
else
{
*volume = reg;
*volume *= 3;
if (*volume == 99)
*volume = 100;
}
return res;
}
/**
* @brief Configure ES8388 data sample bits
*
* @param mode: set ADC or DAC or all
* @param bitPerSample: see BitsLength
*
* @return
* - (-1) Parameter error
* - (0) Success
*/
esp_err_t
es8388_set_bits_per_sample (es_module_t mode, es_bits_length_t bits_length)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
int bits = (int)bits_length;
if (mode == ES_MODULE_ADC || mode == ES_MODULE_ADC_DAC)
{
res = es_read_reg (ES8388_ADCCONTROL4, &reg);
reg = reg & 0xe3;
res |= es_write_reg (ES8388_ADDR, ES8388_ADCCONTROL4, reg | (bits << 2));
}
if (mode == ES_MODULE_DAC || mode == ES_MODULE_ADC_DAC)
{
res = es_read_reg (ES8388_DACCONTROL1, &reg);
reg = reg & 0xc7;
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL1, reg | (bits << 3));
}
return res;
}
/**
* @brief Configure ES8388 DAC mute or not. Basically you can use this function
* to mute the output or unmute
*
* @param enable: enable or disable
*
* @return
* - (-1) Parameter error
* - (0) Success
*/
esp_err_t
es8388_set_voice_mute (bool enable)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
res = es_read_reg (ES8388_DACCONTROL3, &reg);
reg = reg & 0xFB;
res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL3,
reg | (((int)enable) << 2));
return res;
}
esp_err_t
es8388_get_voice_mute (void)
{
esp_err_t res = ESP_OK;
uint8_t reg = 0;
res = es_read_reg (ES8388_DACCONTROL3, &reg);
if (res == ESP_OK)
{
reg = (reg & 0x04) >> 2;
}
return res == ESP_OK ? reg : res;
}
/**
* @param gain: Config DAC Output
*
* @return
* - (-1) Parameter error
* - (0) Success
*/
esp_err_t
es8388_config_dac_output (int output)
{
esp_err_t res;
uint8_t reg = 0;
res = es_read_reg (ES8388_DACPOWER, &reg);
reg = reg & 0xc3;
res |= es_write_reg (ES8388_ADDR, ES8388_DACPOWER, reg | output);
return res;
}
/**
* @param gain: Config ADC input
*
* @return
* - (-1) Parameter error
* - (0) Success
*/
esp_err_t
es8388_config_adc_input (es_adc_input_t input)
{
esp_err_t res;
uint8_t reg = 0;
res = es_read_reg (ES8388_ADCCONTROL2, &reg);
reg = reg & 0x0f;
res |= es_write_reg (ES8388_ADDR, ES8388_ADCCONTROL2, reg | input);
return res;
}
/**
* @param gain: see es_mic_gain_t
*
* @return
* - (-1) Parameter error
* - (0) Success
*/
esp_err_t
es8388_set_mic_gain (es_mic_gain_t gain)
{
esp_err_t res, gain_n;
gain_n = (int)gain / 3;
gain_n = (gain_n << 4) + gain_n;
res = es_write_reg (ES8388_ADDR, ES8388_ADCCONTROL1, gain_n); // MIC PGA
return res;
}
int
es8388_ctrl_state (audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state)
{
int res = 0;
int es_mode_t = 0;
switch (mode)
{
case AUDIO_HAL_CODEC_MODE_ENCODE:
es_mode_t = ES_MODULE_ADC;
break;
case AUDIO_HAL_CODEC_MODE_LINE_IN:
es_mode_t = ES_MODULE_LINE;
break;
case AUDIO_HAL_CODEC_MODE_DECODE:
es_mode_t = ES_MODULE_DAC;
break;
case AUDIO_HAL_CODEC_MODE_BOTH:
es_mode_t = ES_MODULE_ADC_DAC;
break;
default:
es_mode_t = ES_MODULE_DAC;
ESP_LOGW (ES_TAG, "Codec mode not support, default is decode mode");
break;
}
if (AUDIO_HAL_CTRL_STOP == ctrl_state)
{
res = es8388_stop (es_mode_t);
}
else
{
res = es8388_start (es_mode_t);
ESP_LOGD (ES_TAG, "start default is decode mode:%d", es_mode_t);
}
return res;
}
esp_err_t
es8388_config_i2s (audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface)
{
esp_err_t res = ESP_OK;
int tmp = 0;
res |= es8388_config_fmt (ES_MODULE_ADC_DAC, iface->fmt);
if (iface->bits == AUDIO_HAL_BIT_LENGTH_16BITS)
{
tmp = BIT_LENGTH_16BITS;
}
else if (iface->bits == AUDIO_HAL_BIT_LENGTH_24BITS)
{
tmp = BIT_LENGTH_24BITS;
}
else
{
tmp = BIT_LENGTH_32BITS;
}
res |= es8388_set_bits_per_sample (ES_MODULE_ADC_DAC, tmp);
return res;
}
void
es8388_pa_power (bool enable)
{
gpio_config_t io_conf;
memset (&io_conf, 0, sizeof (io_conf));
io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = BIT64 (get_pa_enable_gpio ());
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
gpio_config (&io_conf);
if (enable)
{
gpio_set_level (get_pa_enable_gpio (), 1);
}
else
{
gpio_set_level (get_pa_enable_gpio (), 0);
}
}

View File

@@ -0,0 +1,319 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef __ES8388_H__
#define __ES8388_H__
#include "audio_hal.h"
#include "driver/i2c.h"
#include "esp_types.h"
#include "esxxx_common.h"
#ifdef __cplusplus
extern "C"
{
#endif
/* ES8388 address */
#define ES8388_ADDR 0x20 /*!< 0x22:CE=1;0x20:CE=0*/
/* ES8388 register */
#define ES8388_CONTROL1 0x00
#define ES8388_CONTROL2 0x01
#define ES8388_CHIPPOWER 0x02
#define ES8388_ADCPOWER 0x03
#define ES8388_DACPOWER 0x04
#define ES8388_CHIPLOPOW1 0x05
#define ES8388_CHIPLOPOW2 0x06
#define ES8388_ANAVOLMANAG 0x07
#define ES8388_MASTERMODE 0x08
/* ADC */
#define ES8388_ADCCONTROL1 0x09
#define ES8388_ADCCONTROL2 0x0a
#define ES8388_ADCCONTROL3 0x0b
#define ES8388_ADCCONTROL4 0x0c
#define ES8388_ADCCONTROL5 0x0d
#define ES8388_ADCCONTROL6 0x0e
#define ES8388_ADCCONTROL7 0x0f
#define ES8388_ADCCONTROL8 0x10
#define ES8388_ADCCONTROL9 0x11
#define ES8388_ADCCONTROL10 0x12
#define ES8388_ADCCONTROL11 0x13
#define ES8388_ADCCONTROL12 0x14
#define ES8388_ADCCONTROL13 0x15
#define ES8388_ADCCONTROL14 0x16
/* DAC */
#define ES8388_DACCONTROL1 0x17
#define ES8388_DACCONTROL2 0x18
#define ES8388_DACCONTROL3 0x19
#define ES8388_DACCONTROL4 0x1a
#define ES8388_DACCONTROL5 0x1b
#define ES8388_DACCONTROL6 0x1c
#define ES8388_DACCONTROL7 0x1d
#define ES8388_DACCONTROL8 0x1e
#define ES8388_DACCONTROL9 0x1f
#define ES8388_DACCONTROL10 0x20
#define ES8388_DACCONTROL11 0x21
#define ES8388_DACCONTROL12 0x22
#define ES8388_DACCONTROL13 0x23
#define ES8388_DACCONTROL14 0x24
#define ES8388_DACCONTROL15 0x25
#define ES8388_DACCONTROL16 0x26
#define ES8388_DACCONTROL17 0x27
#define ES8388_DACCONTROL18 0x28
#define ES8388_DACCONTROL19 0x29
#define ES8388_DACCONTROL20 0x2a
#define ES8388_DACCONTROL21 0x2b
#define ES8388_DACCONTROL22 0x2c
#define ES8388_DACCONTROL23 0x2d
#define ES8388_DACCONTROL24 0x2e
#define ES8388_DACCONTROL25 0x2f
#define ES8388_DACCONTROL26 0x30
#define ES8388_DACCONTROL27 0x31
#define ES8388_DACCONTROL28 0x32
#define ES8388_DACCONTROL29 0x33
#define ES8388_DACCONTROL30 0x34
/**
* @brief Initialize ES8388 codec chip
*
* @param cfg configuration of ES8388
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8388_init (audio_hal_codec_config_t *cfg);
/**
* @brief Deinitialize ES8388 codec chip
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8388_deinit (void);
/**
* @brief Configure ES8388 I2S format
*
* @param mod: set ADC or DAC or both
* @param cfg: ES8388 I2S format
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8388_config_fmt (es_module_t mod, es_i2s_fmt_t cfg);
/**
* @brief Configure I2s clock in MSATER mode
*
* @param cfg: set bits clock and WS clock
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8388_i2s_config_clock (es_i2s_clock_t cfg);
/**
* @brief Configure ES8388 data sample bits
*
* @param mode: set ADC or DAC or both
* @param bit_per_sample: bit number of per sample
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8388_set_bits_per_sample (es_module_t mode,
es_bits_length_t bit_per_sample);
/**
* @brief Start ES8388 codec chip
*
* @param mode: set ADC or DAC or both
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8388_start (es_module_t mode);
/**
* @brief Stop ES8388 codec chip
*
* @param mode: set ADC or DAC or both
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8388_stop (es_module_t mode);
/**
* @brief Set voice volume
*
* @param volume: voice volume (0~100)
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8388_set_voice_volume (int volume);
/**
* @brief Get voice volume
*
* @param[out] *volume: voice volume (0~100)
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8388_get_voice_volume (int *volume);
/**
* @brief Configure ES8388 DAC mute or not. Basically you can use this
* function to mute the output or unmute
*
* @param enable enable(1) or disable(0)
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8388_set_voice_mute (bool enable);
/**
* @brief Get ES8388 DAC mute status
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8388_get_voice_mute (void);
/**
* @brief Set ES8388 mic gain
*
* @param gain db of mic gain
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8388_set_mic_gain (es_mic_gain_t gain);
/**
* @brief Set ES8388 adc input mode
*
* @param input adc input mode
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8388_config_adc_input (es_adc_input_t input);
/**
* @brief Set ES8388 dac output mode
*
* @param output dac output mode
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8388_config_dac_output (es_dac_output_t output);
/**
* @brief Write ES8388 register
*
* @param reg_add address of register
* @param data data of register
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8388_write_reg (uint8_t reg_add, uint8_t data);
/**
* @brief Print all ES8388 registers
*
* @return
* - void
*/
void es8388_read_all ();
/**
* @brief Configure ES8388 codec mode and I2S interface
*
* @param mode codec mode
* @param iface I2S config
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8388_config_i2s (audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface);
/**
* @brief Control ES8388 codec chip
*
* @param mode codec mode
* @param ctrl_state start or stop decode or encode progress
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8388_ctrl_state (audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state);
/**
* @brief Set ES8388 PA power
*
* @param enable true for enable PA power, false for disable PA power
*
* @return
* - void
*/
void es8388_pa_power (bool enable);
#ifdef __cplusplus
}
#endif
#endif //__ES8388_H__

View File

@@ -0,0 +1,110 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include <stdio.h>
#include <string.h>
#include "board.h"
#include "driver/gpio.h"
#include "es8388.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
#define HP_DELAY_TIME_MS 1000
static char *TAG = "HEADPHONE";
static xTimerHandle timer_headphone;
static void
hp_timer_cb (TimerHandle_t xTimer)
{
int num = (int)pvTimerGetTimerID (xTimer);
int res = gpio_get_level (num);
es8388_pa_power (res);
ESP_LOGW (TAG, "Headphone jack %s", res ? "removed" : "inserted");
}
static int
hp_timer_init (int num)
{
timer_headphone
= xTimerCreate ("hp_timer0", HP_DELAY_TIME_MS / portTICK_RATE_MS,
pdFALSE, (void *)num, hp_timer_cb);
if (timer_headphone == NULL)
{
ESP_LOGE (TAG, "hp_timer create err");
return ESP_FAIL;
}
return ESP_OK;
}
static void IRAM_ATTR
headphone_gpio_intr_handler (void *arg)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xTimerResetFromISR (timer_headphone, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken != pdFALSE)
{
portYIELD_FROM_ISR ();
}
}
void
headphone_detect_deinit ()
{
xTimerDelete (timer_headphone, HP_DELAY_TIME_MS / portTICK_RATE_MS);
gpio_uninstall_isr_service ();
timer_headphone = NULL;
}
int
headphone_status_get ()
{
return gpio_get_level (0);
}
void
headphone_detect_init (int num)
{
hp_timer_init (num);
gpio_config_t io_conf;
memset (&io_conf, 0, sizeof (io_conf));
io_conf.intr_type = GPIO_INTR_ANYEDGE;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = BIT64 (num);
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 1;
gpio_config (&io_conf);
gpio_install_isr_service (0);
gpio_isr_handler_add (num, headphone_gpio_intr_handler, (void *)num);
}
#endif /* CONFIG_ESP_LYRAT_V4_3_BOARD */

View File

@@ -0,0 +1,66 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _AUDIO_HEADPHONE_DETEC_H_
#define _AUDIO_HEADPHONE_DETEC_H_
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Get headphone insertion status
*
* @param None.
*
* @return int, 0:headphone inserted, 1:headphone not inserted.
*/
int headphone_status_get ();
/**
* @brief Initialize headphone detect gpio.
*
* @param None.
*
* @return None.
*/
void headphone_detect_init (int num);
/**
* @brief Delete headphone detect timer.
*
* @param None.
*
* @return None.
*/
void headphone_detect_deinit ();
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,202 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _ESXXX_COMMON_H_
#define _ESXXX_COMMON_H_
#ifdef __cplusplus
extern "C"
{
#endif
typedef enum
{
BIT_LENGTH_MIN = -1,
BIT_LENGTH_16BITS = 0x03,
BIT_LENGTH_18BITS = 0x02,
BIT_LENGTH_20BITS = 0x01,
BIT_LENGTH_24BITS = 0x00,
BIT_LENGTH_32BITS = 0x04,
BIT_LENGTH_MAX,
} es_bits_length_t;
typedef enum
{
MCLK_DIV_MIN = -1,
MCLK_DIV_1 = 1,
MCLK_DIV_2 = 2,
MCLK_DIV_3 = 3,
MCLK_DIV_4 = 4,
MCLK_DIV_6 = 5,
MCLK_DIV_8 = 6,
MCLK_DIV_9 = 7,
MCLK_DIV_11 = 8,
MCLK_DIV_12 = 9,
MCLK_DIV_16 = 10,
MCLK_DIV_18 = 11,
MCLK_DIV_22 = 12,
MCLK_DIV_24 = 13,
MCLK_DIV_33 = 14,
MCLK_DIV_36 = 15,
MCLK_DIV_44 = 16,
MCLK_DIV_48 = 17,
MCLK_DIV_66 = 18,
MCLK_DIV_72 = 19,
MCLK_DIV_5 = 20,
MCLK_DIV_10 = 21,
MCLK_DIV_15 = 22,
MCLK_DIV_17 = 23,
MCLK_DIV_20 = 24,
MCLK_DIV_25 = 25,
MCLK_DIV_30 = 26,
MCLK_DIV_32 = 27,
MCLK_DIV_34 = 28,
MCLK_DIV_7 = 29,
MCLK_DIV_13 = 30,
MCLK_DIV_14 = 31,
MCLK_DIV_MAX,
} es_sclk_div_t;
typedef enum
{
LCLK_DIV_MIN = -1,
LCLK_DIV_128 = 0,
LCLK_DIV_192 = 1,
LCLK_DIV_256 = 2,
LCLK_DIV_384 = 3,
LCLK_DIV_512 = 4,
LCLK_DIV_576 = 5,
LCLK_DIV_768 = 6,
LCLK_DIV_1024 = 7,
LCLK_DIV_1152 = 8,
LCLK_DIV_1408 = 9,
LCLK_DIV_1536 = 10,
LCLK_DIV_2112 = 11,
LCLK_DIV_2304 = 12,
LCLK_DIV_125 = 16,
LCLK_DIV_136 = 17,
LCLK_DIV_250 = 18,
LCLK_DIV_272 = 19,
LCLK_DIV_375 = 20,
LCLK_DIV_500 = 21,
LCLK_DIV_544 = 22,
LCLK_DIV_750 = 23,
LCLK_DIV_1000 = 24,
LCLK_DIV_1088 = 25,
LCLK_DIV_1496 = 26,
LCLK_DIV_1500 = 27,
LCLK_DIV_MAX,
} es_lclk_div_t;
typedef enum
{
D2SE_PGA_GAIN_MIN = -1,
D2SE_PGA_GAIN_DIS = 0,
D2SE_PGA_GAIN_EN = 1,
D2SE_PGA_GAIN_MAX = 2,
} es_d2se_pga_t;
typedef enum
{
ADC_INPUT_MIN = -1,
ADC_INPUT_LINPUT1_RINPUT1 = 0x00,
ADC_INPUT_MIC1 = 0x05,
ADC_INPUT_MIC2 = 0x06,
ADC_INPUT_LINPUT2_RINPUT2 = 0x50,
ADC_INPUT_DIFFERENCE = 0xf0,
ADC_INPUT_MAX,
} es_adc_input_t;
typedef enum
{
DAC_OUTPUT_MIN = -1,
DAC_OUTPUT_LOUT1 = 0x04,
DAC_OUTPUT_LOUT2 = 0x08,
DAC_OUTPUT_SPK = 0x09,
DAC_OUTPUT_ROUT1 = 0x10,
DAC_OUTPUT_ROUT2 = 0x20,
DAC_OUTPUT_ALL = 0x3c,
DAC_OUTPUT_MAX,
} es_dac_output_t;
typedef enum
{
MIC_GAIN_MIN = -1,
MIC_GAIN_0DB = 0,
MIC_GAIN_3DB = 3,
MIC_GAIN_6DB = 6,
MIC_GAIN_9DB = 9,
MIC_GAIN_12DB = 12,
MIC_GAIN_15DB = 15,
MIC_GAIN_18DB = 18,
MIC_GAIN_21DB = 21,
MIC_GAIN_24DB = 24,
MIC_GAIN_MAX,
} es_mic_gain_t;
typedef enum
{
ES_MODULE_MIN = -1,
ES_MODULE_ADC = 0x01,
ES_MODULE_DAC = 0x02,
ES_MODULE_ADC_DAC = 0x03,
ES_MODULE_LINE = 0x04,
ES_MODULE_MAX
} es_module_t;
typedef enum
{
ES_MODE_MIN = -1,
ES_MODE_SLAVE = 0x00,
ES_MODE_MASTER = 0x01,
ES_MODE_MAX,
} es_mode_t;
typedef enum
{
ES_I2S_MIN = -1,
ES_I2S_NORMAL = 0,
ES_I2S_LEFT = 1,
ES_I2S_RIGHT = 2,
ES_I2S_DSP = 3,
ES_I2S_MAX
} es_i2s_fmt_t;
/**
* @brief Configure ES8388 clock
*/
typedef struct
{
es_sclk_div_t sclk_div; /*!< bits clock divide */
es_lclk_div_t lclk_div; /*!< WS clock divide */
} es_i2s_clock_t;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,323 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "tas5805m.h"
#include "board.h"
#include "esp_log.h"
#include "i2c_bus.h"
#include "tas5805m_reg_cfg.h"
static const char *TAG = "TAS5805M";
#define TAS5805M_ADDR 0x5c
#define TAS5805M_RST_GPIO get_pa_enable_gpio ()
#define TAS5805M_VOLUME_MAX 100
#define TAS5805M_VOLUME_MIN 0
#define TAS5805M_ASSERT(a, format, b, ...) \
if ((a) != 0) \
{ \
ESP_LOGE (TAG, format, ##__VA_ARGS__); \
return b; \
}
esp_err_t tas5805m_ctrl (audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state);
esp_err_t tas5805m_conig_iface (audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface);
static i2c_bus_handle_t i2c_handler;
/*
* i2c default configuration
*/
static i2c_config_t i2c_cfg = {
.mode = I2C_MODE_MASTER,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000,
};
/*
* Operate fuction of PA
*/
audio_hal_func_t AUDIO_CODEC_TAS5805M_DEFAULT_HANDLE = {
.audio_codec_initialize = tas5805m_init,
.audio_codec_deinitialize = tas5805m_deinit,
.audio_codec_ctrl = tas5805m_ctrl,
.audio_codec_config_iface = tas5805m_conig_iface,
.audio_codec_set_mute = tas5805m_set_mute,
.audio_codec_set_volume = tas5805m_set_volume,
.audio_codec_get_volume = tas5805m_get_volume,
.audio_hal_lock = NULL,
.handle = NULL,
};
static esp_err_t
tas5805m_transmit_registers (const tas5805m_cfg_reg_t *conf_buf, int size)
{
int i = 0;
esp_err_t ret = ESP_OK;
while (i < size)
{
switch (conf_buf[i].offset)
{
case CFG_META_SWITCH:
// Used in legacy applications. Ignored here.
break;
case CFG_META_DELAY:
vTaskDelay (conf_buf[i].value / portTICK_RATE_MS);
break;
case CFG_META_BURST:
ret = i2c_bus_write_bytes (
i2c_handler, TAS5805M_ADDR,
(unsigned char *)(&conf_buf[i + 1].offset), 1,
(unsigned char *)(&conf_buf[i + 1].value), conf_buf[i].value);
i += (conf_buf[i].value / 2) + 1;
break;
case CFG_END_1:
if (CFG_END_2 == conf_buf[i + 1].offset
&& CFG_END_3 == conf_buf[i + 2].offset)
{
ESP_LOGI (TAG, "End of tms5805m reg: %d\n", i);
}
break;
default:
ret = i2c_bus_write_bytes (i2c_handler, TAS5805M_ADDR,
(unsigned char *)(&conf_buf[i].offset), 1,
(unsigned char *)(&conf_buf[i].value), 1);
break;
}
i++;
}
if (ret != ESP_OK)
{
ESP_LOGE (TAG, "Fail to load configuration to tas5805m");
return ESP_FAIL;
}
ESP_LOGI (TAG, "%s: write %d reg done", __FUNCTION__, i);
return ret;
}
esp_err_t
tas5805m_init (audio_hal_codec_config_t *codec_cfg)
{
esp_err_t ret = ESP_OK;
ESP_LOGI (TAG, "Power ON CODEC with GPIO %d", TAS5805M_RST_GPIO);
gpio_config_t io_conf;
io_conf.pin_bit_mask = BIT64 (TAS5805M_RST_GPIO);
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.intr_type = GPIO_INTR_DISABLE;
gpio_config (&io_conf);
gpio_set_level (TAS5805M_RST_GPIO, 0);
vTaskDelay (20 / portTICK_RATE_MS);
gpio_set_level (TAS5805M_RST_GPIO, 1);
vTaskDelay (200 / portTICK_RATE_MS);
ret = get_i2c_pins (I2C_NUM_0, &i2c_cfg);
i2c_handler = i2c_bus_create (I2C_NUM_0, &i2c_cfg);
if (i2c_handler == NULL)
{
ESP_LOGW (TAG, "failed to create i2c bus handler\n");
return ESP_FAIL;
}
ret |= tas5805m_transmit_registers (tas5805m_registers,
sizeof (tas5805m_registers)
/ sizeof (tas5805m_registers[0]));
TAS5805M_ASSERT (ret, "Fail to iniitialize tas5805m PA", ESP_FAIL);
return ret;
}
esp_err_t
tas5805m_set_volume (int vol)
{
int vol_idx = 0;
if (vol < TAS5805M_VOLUME_MIN)
{
vol = TAS5805M_VOLUME_MIN;
}
if (vol > TAS5805M_VOLUME_MAX)
{
vol = TAS5805M_VOLUME_MAX;
}
vol_idx = vol / 5;
uint8_t cmd[2] = { 0, 0 };
esp_err_t ret = ESP_OK;
cmd[0] = MASTER_VOL_REG_ADDR;
cmd[1] = tas5805m_volume[vol_idx];
ret = i2c_bus_write_bytes (i2c_handler, TAS5805M_ADDR, &cmd[0], 1, &cmd[1],
1);
ESP_LOGW (TAG, "volume = 0x%x", cmd[1]);
return ret;
}
esp_err_t
tas5805m_get_volume (int *value)
{
/// FIXME: Got the digit volume is not right.
uint8_t cmd[2] = { MASTER_VOL_REG_ADDR, 0x00 };
esp_err_t ret = i2c_bus_read_bytes (i2c_handler, TAS5805M_ADDR, &cmd[0], 1,
&cmd[1], 1);
TAS5805M_ASSERT (ret, "Fail to get volume", ESP_FAIL);
int i;
for (i = 0; i < sizeof (tas5805m_volume); i++)
{
if (cmd[1] >= tas5805m_volume[i])
break;
}
ESP_LOGI (TAG, "Volume is %d", i * 5);
*value = 5 * i;
return ret;
}
esp_err_t
tas5805m_set_mute (bool enable)
{
esp_err_t ret = ESP_OK;
uint8_t cmd[2] = { TAS5805M_REG_03, 0x00 };
ret |= i2c_bus_read_bytes (i2c_handler, TAS5805M_ADDR, &cmd[0], 1, &cmd[1],
1);
if (enable)
{
cmd[1] |= 0x8;
}
else
{
cmd[1] &= (~0x08);
}
ret |= i2c_bus_write_bytes (i2c_handler, TAS5805M_ADDR, &cmd[0], 1, &cmd[1],
1);
TAS5805M_ASSERT (ret, "Fail to set mute", ESP_FAIL);
return ret;
}
esp_err_t
tas5805m_get_mute (int *value)
{
esp_err_t ret = ESP_OK;
uint8_t cmd[2] = { TAS5805M_REG_03, 0x00 };
ret |= i2c_bus_read_bytes (i2c_handler, TAS5805M_ADDR, &cmd[0], 1, &cmd[1],
1);
TAS5805M_ASSERT (ret, "Fail to get mute", ESP_FAIL);
*value = (cmd[1] & 0x08) >> 4;
ESP_LOGI (TAG, "Get mute value: 0x%x", *value);
return ret;
}
esp_err_t
tas5805m_set_mute_fade (int value)
{
esp_err_t ret = 0;
unsigned char cmd[2] = { MUTE_TIME_REG_ADDR, 0x00 };
/* Time for register value
* 000: 11.5 ms
* 001: 53 ms
* 010: 106.5 ms
* 011: 266.5 ms
* 100: 0.535 sec
* 101: 1.065 sec
* 110: 2.665 sec
* 111: 5.33 sec
*/
if (value <= 12)
{
cmd[1] = 0;
}
else if (value <= 53)
{
cmd[1] = 1;
}
else if (value <= 107)
{
cmd[1] = 2;
}
else if (value <= 267)
{
cmd[1] = 3;
}
else if (value <= 535)
{
cmd[1] = 4;
}
else if (value <= 1065)
{
cmd[1] = 5;
}
else if (value <= 2665)
{
cmd[1] = 6;
}
else
{
cmd[1] = 7;
}
cmd[1] |= (cmd[1] << 4);
ret |= i2c_bus_write_bytes (i2c_handler, TAS5805M_ADDR, &cmd[0], 1, &cmd[1],
1);
TAS5805M_ASSERT (ret, "Fail to set mute fade", ESP_FAIL);
ESP_LOGI (TAG, "Set mute fade, value:%d, 0x%x", value, cmd[1]);
return ret;
}
esp_err_t
tas5805m_set_damp_mode (int value)
{
unsigned char cmd[2] = { 0 };
cmd[0] = TAS5805M_REG_02;
cmd[1] = 0x10 | value;
return i2c_bus_write_bytes (i2c_handler, TAS5805M_ADDR, &cmd[0], 1, &cmd[1],
1);
}
esp_err_t
tas5805m_deinit (void)
{
// TODO
return ESP_OK;
}
esp_err_t
tas5805m_ctrl (audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state)
{
// TODO
return ESP_OK;
}
esp_err_t
tas5805m_conig_iface (audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface)
{
// TODO
return ESP_OK;
}

View File

@@ -0,0 +1,155 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _TAS5805M_H_
#define _TAS5805M_H_
#include "audio_hal.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define TAS5805M_REG_00 0x00
#define TAS5805M_REG_02 0x02
#define TAS5805M_REG_03 0x03
#define TAS5805M_REG_24 0x24
#define TAS5805M_REG_25 0x25
#define TAS5805M_REG_26 0x26
#define TAS5805M_REG_27 0x27
#define TAS5805M_REG_28 0x28
#define TAS5805M_REG_29 0x29
#define TAS5805M_REG_2A 0x2a
#define TAS5805M_REG_2B 0x2b
#define TAS5805M_REG_35 0x35
#define TAS5805M_REG_7E 0x7e
#define TAS5805M_REG_7F 0x7f
#define TAS5805M_PAGE_00 0x00
#define TAS5805M_PAGE_2A 0x2a
#define TAS5805M_BOOK_00 0x00
#define TAS5805M_BOOK_8C 0x8c
#define MASTER_VOL_REG_ADDR 0X4C
#define MUTE_TIME_REG_ADDR 0X51
#define TAS5805M_DAMP_MODE_BTL 0x0
#define TAS5805M_DAMP_MODE_PBTL 0x04
/**
* @brief Initialize TAS5805 codec chip
*
* @param cfg configuration of TAS5805
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t tas5805m_init (audio_hal_codec_config_t *codec_cfg);
/**
* @brief Deinitialize TAS5805 codec chip
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t tas5805m_deinit (void);
/**
* @brief Set voice volume
*
* @param volume: voice volume (0~100)
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t tas5805m_set_volume (int vol);
/**
* @brief Get voice volume
*
* @param[out] *volume: voice volume (0~100)
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t tas5805m_get_volume (int *value);
/**
* @brief Set TAS5805 mute or not
* Continuously call should have an interval time determined by
* tas5805m_set_mute_fade()
*
* @param enable enable(1) or disable(0)
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t tas5805m_set_mute (bool enable);
/**
* @brief Mute gradually by (value)ms
*
* @param value Time for mute with millisecond.
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*
*/
esp_err_t tas5805m_set_mute_fade (int value);
/**
* @brief Get TAS5805 mute status
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t tas5805m_get_mute (int *value);
/**
* @brief Set DAMP mode
*
* @param value TAS5805M_DAMP_MODE_BTL or TAS5805M_DAMP_MODE_PBTL
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*
*/
esp_err_t tas5805m_set_damp_mode (int value);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,272 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _AUDIO_HAL_H_
#define _AUDIO_HAL_H_
#include "audio_error.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define AUDIO_HAL_VOL_DEFAULT 70
typedef struct audio_hal *audio_hal_handle_t;
/**
* @brief Select media hal codec mode
*/
typedef enum
{
AUDIO_HAL_CODEC_MODE_ENCODE = 1, /*!< select adc */
AUDIO_HAL_CODEC_MODE_DECODE, /*!< select dac */
AUDIO_HAL_CODEC_MODE_BOTH, /*!< select both adc and dac */
AUDIO_HAL_CODEC_MODE_LINE_IN, /*!< set adc channel */
} audio_hal_codec_mode_t;
/**
* @brief Select adc channel for input mic signal
*/
typedef enum
{
AUDIO_HAL_ADC_INPUT_LINE1 = 0x00, /*!< mic input to adc channel 1 */
AUDIO_HAL_ADC_INPUT_LINE2, /*!< mic input to adc channel 2 */
AUDIO_HAL_ADC_INPUT_ALL, /*!< mic input to both channels of adc */
AUDIO_HAL_ADC_INPUT_DIFFERENCE, /*!< mic input to adc difference channel */
} audio_hal_adc_input_t;
/**
* @brief Select channel for dac output
*/
typedef enum
{
AUDIO_HAL_DAC_OUTPUT_LINE1 = 0x00, /*!< dac output signal to channel 1 */
AUDIO_HAL_DAC_OUTPUT_LINE2, /*!< dac output signal to channel 2 */
AUDIO_HAL_DAC_OUTPUT_ALL, /*!< dac output signal to both channels */
} audio_hal_dac_output_t;
/**
* @brief Select operating mode i.e. start or stop for audio codec chip
*/
typedef enum
{
AUDIO_HAL_CTRL_STOP = 0x00, /*!< set stop mode */
AUDIO_HAL_CTRL_START = 0x01, /*!< set start mode */
} audio_hal_ctrl_t;
/**
* @brief Select I2S interface operating mode i.e. master or slave for audio
* codec chip
*/
typedef enum
{
AUDIO_HAL_MODE_SLAVE = 0x00, /*!< set slave mode */
AUDIO_HAL_MODE_MASTER = 0x01, /*!< set master mode */
} audio_hal_iface_mode_t;
/**
* @brief Select I2S interface samples per second
*/
typedef enum
{
AUDIO_HAL_08K_SAMPLES, /*!< set to 8k samples per second */
AUDIO_HAL_11K_SAMPLES, /*!< set to 11.025k samples per second */
AUDIO_HAL_16K_SAMPLES, /*!< set to 16k samples in per second */
AUDIO_HAL_22K_SAMPLES, /*!< set to 22.050k samples per second */
AUDIO_HAL_24K_SAMPLES, /*!< set to 24k samples in per second */
AUDIO_HAL_32K_SAMPLES, /*!< set to 32k samples in per second */
AUDIO_HAL_44K_SAMPLES, /*!< set to 44.1k samples per second */
AUDIO_HAL_48K_SAMPLES, /*!< set to 48k samples per second */
} audio_hal_iface_samples_t;
/**
* @brief Select I2S interface number of bits per sample
*/
typedef enum
{
AUDIO_HAL_BIT_LENGTH_16BITS = 1, /*!< set 16 bits per sample */
AUDIO_HAL_BIT_LENGTH_24BITS, /*!< set 24 bits per sample */
AUDIO_HAL_BIT_LENGTH_32BITS, /*!< set 32 bits per sample */
} audio_hal_iface_bits_t;
/**
* @brief Select I2S interface format for audio codec chip
*/
typedef enum
{
AUDIO_HAL_I2S_NORMAL = 0, /*!< set normal I2S format */
AUDIO_HAL_I2S_LEFT, /*!< set all left format */
AUDIO_HAL_I2S_RIGHT, /*!< set all right format */
AUDIO_HAL_I2S_DSP, /*!< set dsp/pcm format */
} audio_hal_iface_format_t;
/**
* @brief I2s interface configuration for audio codec chip
*/
typedef struct
{
audio_hal_iface_mode_t mode; /*!< audio codec chip mode */
audio_hal_iface_format_t fmt; /*!< I2S interface format */
audio_hal_iface_samples_t samples; /*!< I2S interface samples per second */
audio_hal_iface_bits_t
bits; /*!< i2s interface number of bits per sample */
} audio_hal_codec_i2s_iface_t;
/**
* @brief Configure media hal for initialization of audio codec chip
*/
typedef struct
{
audio_hal_adc_input_t adc_input; /*!< set adc channel */
audio_hal_dac_output_t dac_output; /*!< set dac channel */
audio_hal_codec_mode_t
codec_mode; /*!< select codec mode: adc, dac or both */
audio_hal_codec_i2s_iface_t
i2s_iface; /*!< set I2S interface configuration */
} audio_hal_codec_config_t;
/**
* @brief Configuration of functions and variables used to operate audio
* codec chip
*/
typedef struct audio_hal
{
esp_err_t (*audio_codec_initialize) (
audio_hal_codec_config_t *codec_cfg); /*!< initialize codec */
esp_err_t (*audio_codec_deinitialize) (void); /*!< deinitialize codec */
esp_err_t (*audio_codec_ctrl) (
audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state); /*!< control codec mode and state */
esp_err_t (*audio_codec_config_iface) (
audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface); /*!< configure i2s interface */
esp_err_t (*audio_codec_set_mute) (bool mute); /*!< set codec mute */
esp_err_t (*audio_codec_set_volume) (int volume); /*!< set codec volume */
esp_err_t (*audio_codec_get_volume) (int *volume); /*!< get codec volume */
xSemaphoreHandle audio_hal_lock; /*!< semaphore of codec */
void *handle; /*!< handle of audio codec */
} audio_hal_func_t;
/**
* @brief Initialize media codec driver
*
* @note If selected codec has already been installed, it'll return the
* audio_hal handle.
*
* @param audio_hal_conf Configure structure audio_hal_config_t
* @param audio_hal_func Structure containing functions used to operate audio
* the codec chip
*
* @return int, 0--success, others--fail
*/
audio_hal_handle_t audio_hal_init (audio_hal_codec_config_t *audio_hal_conf,
audio_hal_func_t *audio_hal_func);
/**
* @brief Uninitialize media codec driver
*
* @param audio_hal reference function pointer for selected audio codec
*
* @return int, 0--success, others--fail
*/
esp_err_t audio_hal_deinit (audio_hal_handle_t audio_hal);
/**
* @brief Start/stop codec driver
*
* @param audio_hal reference function pointer for selected audio codec
* @param mode select media hal codec mode either encode/decode/or both to
* start from audio_hal_codec_mode_t
* @param audio_hal_ctrl select start stop state for specific mode
*
* @return int, 0--success, others--fail
*/
esp_err_t audio_hal_ctrl_codec (audio_hal_handle_t audio_hal,
audio_hal_codec_mode_t mode,
audio_hal_ctrl_t audio_hal_ctrl);
/**
* @brief Set codec I2S interface samples rate & bit width and format either
* I2S or PCM/DSP.
*
* @param audio_hal reference function pointer for selected audio codec
* @param mode select media hal codec mode either encode/decode/or both to
* start from audio_hal_codec_mode_t
* @param iface I2S sample rate (ex: 16000, 44100), I2S bit width (16, 24,
* 32),I2s format (I2S, PCM, DSP).
*
* @return
* - 0 Success
* - -1 Error
*/
esp_err_t audio_hal_codec_iface_config (audio_hal_handle_t audio_hal,
audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface);
/**
* @brief Set voice mute. Enables or disables DAC mute of a codec.
* @note `audio_hal_get_volume` will still give a non-zero number in
* mute state. It will be set to that number when speaker is unmuted.
*
* @param audio_hal reference function pointer for selected audio codec
* @param mute true/false. If true speaker will be muted and if false
* speaker will be unmuted.
*
* @return int, 0--success, others--fail
*/
esp_err_t audio_hal_set_mute (audio_hal_handle_t audio_hal, bool mute);
/**
* @brief Set voice volume.
* @note if volume is 0, mute is enabled,range is 0-100.
*
* @param audio_hal reference function pointer for selected audio codec
* @param volume value of volume in percent(%)
*
* @return int, 0--success, others--fail
*/
esp_err_t audio_hal_set_volume (audio_hal_handle_t audio_hal, int volume);
/**
* @brief get voice volume.
* @note if volume is 0, mute is enabled, range is 0-100.
*
* @param audio_hal reference function pointer for selected audio codec
* @param volume value of volume in percent returned(%)
*
* @return int, 0--success, others--fail
*/
esp_err_t audio_hal_get_volume (audio_hal_handle_t audio_hal, int *volume);
#ifdef __cplusplus
}
#endif
#endif //__AUDIO_HAL_H__

View File

@@ -0,0 +1,2 @@
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
COMPONENT_EMBED_TXTFILES := test.pcm

Binary file not shown.

View File

@@ -0,0 +1,189 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "audio_hal.h"
#include "audio_mem.h"
#include "board.h"
#include "driver/gpio.h"
#include "driver/i2s.h"
#include "es8311.h"
#include "es8388.h"
#include "esp_log.h"
#include "unity.h"
#include "zl38063.h"
#define TEST_I2S_NUM I2S_NUM_0
static const char *TAG = "TEST_AUDIO_HAL";
extern const uint8_t test_pcm_start[] asm("_binary_test_pcm_start");
extern const uint8_t test_pcm_end[] asm("_binary_test_pcm_end");
static void
i2s_init ()
{
i2s_config_t i2s_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX,
.sample_rate = 16000,
.bits_per_sample = 16,
.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_driver_install (TEST_I2S_NUM, &i2s_cfg, 0, NULL);
i2s_pin_config_t i2s_pin_cfg = { 0 };
get_i2s_pins (TEST_I2S_NUM, &i2s_pin_cfg);
i2s_set_pin (TEST_I2S_NUM, &i2s_pin_cfg);
i2s_mclk_gpio_select (TEST_I2S_NUM, GPIO_NUM_0);
}
static void
i2s_deinit ()
{
i2s_driver_uninstall (TEST_I2S_NUM);
}
TEST_CASE ("Usage test", "[audio_hal]")
{
ESP_LOGI (TAG, "Initialize i2s");
i2s_init ();
ESP_LOGI (TAG, "Start codec chip");
audio_board_handle_t board_handle = audio_board_init ();
TEST_ASSERT_NOT_NULL (board_handle);
TEST_ASSERT_FALSE (audio_hal_ctrl_codec (board_handle->audio_hal,
AUDIO_HAL_CODEC_MODE_DECODE,
AUDIO_HAL_CTRL_START));
ESP_LOGI (TAG, "Set codec volume");
TEST_ASSERT_FALSE (audio_hal_set_volume (board_handle->audio_hal, 65));
int volume = 0;
TEST_ASSERT_FALSE (audio_hal_get_volume (board_handle->audio_hal, &volume));
ESP_LOGI (TAG, "Get codec volume: %d", volume);
size_t bytes_written = 0;
ESP_LOGI (TAG, "Start to play music");
TEST_ASSERT_FALSE (i2s_write (TEST_I2S_NUM, test_pcm_start,
test_pcm_end - test_pcm_start, &bytes_written,
portMAX_DELAY));
ESP_LOGW (TAG, "Reach the end of music, release all resource");
TEST_ASSERT_FALSE (audio_board_deinit (board_handle));
i2c_driver_delete (I2C_NUM_0);
i2s_deinit ();
}
/*
* To run this case, please choose Lyrat_v4.3 in menuconfig and run on
* lyrat_v4.3 board
*/
TEST_CASE ("Test for es8388 driver", "[audio_hal]")
{
ESP_LOGI (TAG, "Initialize i2s");
i2s_init ();
ESP_LOGI (TAG, "Start es8388 codec chip");
audio_hal_codec_config_t es8388_cfg = AUDIO_CODEC_DEFAULT_CONFIG ();
TEST_ASSERT_FALSE (es8388_init (&es8388_cfg));
TEST_ASSERT_FALSE (
es8388_config_i2s (es8388_cfg.codec_mode, &es8388_cfg.i2s_iface));
TEST_ASSERT_FALSE (
es8388_ctrl_state (AUDIO_HAL_CODEC_MODE_BOTH, AUDIO_HAL_CTRL_START));
TEST_ASSERT_FALSE (es8388_set_voice_volume (50));
size_t bytes_written = 0;
ESP_LOGI (TAG, "Start to play music");
TEST_ASSERT_FALSE (i2s_write (TEST_I2S_NUM, test_pcm_start,
test_pcm_end - test_pcm_start, &bytes_written,
portMAX_DELAY));
ESP_LOGW (TAG, "Reach the end of music, release all resource");
i2c_driver_delete (I2C_NUM_0);
i2s_deinit ();
}
/*
* To run this case, please choose Lyrat_mini in menuconfig and run on
* lyrat_mini board
*/
TEST_CASE ("Test for es8311 driver", "[audio_hal]")
{
ESP_LOGI (TAG, "Initialize i2s");
i2s_init ();
ESP_LOGI (TAG, "Start es8311 codec chip");
audio_hal_codec_config_t es8311_cfg = AUDIO_CODEC_DEFAULT_CONFIG ();
TEST_ASSERT_FALSE (es8311_codec_init (&es8311_cfg));
TEST_ASSERT_FALSE (
es8311_codec_config_i2s (es8311_cfg.codec_mode, &es8311_cfg.i2s_iface));
TEST_ASSERT_FALSE (es8311_codec_ctrl_state (AUDIO_HAL_CODEC_MODE_BOTH,
AUDIO_HAL_CTRL_START));
TEST_ASSERT_FALSE (es8311_codec_set_voice_volume (50));
size_t bytes_written = 0;
ESP_LOGI (TAG, "Start to play music");
TEST_ASSERT_FALSE (i2s_write (TEST_I2S_NUM, test_pcm_start,
test_pcm_end - test_pcm_start, &bytes_written,
portMAX_DELAY));
ESP_LOGW (TAG, "Reach the end of music, release all resource");
i2c_driver_delete (I2C_NUM_0);
i2s_deinit ();
}
/*
* To run this case, please choose LyratD_MSC in menuconfig and run on
* lyratD_MSC board
*/
TEST_CASE ("Test for zl38063 driver", "[audio_hal]")
{
ESP_LOGI (TAG, "Initialize i2s");
i2s_init ();
ESP_LOGI (TAG, "Start zl38063 DSP");
audio_hal_codec_config_t zl38063_cfg = AUDIO_CODEC_DEFAULT_CONFIG ();
TEST_ASSERT_FALSE (zl38063_codec_init (&zl38063_cfg));
TEST_ASSERT_FALSE (zl38063_codec_config_i2s (zl38063_cfg.codec_mode,
&zl38063_cfg.i2s_iface));
TEST_ASSERT_FALSE (zl38063_codec_ctrl_state (AUDIO_HAL_CODEC_MODE_BOTH,
AUDIO_HAL_CTRL_START));
TEST_ASSERT_FALSE (zl38063_codec_set_voice_volume (50));
size_t bytes_written = 0;
ESP_LOGI (TAG, "Start to play music");
TEST_ASSERT_FALSE (i2s_write (TEST_I2S_NUM, test_pcm_start,
test_pcm_end - test_pcm_start, &bytes_written,
portMAX_DELAY));
ESP_LOGW (TAG, "Reach the end of music, release all resource");
i2c_driver_delete (I2C_NUM_0);
i2s_deinit ();
}

View File

@@ -0,0 +1,9 @@
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_SRCS "audio_mem.c"
"audio_sys.c"
"audio_thread.c"
"audio_url.c")
register_component()

View File

@@ -0,0 +1,194 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "audio_mem.h"
#include "esp_efuse.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_system.h"
#include "sdkconfig.h"
#include "string.h"
#include <stdlib.h>
// #define ENABLE_AUDIO_MEM_TRACE
void *
audio_malloc (size_t size)
{
void *data = NULL;
#if CONFIG_SPIRAM_BOOT_INIT
data = heap_caps_malloc (size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
#else
data = malloc (size);
#endif
#ifdef ENABLE_AUDIO_MEM_TRACE
ESP_LOGI ("AUDIO_MEM", "malloc:%p, size:%d, called:0x%08x", data, size,
(intptr_t)__builtin_return_address (0) - 2);
#endif
return data;
}
void
audio_free (void *ptr)
{
free (ptr);
#ifdef ENABLE_AUDIO_MEM_TRACE
ESP_LOGI ("AUIDO_MEM", "free:%p, called:0x%08x", ptr,
(intptr_t)__builtin_return_address (0) - 2);
#endif
}
void *
audio_calloc (size_t nmemb, size_t size)
{
void *data = NULL;
#if CONFIG_SPIRAM_BOOT_INIT
data = heap_caps_malloc (nmemb * size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
if (data)
{
memset (data, 0, nmemb * size);
}
#else
data = calloc (nmemb, size);
#endif
#ifdef ENABLE_AUDIO_MEM_TRACE
ESP_LOGI ("AUIDO_MEM", "calloc:%p, size:%d, called:0x%08x", data, size,
(intptr_t)__builtin_return_address (0) - 2);
#endif
return data;
}
void *
audio_realloc (void *ptr, size_t size)
{
void *p = NULL;
#if CONFIG_SPIRAM_BOOT_INIT
p = heap_caps_realloc (ptr, size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
#else
p = heap_caps_realloc (ptr, size, MALLOC_CAP_8BIT);
#endif
#ifdef ENABLE_AUDIO_MEM_TRACE
ESP_LOGI ("AUDIO_MEM", "realloc,new:%p, ptr:%p size:%d, called:0x%08x", p,
ptr, size, (intptr_t)__builtin_return_address (0) - 2);
#endif
return p;
}
char *
audio_strdup (const char *str)
{
#if CONFIG_SPIRAM_BOOT_INIT
char *copy = heap_caps_malloc (strlen (str) + 1,
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
#else
char *copy = malloc (strlen (str) + 1);
#endif
if (copy)
{
strcpy (copy, str);
}
#ifdef ENABLE_AUDIO_MEM_TRACE
ESP_LOGI ("AUDIO_MEM", "strdup:%p, size:%d, called:0x%08x", copy,
strlen (copy), (intptr_t)__builtin_return_address (0) - 2);
#endif
return copy;
}
void *
audio_calloc_inner (size_t n, size_t size)
{
void *data = NULL;
#if CONFIG_SPIRAM_BOOT_INIT
data = heap_caps_calloc_prefer (
n, size, 2, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT,
MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM);
#else
data = heap_caps_calloc (n, size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
#endif
#ifdef ENABLE_AUDIO_MEM_TRACE
ESP_LOGI ("AUIDO_MEM", "calloc_inner:%p, size:%d, called:0x%08x", data, size,
(intptr_t)__builtin_return_address (0) - 2);
#endif
return data;
}
void
audio_mem_print (const char *tag, int line, const char *func)
{
#ifdef CONFIG_SPIRAM_BOOT_INIT
ESP_LOGI (tag,
"Func:%s, Line:%d, MEM Total:%d Bytes, Inter:%d Bytes, Dram:%d "
"Bytes\r\n",
func, line, esp_get_free_heap_size (),
heap_caps_get_free_size (MALLOC_CAP_INTERNAL),
heap_caps_get_free_size (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT));
#else
ESP_LOGI (tag, "Func:%s, Line:%d, MEM Total:%d Bytes\r\n", func, line,
esp_get_free_heap_size ());
#endif
}
#if defined(CONFIG_SPIRAM_BOOT_INIT)
bool
audio_mem_spiram_is_enabled (void)
{
return true;
}
#else
bool
audio_mem_spiram_is_enabled (void)
{
return false;
}
#endif
#if defined(CONFIG_SPIRAM_BOOT_INIT) \
&& (CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY)
bool
audio_mem_spiram_stack_is_enabled (void)
{
bool ret = true;
#if CONFIG_IDF_TARGET_ESP32
uint8_t chip_ver = esp_efuse_get_chip_ver ();
if (chip_ver < 3)
{
ESP_LOGW (
"AUIDO_MEM",
"Can't support stack on external memory due to ESP32 chip is %d",
chip_ver);
ret = false;
}
#endif
return ret;
}
#else
bool
audio_mem_spiram_stack_is_enabled (void)
{
return false;
}
#endif

View File

@@ -0,0 +1,197 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "audio_sys.h"
#include "audio_error.h"
#include "audio_mem.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "soc/soc_memory_layout.h"
#include <sys/time.h>
static const char *TAG = "AUDIO_SYS";
#define ARRAY_SIZE_OFFSET \
8 // Increase this if audio_sys_get_real_time_stats returns
// ESP_ERR_INVALID_SIZE
#define AUDIO_SYS_TASKS_ELAPSED_TIME_MS 1000 // Period of stats measurement
const char *task_state[]
= { "Running", "Ready", "Blocked", "Suspended", "Deleted" };
/** @brief
* "Extr": Allocated task stack from psram, "Intr": Allocated task stack from
* internel
*/
const char *task_stack[] = { "Extr", "Intr" };
int
audio_sys_get_tick_by_time_ms (int ms)
{
return (ms / portTICK_PERIOD_MS);
}
int64_t
audio_sys_get_time_ms (void)
{
struct timeval te;
gettimeofday (&te, NULL);
int64_t milliseconds = te.tv_sec * 1000LL + te.tv_usec / 1000;
return milliseconds;
}
esp_err_t
audio_sys_get_real_time_stats (void)
{
#if (CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID \
&& CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS)
TaskStatus_t *start_array = NULL, *end_array = NULL;
UBaseType_t start_array_size, end_array_size;
uint32_t start_run_time, end_run_time;
uint32_t task_elapsed_time, percentage_time;
esp_err_t ret;
// Allocate array to store current task states
start_array_size = uxTaskGetNumberOfTasks () + ARRAY_SIZE_OFFSET;
start_array = audio_malloc (sizeof (TaskStatus_t) * start_array_size);
AUDIO_MEM_CHECK (TAG, start_array, {
ret = ESP_FAIL;
goto exit;
});
// Get current task states
start_array_size
= uxTaskGetSystemState (start_array, start_array_size, &start_run_time);
if (start_array_size == 0)
{
ESP_LOGE (TAG, "Insufficient array size for uxTaskGetSystemState. "
"Trying increasing ARRAY_SIZE_OFFSET");
ret = ESP_FAIL;
goto exit;
}
vTaskDelay (pdMS_TO_TICKS (AUDIO_SYS_TASKS_ELAPSED_TIME_MS));
// Allocate array to store tasks states post delay
end_array_size = uxTaskGetNumberOfTasks () + ARRAY_SIZE_OFFSET;
end_array = audio_malloc (sizeof (TaskStatus_t) * end_array_size);
AUDIO_MEM_CHECK (TAG, start_array, {
ret = ESP_FAIL;
goto exit;
});
// Get post delay task states
end_array_size
= uxTaskGetSystemState (end_array, end_array_size, &end_run_time);
if (end_array_size == 0)
{
ESP_LOGE (TAG, "Insufficient array size for uxTaskGetSystemState. "
"Trying increasing ARRAY_SIZE_OFFSET");
ret = ESP_FAIL;
goto exit;
}
// Calculate total_elapsed_time in units of run time stats clock period.
uint32_t total_elapsed_time = (end_run_time - start_run_time);
if (total_elapsed_time == 0)
{
ESP_LOGE (TAG, "Delay duration too short. Trying increasing "
"AUDIO_SYS_TASKS_ELAPSED_TIME_MS");
ret = ESP_FAIL;
goto exit;
}
ESP_LOGI (TAG, "| Task | Run Time | Per | Prio | HWM "
"| State | CoreId | Stack ");
// Match each task in start_array to those in the end_array
for (int i = 0; i < start_array_size; i++)
{
for (int j = 0; j < end_array_size; j++)
{
if (start_array[i].xHandle == end_array[j].xHandle)
{
task_elapsed_time = end_array[j].ulRunTimeCounter
- start_array[i].ulRunTimeCounter;
percentage_time = (task_elapsed_time * 100UL)
/ (total_elapsed_time * portNUM_PROCESSORS);
ESP_LOGI (
TAG,
"| %-17s | %-11d |%2d%% | %-4u | %-9u | %-7s | %-8x | %s",
start_array[i].pcTaskName, task_elapsed_time,
percentage_time, start_array[i].uxCurrentPriority,
start_array[i].usStackHighWaterMark,
task_state[(start_array[i].eCurrentState)],
start_array[i].xCoreID,
task_stack[esp_ptr_internal (
pxTaskGetStackStart (start_array[i].xHandle))]);
// Mark that task have been matched by overwriting their handles
start_array[i].xHandle = NULL;
end_array[j].xHandle = NULL;
break;
}
}
}
// Print unmatched tasks
for (int i = 0; i < start_array_size; i++)
{
if (start_array[i].xHandle != NULL)
{
ESP_LOGI (TAG, "| %s | Deleted", start_array[i].pcTaskName);
}
}
for (int i = 0; i < end_array_size; i++)
{
if (end_array[i].xHandle != NULL)
{
ESP_LOGI (TAG, "| %s | Created", end_array[i].pcTaskName);
}
}
printf ("\n");
ret = ESP_OK;
exit: // Common return path
if (start_array)
{
audio_free (start_array);
start_array = NULL;
}
if (end_array)
{
audio_free (end_array);
end_array = NULL;
}
return ret;
#else
ESP_LOGW (TAG,
"Please enbale `CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID` and "
"`CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS` in menuconfig");
return ESP_FAIL;
#endif
}

View File

@@ -0,0 +1,122 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "audio_error.h"
#include "audio_mem.h"
#include "audio_thread.h"
#include "esp_log.h"
static const char *TAG = "AUDIO_THREAD";
BaseType_t __attribute__ ((weak)) xTaskCreateRestrictedPinnedToCore (
const TaskParameters_t *const pxTaskDefinition,
TaskHandle_t *pxCreatedTask, const BaseType_t xCoreID)
{
ESP_LOGE (TAG,
"Not found right %s.\r\nPlease enter IDF-PATH with \"cd "
"$IDF_PATH\" and apply the IDF patch with \"git apply "
"$ADF_PATH/idf_patches/idf_v3.3_freertos.patch\" first\r\n",
__func__);
return pdFALSE;
}
esp_err_t
audio_thread_create (audio_thread_t *p_handle, const char *name,
void (*main_func) (void *arg), void *arg, uint32_t stack,
int prio, bool stack_in_ext, int core_id)
{
StackType_t *task_stack = NULL;
if (stack_in_ext && audio_mem_spiram_stack_is_enabled ())
{
/*
* Note: 1. ESP32-ECO3 chip support stack on external memory only.
* 2. Make sure selected the `CONFIG_SPIRAM_BOOT_INIT` and
* `CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY` by `make menuconfig`
* 3. Please apply the
* $ADF_PATH/idf_patches/idf_v3.3_freertos.patch
*
*/
ESP_LOGI (TAG, "The %s task allocate stack on external memory", name);
/* task_stack freed by freertos*/
task_stack = (StackType_t *)audio_calloc (1, stack);
AUDIO_MEM_CHECK (TAG, task_stack, goto audio_thread_create_error);
TaskParameters_t xRegParameters
= { .pvTaskCode = main_func,
.pcName = name,
.usStackDepth = stack,
.pvParameters = arg,
.uxPriority = prio | portPRIVILEGE_BIT,
.puxStackBuffer = task_stack,
.xRegions = { {
.pvBaseAddress = 0x00,
.ulLengthInBytes = 0x00,
.ulParameters = 0x00,
} } };
if (xTaskCreateRestrictedPinnedToCore (&xRegParameters,
(xTaskHandle)p_handle, core_id)
!= pdPASS)
{
ESP_LOGE (TAG, "Error creating RestrictedPinnedToCore %s", name);
goto audio_thread_create_error;
}
}
else
{
if (xTaskCreatePinnedToCore (main_func, name, stack, arg, prio,
(xTaskHandle)p_handle, core_id)
!= pdPASS)
{
ESP_LOGE (TAG, "Error creating task %s", name);
goto audio_thread_create_error;
}
}
return ESP_OK;
audio_thread_create_error:
if (task_stack)
{
audio_free (task_stack);
}
return ESP_FAIL;
}
esp_err_t
audio_thread_cleanup (audio_thread_t *p_handle)
{
// TODO nothing
return ESP_OK;
}
esp_err_t
audio_thread_delete_task (audio_thread_t *p_handle)
{
vTaskDelete (NULL);
return ESP_OK; /* Control never reach here if this is self delete */
}

View File

@@ -0,0 +1,66 @@
#include "audio_error.h"
#include "audio_mem.h"
#include "esp_log.h"
#include <ctype.h>
#include <string.h>
static char *TAG = "AUDIO_URL";
static unsigned char
char_to_hex (unsigned char x)
{
return x > 9 ? x + 0x37 : x + 0x30;
}
char *
audio_url_encode (const char *str)
{
int out_len = (strlen (str) + 1) * 3;
char *final = audio_malloc (out_len);
AUDIO_MEM_CHECK (TAG, final, return NULL);
char *tmp = final;
for (size_t i = 0; i < strlen (str); i++)
{
if (isalnum ((unsigned char)str[i]) || (str[i] == '-') || (str[i] == '_')
|| (str[i] == '.') || (str[i] == '!') || (str[i] == '@')
|| (str[i] == '#') || (str[i] == '$') || (str[i] == '&')
|| (str[i] == '*') || (str[i] == '(') || (str[i] == ')')
|| (str[i] == '=') || (str[i] == ':') || (str[i] == '/')
|| (str[i] == ',') || (str[i] == ';') || (str[i] == '?')
|| (str[i] == '+') || (str[i] == '\'') || (str[i] == '~'))
{
*final++ = str[i];
}
else
{
*final++ = '%';
*final++ = char_to_hex ((unsigned char)str[i] >> 4);
*final++ = char_to_hex ((unsigned char)str[i] % 16);
}
}
*final = 0;
return tmp;
}
char *
audio_url_decode (const char *str)
{
char *final = audio_malloc (strlen (str) + 1);
AUDIO_MEM_CHECK (TAG, final, return NULL);
char *tmp = final;
while (*str)
{
if (*str == '%')
{
char buffer[3] = { str[1], str[2], 0 };
*final++ = strtol (buffer, NULL, 16);
str += 3;
}
else
{
*final++ = *str++;
}
}
*final = 0;
return tmp;
}

View File

@@ -0,0 +1,6 @@
#
# Component Makefile
COMPONENT_ADD_INCLUDEDIRS := . ./include
COMPONENT_SRCDIRS := .

View File

@@ -0,0 +1,93 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _AUDIO_ERROR_H_
#define _AUDIO_ERROR_H_
#include "esp_err.h"
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef __FILENAME__
#define __FILENAME__ __FILE__
#endif
#define ESP_ERR_ADF_BASE \
0x80000 /*!< Starting number of ESP-ADF error codes \
*/
/*
* ESP-ADF error code field start from 0x80000, end of the -1.
* The whole area is divided into series independent modules.
* The range of each module is 0x1000.
* //////////////////////////////////////////////////////////
* ESP-Audio module starting on 0x81000;
*
*/
#define ESP_ERR_ADF_NO_ERROR ESP_OK
#define ESP_ERR_ADF_NO_FAIL ESP_FAIL
#define ESP_ERR_ADF_UNKNOWN ESP_ERR_ADF_BASE + 0
#define ESP_ERR_ADF_ALREADY_EXISTS ESP_ERR_ADF_BASE + 1
#define ESP_ERR_ADF_MEMORY_LACK ESP_ERR_ADF_BASE + 2
#define ESP_ERR_ADF_INVALID_URI ESP_ERR_ADF_BASE + 3
#define ESP_ERR_ADF_INVALID_PATH ESP_ERR_ADF_BASE + 4
#define ESP_ERR_ADF_INVALID_PARAMETER ESP_ERR_ADF_BASE + 5
#define ESP_ERR_ADF_NOT_READY ESP_ERR_ADF_BASE + 6
#define ESP_ERR_ADF_NOT_SUPPORT ESP_ERR_ADF_BASE + 7
#define ESP_ERR_ADF_NOT_FOUND ESP_ERR_ADF_BASE + 8
#define ESP_ERR_ADF_TIMEOUT ESP_ERR_ADF_BASE + 9
#define ESP_ERR_ADF_INITIALIZED ESP_ERR_ADF_BASE + 10
#define ESP_ERR_ADF_UNINITIALIZED ESP_ERR_ADF_BASE + 11
#define AUDIO_CHECK(TAG, a, action, msg) \
if (!(a)) \
{ \
ESP_LOGE (TAG, "%s:%d (%s): %s", __FILENAME__, __LINE__, __FUNCTION__, \
msg); \
action; \
}
#define AUDIO_MEM_CHECK(TAG, a, action) \
AUDIO_CHECK (TAG, a, action, "Memory exhausted")
#define AUDIO_NULL_CHECK(TAG, a, action) \
AUDIO_CHECK (TAG, a, action, "Got NULL Pointer")
#define AUDIO_ERROR(TAG, str) \
ESP_LOGE (TAG, "%s:%d (%s): %s", __FILENAME__, __LINE__, __FUNCTION__, str)
#define ESP_EXISTS (ESP_OK + 1)
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,146 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _AUDIO_MEM_H_
#define _AUDIO_MEM_H_
#include <esp_types.h>
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Malloc memory in ADF
*
* @param[in] size memory size
*
* @return
* - valid pointer on success
* - NULL when any errors
*/
void *audio_malloc (size_t size);
/**
* @brief Free memory in ADF
*
* @param[in] ptr memory pointer
*
* @return
* - void
*/
void audio_free (void *ptr);
/**
* @brief Malloc memory in ADF, if spi ram is enabled, it will malloc memory
* in the spi ram
*
* @param[in] nmemb number of block
* @param[in] size block memory size
*
* @return
* - valid pointer on success
* - NULL when any errors
*/
void *audio_calloc (size_t nmemb, size_t size);
/**
* @brief Malloc memory in ADF, it will malloc to internal memory
*
* @param[in] nmemb number of block
* @param[in] size block memory size
*
* @return
* - valid pointer on success
* - NULL when any errors
*/
void *audio_calloc_inner (size_t nmemb, size_t size);
/**
* @brief Print heap memory status
*
* @param[in] tag tag of log
* @param[in] line line of log
* @param[in] func function name of log
*
* @return
* - void
*/
void audio_mem_print (const char *tag, int line, const char *func);
/**
* @brief Reallocate memory in ADF, if spi ram is enabled, it will allocate
* memory in the spi ram
*
* @param[in] ptr memory pointer
* @param[in] size block memory size
*
* @return
* - valid pointer on success
* - NULL when any errors
*/
void *audio_realloc (void *ptr, size_t size);
/**
* @brief Duplicate given string.
*
* Allocate new memory, copy contents of given string into it and
* return the pointer
*
* @param[in] str String to be duplicated
*
* @return
* - Pointer to new malloc'ed string
* - NULL otherwise
*/
char *audio_strdup (const char *str);
/**
* @brief SPI ram is enabled or not
*
* @return
* - true, spi ram is enabled
* - false, spi ram is not enabled
*/
bool audio_mem_spiram_is_enabled (void);
/**
* @brief Stack on external SPI ram is enabled or not
*
* @return
* - true, stack on spi ram is enabled
* - false, stack on spi ram is not enabled
*/
bool audio_mem_spiram_stack_is_enabled (void);
#define AUDIO_MEM_SHOW(x) audio_mem_print (x, __LINE__, __func__)
#ifdef __cplusplus
}
#endif
#endif /*_AUDIO_MEM_H_*/

View File

@@ -0,0 +1,50 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _AUDIO_MUTEX_H_
#define _AUDIO_MUTEX_H_
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define mutex_lock(x) \
while (xSemaphoreTake (x, portMAX_DELAY) != pdPASS) \
;
#define mutex_unlock(x) xSemaphoreGive (x)
#define mutex_create() xSemaphoreCreateMutex ()
#define mutex_destroy(x) vSemaphoreDelete (x)
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,84 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _AUDIO_SYS_H_
#define _AUDIO_SYS_H_
#include "esp_err.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define ___STR___(x) #x
#define STR_AUDIO(x) ___STR___ (x)
/**
* @brief Get system ticks by given millisecond
*
* @param[in] ms millisecond
*
* @return
* - tick
*/
int audio_sys_get_tick_by_time_ms (int ms);
/**
* @brief Get system time with millisecond
*
* @return
* - time with millisecond
*/
int64_t audio_sys_get_time_ms (void);
/**
* @brief Function to print the CPU usage of tasks over a given
* AUDIO_SYS_TASKS_ELAPSED_TIME_MS.
*
* This function will measure and print the CPU usage of tasks over a
* specified number of ticks (i.e. real time stats). This is implemented by
* simply calling uxTaskGetSystemState() twice separated by a delay, then
* calculating the differences of task run times before and after the delay.
*
* @note If any tasks are added or removed during the delay, the stats of
* those tasks will not be printed.
* @note This function should be called from a high priority task to
* minimize inaccuracies with delays.
* @note When running in dual core mode, each core will correspond to 50%
* of the run time.
*
* @return
* - ESP_OK
* - ESP_FIAL
*/
esp_err_t audio_sys_get_real_time_stats (void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,97 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _AUDIO_THREAD_H_
#define _AUDIO_THREAD_H_
#include "esp_err.h"
#include "stdbool.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define audio_thread_t xTaskHandle
/**
* @brief Allocate handle if not allocated and create a thread
*
* @param p_handle pointer to audio_thread_t handle
* @param name Task name
* @param main_func The function which task will execute
* @param stack Task stack
* @param prio Task priority
* @param stack_in_ext If task should reside in external memory
* @param core_id Core to which task will be pinned
*
* @return - ESP_OK : Task creation successful
* - ESP_FAIL: Failed to create task
*
* @note - Please apply the
* $ADF_PATH/idf_patches/idf_v3.3/4.x_freertos.patch first.
* - Please enable support for external RAM and `Allow external
* memory as an argument to xTaskCreateStatic` to be able to use external
* memory for task stack, namely `CONFIG_SPIRAM_BOOT_INIT=y` and
* `CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y`.
*
*/
esp_err_t audio_thread_create (audio_thread_t *p_handle, const char *name,
void (*main_func) (void *arg), void *arg,
uint32_t stack, int prio, bool stack_in_ext,
int core_id);
/**
* @brief Cleanup all the task memory
*
* @param p_handle The pointer to audio_thread_t handle
*
* @return - ESP_OK : Task cleanup successful
* - ESP_FAIL: Task is already cleaned up
*
* @note must be called from different task after this task is
* deleted.
*/
esp_err_t audio_thread_cleanup (audio_thread_t *p_handle);
/**
* @brief Delete the task
*
* @param p_handle The pointer to audio_thread_t handle
*
* @return - ESP_OK : Task deleted successfully
* - ESP_FAIL: Task is not running or cleaned up
*
* @note This only deletes the task and all the memory cleanup should
* be done with `audio_thread_cleanup`
*/
esp_err_t audio_thread_delete_task (audio_thread_t *p_handle);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _AUDIO_THREAD_H_ */

View File

@@ -0,0 +1,69 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef __AUDIO_URL_H__
#define __AUDIO_URL_H__
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Allocate new memory, encoding given string to percent-encoding and
* return the pointer
*
* @note Returned pointer should be freed by user.
* ALPHA(0x41-0x5A and 0x61-0x7A), DIGIT (0x30-0x39) and
* "~!@#$&*()=:/,;?+'-_." are reserved.
*
* @param str String to be encode
*
* @return
* - valid pointer on success
* - NULL when any errors
*/
char *audio_url_encode (const char *str);
/**
* @brief Allocate new memory, decoding given percent-encoding string and
* return the pointer
*
* @note Returned pointer should be freed by user
*
* @param str String to be decode
*
* @return
* - valid pointer on success
* - NULL when any errors
*/
char *audio_url_decode (const char *str);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,89 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "audio_mem.h"
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "unity.h"
#include <pthread.h>
static const char *TAG = "AUDIO_MEM_TEST";
TEST_CASE ("audio_mem", "esp-adf")
{
esp_log_level_set ("AUDIO_MEM", ESP_LOG_VERBOSE);
ESP_LOGI (TAG, "[✓] audio_malloc,audio_callo,audio_calloc_inner, "
"audio_inaudio memory print");
AUDIO_MEM_SHOW (TAG);
uint8_t *pdata = audio_malloc (1024);
TEST_ASSERT_NOT_NULL (pdata);
AUDIO_MEM_SHOW (TAG);
audio_free (pdata);
AUDIO_MEM_SHOW (TAG);
pdata = audio_calloc (1, 2 * 1024 * 1024);
TEST_ASSERT_NOT_NULL (pdata);
AUDIO_MEM_SHOW (TAG);
audio_free (pdata);
AUDIO_MEM_SHOW (TAG);
pdata = audio_calloc_inner (1, 1024);
TEST_ASSERT_NOT_NULL (pdata);
AUDIO_MEM_SHOW (TAG);
audio_free (pdata);
AUDIO_MEM_SHOW (TAG);
}
TEST_CASE ("audio_strdup", "esp-adf")
{
esp_log_level_set ("AUDIO_STRDUP", ESP_LOG_VERBOSE);
ESP_LOGI (TAG, "[✓] audio_strdup");
AUDIO_MEM_SHOW (TAG);
char *strings = "audio string dump";
char *pdata = audio_strdup (strings);
TEST_ASSERT_NOT_NULL (pdata);
AUDIO_MEM_SHOW (TAG);
audio_free (pdata);
AUDIO_MEM_SHOW (TAG);
}
TEST_CASE ("audio_realloc", "esp-adf")
{
esp_log_level_set ("AUDIO_REALLOC", ESP_LOG_VERBOSE);
ESP_LOGI (TAG, "[✓] audio_realloc");
AUDIO_MEM_SHOW (TAG);
uint8_t *pdata = audio_malloc (1024);
TEST_ASSERT_NOT_NULL (pdata);
AUDIO_MEM_SHOW (TAG);
pdata = audio_realloc (pdata, 2 * 1024);
TEST_ASSERT_NOT_NULL (pdata);
AUDIO_MEM_SHOW (TAG);
audio_free (pdata);
AUDIO_MEM_SHOW (TAG);
}

View File

@@ -0,0 +1,5 @@
#
#Component Makefile
#
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

View File

@@ -1,6 +1,6 @@
# Edit following two lines to set component requirements (see docs)
set(COMPONENT_REQUIRES)
set(COMPONENT_PRIV_REQUIRES audio_hal esp_dispatcher esp_peripherals display_service)
set(COMPONENT_PRIV_REQUIRES audio_hal esp_peripherals)
if(CONFIG_AUDIO_BOARD_CUSTOM)
message(STATUS "Current board name is " CONFIG_AUDIO_BOARD_CUSTOM)

View File

@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Modifications copyright (C) 2021 CarlosDerSeher
#include <esp_types.h>
#include <math.h>
#include <stdbool.h>

View File

@@ -12,326 +12,367 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Modifications copyright (C) 2021 CarlosDerSeher
#pragma once
#include "esp_types.h"
#include "driver/periph_ctrl.h"
#include "esp_err.h"
#include "esp_intr_alloc.h"
#include "esp_types.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "hal/i2s_hal.h"
#include "hal/i2s_types.h"
#include "soc/i2s_periph.h"
#include "soc/rtc_periph.h"
#include "soc/soc_caps.h"
#include "hal/i2s_hal.h"
#include "hal/i2s_types.h"
#include "driver/periph_ctrl.h"
#include "esp_intr_alloc.h"
#ifdef __cplusplus
extern "C" {
extern "C"
{
#endif
#define I2S_PIN_NO_CHANGE (-1) /*!< Use in i2s_pin_config_t for pins which should not be changed */
#define I2S_PIN_NO_CHANGE \
(-1) /*!< Use in i2s_pin_config_t for pins which should not be changed */
typedef intr_handle_t i2s_isr_handle_t;
typedef intr_handle_t i2s_isr_handle_t;
/**
* @brief Set I2S pin number
*
* @note
* The I2S peripheral output signals can be connected to multiple GPIO pads.
* However, the I2S peripheral input signal can only be connected to one GPIO pad.
*
* @param i2s_num I2S_NUM_0 or I2S_NUM_1
*
* @param pin I2S Pin structure, or NULL to set 2-channel 8-bit internal DAC pin configuration (GPIO25 & GPIO26)
*
* Inside the pin configuration structure, set I2S_PIN_NO_CHANGE for any pin where
* the current configuration should not be changed.
*
* @note if *pin is set as NULL, this function will initialize both of the built-in DAC channels by default.
* if you don't want this to happen and you want to initialize only one of the DAC channels, you can call i2s_set_dac_mode instead.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL IO error
*/
esp_err_t i2s_custom_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin);
/**
* @brief Set I2S pin number
*
* @note
* The I2S peripheral output signals can be connected to multiple GPIO pads.
* However, the I2S peripheral input signal can only be connected to one GPIO
* pad.
*
* @param i2s_num I2S_NUM_0 or I2S_NUM_1
*
* @param pin I2S Pin structure, or NULL to set 2-channel 8-bit
* internal DAC pin configuration (GPIO25 & GPIO26)
*
* Inside the pin configuration structure, set I2S_PIN_NO_CHANGE for any pin
* where the current configuration should not be changed.
*
* @note if *pin is set as NULL, this function will initialize both of the
* built-in DAC channels by default. if you don't want this to happen and you
* want to initialize only one of the DAC channels, you can call
* i2s_set_dac_mode instead.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_FAIL IO error
*/
esp_err_t i2s_custom_set_pin (i2s_port_t i2s_num,
const i2s_pin_config_t *pin);
#if SOC_I2S_SUPPORTS_PDM
/**
* @brief Set PDM mode down-sample rate
* In PDM RX mode, there would be 2 rounds of downsample process in hardware.
* In the first downsample process, the sampling number can be 16 or 8.
* In the second downsample process, the sampling number is fixed as 8.
* So the clock frequency in PDM RX mode would be (fpcm * 64) or (fpcm * 128) accordingly.
* @param i2s_num I2S_NUM_0, I2S_NUM_1
* @param dsr i2s RX down sample rate for PDM mode.
*
* @note After calling this function, it would call i2s_set_clk inside to update the clock frequency.
* Please call this function after I2S driver has been initialized.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t i2s_custom_set_pdm_rx_down_sample(i2s_port_t i2s_num, i2s_pdm_dsr_t dsr);
/**
* @brief Set PDM mode down-sample rate
* In PDM RX mode, there would be 2 rounds of downsample process in
* hardware. In the first downsample process, the sampling number can be 16
* or 8. In the second downsample process, the sampling number is fixed as 8.
* So the clock frequency in PDM RX mode would be (fpcm * 64) or (fpcm
* * 128) accordingly.
* @param i2s_num I2S_NUM_0, I2S_NUM_1
* @param dsr i2s RX down sample rate for PDM mode.
*
* @note After calling this function, it would call i2s_set_clk inside to
* update the clock frequency. Please call this function after I2S driver has
* been initialized.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t i2s_custom_set_pdm_rx_down_sample (i2s_port_t i2s_num,
i2s_pdm_dsr_t dsr);
#endif
/**
* @brief Set I2S dac mode, I2S built-in DAC is disabled by default
*
* @param dac_mode DAC mode configurations - see i2s_dac_mode_t
*
* @note Built-in DAC functions are only supported on I2S0 for current ESP32 chip.
* If either of the built-in DAC channel are enabled, the other one can not
* be used as RTC DAC function at the same time.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_set_dac_mode(i2s_dac_mode_t dac_mode);
/**
* @brief Set I2S dac mode, I2S built-in DAC is disabled by default
*
* @param dac_mode DAC mode configurations - see i2s_dac_mode_t
*
* @note Built-in DAC functions are only supported on I2S0 for current ESP32
* chip. If either of the built-in DAC channel are enabled, the other one can
* not be used as RTC DAC function at the same time.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_set_dac_mode (i2s_dac_mode_t dac_mode);
/**
* @brief Install and start I2S driver.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param i2s_config I2S configurations - see i2s_config_t struct
*
* @param queue_size I2S event queue size/depth.
*
* @param i2s_queue I2S event queue handle, if set NULL, driver will not use an event queue.
*
* This function must be called before any I2S driver read/write operations.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t i2s_custom_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void* i2s_queue);
/**
* @brief Install and start I2S driver.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param i2s_config I2S configurations - see i2s_config_t struct
*
* @param queue_size I2S event queue size/depth.
*
* @param i2s_queue I2S event queue handle, if set NULL, driver will
* not use an event queue.
*
* This function must be called before any I2S driver read/write operations.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t i2s_custom_driver_install (i2s_port_t i2s_num,
const i2s_config_t *i2s_config,
int queue_size, void *i2s_queue);
/**
* @brief Uninstall I2S driver.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_driver_uninstall(i2s_port_t i2s_num);
/**
* @brief Uninstall I2S driver.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_driver_uninstall (i2s_port_t i2s_num);
/**
* @brief Write data to I2S DMA transmit buffer.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param src Source address to write from
*
* @param size Size of data in bytes
*
* @param[out] bytes_written Number of bytes written, if timeout, the result will be less than the size passed in.
*
* @param ticks_to_wait TX buffer wait timeout in RTOS ticks. If this
* many ticks pass without space becoming available in the DMA
* transmit buffer, then the function will return (note that if the
* data is written to the DMA buffer in pieces, the overall operation
* may still take longer than this timeout.) Pass portMAX_DELAY for no
* timeout.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *bytes_written, TickType_t ticks_to_wait);
/**
* @brief Write data to I2S DMA transmit buffer.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param src Source address to write from
*
* @param size Size of data in bytes
*
* @param[out] bytes_written Number of bytes written, if timeout, the result
* will be less than the size passed in.
*
* @param ticks_to_wait TX buffer wait timeout in RTOS ticks. If this
* many ticks pass without space becoming available in the DMA
* transmit buffer, then the function will return (note that if the
* data is written to the DMA buffer in pieces, the overall operation
* may still take longer than this timeout.) Pass portMAX_DELAY for no
* timeout.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_write (i2s_port_t i2s_num, const void *src, size_t size,
size_t *bytes_written, TickType_t ticks_to_wait);
/**
* @brief Write data to I2S DMA transmit buffer while expanding the number of bits per sample. For example, expanding 16-bit PCM to 32-bit PCM.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param src Source address to write from
*
* @param size Size of data in bytes
*
* @param src_bits Source audio bit
*
* @param aim_bits Bit wanted, no more than 32, and must be greater than src_bits
*
* @param[out] bytes_written Number of bytes written, if timeout, the result will be less than the size passed in.
*
* @param ticks_to_wait TX buffer wait timeout in RTOS ticks. If this
* many ticks pass without space becoming available in the DMA
* transmit buffer, then the function will return (note that if the
* data is written to the DMA buffer in pieces, the overall operation
* may still take longer than this timeout.) Pass portMAX_DELAY for no
* timeout.
*
* Format of the data in source buffer is determined by the I2S
* configuration (see i2s_config_t).
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_write_expand(i2s_port_t i2s_num, const void *src, size_t size, size_t src_bits, size_t aim_bits, size_t *bytes_written, TickType_t ticks_to_wait);
/**
* @brief Write data to I2S DMA transmit buffer while expanding the number of
* bits per sample. For example, expanding 16-bit PCM to 32-bit PCM.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param src Source address to write from
*
* @param size Size of data in bytes
*
* @param src_bits Source audio bit
*
* @param aim_bits Bit wanted, no more than 32, and must be
* greater than src_bits
*
* @param[out] bytes_written Number of bytes written, if timeout, the result
* will be less than the size passed in.
*
* @param ticks_to_wait TX buffer wait timeout in RTOS ticks. If this
* many ticks pass without space becoming available in the DMA
* transmit buffer, then the function will return (note that if the
* data is written to the DMA buffer in pieces, the overall operation
* may still take longer than this timeout.) Pass portMAX_DELAY for no
* timeout.
*
* Format of the data in source buffer is determined by the I2S
* configuration (see i2s_config_t).
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_write_expand (i2s_port_t i2s_num, const void *src,
size_t size, size_t src_bits,
size_t aim_bits, size_t *bytes_written,
TickType_t ticks_to_wait);
/**
* @brief Read data from I2S DMA receive buffer
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param dest Destination address to read into
*
* @param size Size of data in bytes
*
* @param[out] bytes_read Number of bytes read, if timeout, bytes read will be less than the size passed in.
*
* @param ticks_to_wait RX buffer wait timeout in RTOS ticks. If this many ticks pass without bytes becoming available in the DMA receive buffer, then the function will return (note that if data is read from the DMA buffer in pieces, the overall operation may still take longer than this timeout.) Pass portMAX_DELAY for no timeout.
*
* @note If the built-in ADC mode is enabled, we should call i2s_adc_enable and i2s_adc_disable around the whole reading process,
* to prevent the data getting corrupted.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_read, TickType_t ticks_to_wait);
/**
* @brief Read data from I2S DMA receive buffer
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param dest Destination address to read into
*
* @param size Size of data in bytes
*
* @param[out] bytes_read Number of bytes read, if timeout, bytes read will
* be less than the size passed in.
*
* @param ticks_to_wait RX buffer wait timeout in RTOS ticks. If this many
* ticks pass without bytes becoming available in the DMA receive buffer,
* then the function will return (note that if data is read from the DMA
* buffer in pieces, the overall operation may still take longer than this
* timeout.) Pass portMAX_DELAY for no timeout.
*
* @note If the built-in ADC mode is enabled, we should call i2s_adc_enable
* and i2s_adc_disable around the whole reading process, to prevent the data
* getting corrupted.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_read (i2s_port_t i2s_num, void *dest, size_t size,
size_t *bytes_read, TickType_t ticks_to_wait);
/**
* @brief APLL calculate function, was described by following:
* APLL Output frequency is given by the formula:
*
* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2)
* apll_freq = fout / ((o_div + 2) * 2)
*
* The dividend in this expression should be in the range of 240 - 600 MHz.
* In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0.
* * sdm0 frequency adjustment parameter, 0..255
* * sdm1 frequency adjustment parameter, 0..255
* * sdm2 frequency adjustment parameter, 0..63
* * o_div frequency divider, 0..31
*
* The most accurate way to find the sdm0..2 and odir parameters is to loop through them all,
* then apply the above formula, finding the closest frequency to the desired one.
* But 256*256*64*32 = 134.217.728 loops are too slow with ESP32
* 1. We will choose the parameters with the highest level of change,
* With 350MHz<fout<500MHz, we limit the sdm2 from 4 to 9,
* Take average frequency close to the desired frequency, and select sdm2
* 2. Next, we look for sequences of less influential and more detailed parameters,
* also by taking the average of the largest and smallest frequencies closer to the desired frequency.
* 3. And finally, loop through all the most detailed of the parameters, finding the best desired frequency
*
* @param[in] rate The I2S Frequency (MCLK)
* @param[in] bits_per_sample The bits per sample
* @param[out] sdm0 The sdm 0
* @param[out] sdm1 The sdm 1
* @param[out] sdm2 The sdm 2
* @param[out] odir The odir
*
* @return ESP_ERR_INVALID_ARG or ESP_OK
*/
/**
* @brief APLL calculate function, was described by following:
* APLL Output frequency is given by the formula:
*
* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 +
* sdm0/65536)/((o_div + 2) * 2) apll_freq = fout / ((o_div + 2) * 2)
*
* The dividend in this expression should be in the range of 240 -
* 600 MHz. In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0.
* * sdm0 frequency adjustment parameter, 0..255
* * sdm1 frequency adjustment parameter, 0..255
* * sdm2 frequency adjustment parameter, 0..63
* * o_div frequency divider, 0..31
*
* The most accurate way to find the sdm0..2 and odir parameters
* is to loop through them all, then apply the above formula, finding the
* closest frequency to the desired one. But 256*256*64*32 = 134.217.728
* loops are too slow with ESP32
* 1. We will choose the parameters with the highest level of
* change, With 350MHz<fout<500MHz, we limit the sdm2 from 4 to 9, Take
* average frequency close to the desired frequency, and select sdm2
* 2. Next, we look for sequences of less influential and more
* detailed parameters, also by taking the average of the largest and
* smallest frequencies closer to the desired frequency.
* 3. And finally, loop through all the most detailed of the
* parameters, finding the best desired frequency
*
* @param[in] rate The I2S Frequency (MCLK)
* @param[in] bits_per_sample The bits per sample
* @param[out] sdm0 The sdm 0
* @param[out] sdm1 The sdm 1
* @param[out] sdm2 The sdm 2
* @param[out] odir The odir
*
* @return ESP_ERR_INVALID_ARG or ESP_OK
*/
esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm0, int *sdm1, int *sdm2, int *odir);
esp_err_t i2s_apll_calculate_fi2s (int rate, int bits_per_sample, int *sdm0,
int *sdm1, int *sdm2, int *odir);
/**
* @brief Set sample rate used for I2S RX and TX.
*
* The bit clock rate is determined by the sample rate and i2s_config_t configuration parameters (number of channels, bits_per_sample).
*
* `bit_clock = rate * (number of channels) * bits_per_sample`
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param rate I2S sample rate (ex: 8000, 44100...)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t i2s_custom_set_sample_rates(i2s_port_t i2s_num, uint32_t rate);
/**
* @brief Set sample rate used for I2S RX and TX.
*
* The bit clock rate is determined by the sample rate and i2s_config_t
* configuration parameters (number of channels, bits_per_sample).
*
* `bit_clock = rate * (number of channels) * bits_per_sample`
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param rate I2S sample rate (ex: 8000, 44100...)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t i2s_custom_set_sample_rates (i2s_port_t i2s_num, uint32_t rate);
/**
* @brief Stop I2S driver
*
* There is no need to call i2s_stop() before calling i2s_driver_uninstall().
*
* Disables I2S TX/RX, until i2s_start() is called.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_stop(i2s_port_t i2s_num);
/**
* @brief Stop I2S driver
*
* There is no need to call i2s_stop() before calling i2s_driver_uninstall().
*
* Disables I2S TX/RX, until i2s_start() is called.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_stop (i2s_port_t i2s_num);
/**
* @brief Start I2S driver
*
* It is not necessary to call this function after i2s_driver_install() (it is started automatically), however it is necessary to call it after i2s_stop().
*
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_start(i2s_port_t i2s_num);
/**
* @brief Start I2S driver
*
* It is not necessary to call this function after i2s_driver_install() (it
* is started automatically), however it is necessary to call it after
* i2s_stop().
*
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_start (i2s_port_t i2s_num);
/**
* @brief Zero the contents of the TX DMA buffer.
*
* Pushes zero-byte samples into the TX DMA buffer, until it is full.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_zero_dma_buffer(i2s_port_t i2s_num);
/**
* @brief Zero the contents of the TX DMA buffer.
*
* Pushes zero-byte samples into the TX DMA buffer, until it is full.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t i2s_custom_zero_dma_buffer (i2s_port_t i2s_num);
/**
* @brief send all dma buffers, so they are available to i2s_custom_write() immediatly
*/
esp_err_t i2s_custom_init_dma_tx_queues(i2s_port_t i2s_num, uint8_t *data, size_t size, size_t *written);
/**
* @brief send all dma buffers, so they are available to i2s_custom_write()
* immediatly
*/
esp_err_t i2s_custom_init_dma_tx_queues (i2s_port_t i2s_num, uint8_t *data,
size_t size, size_t *written);
/**
* @brief Set clock & bit width used for I2S RX and TX.
*
* Similar to i2s_set_sample_rates(), but also sets bit width.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param rate I2S sample rate (ex: 8000, 44100...)
*
* @param bits I2S bit width (I2S_BITS_PER_SAMPLE_16BIT, I2S_BITS_PER_SAMPLE_24BIT, I2S_BITS_PER_SAMPLE_32BIT)
*
* @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t i2s_custom_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch);
/**
* @brief Set clock & bit width used for I2S RX and TX.
*
* Similar to i2s_set_sample_rates(), but also sets bit width.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @param rate I2S sample rate (ex: 8000, 44100...)
*
* @param bits I2S bit width (I2S_BITS_PER_SAMPLE_16BIT,
* I2S_BITS_PER_SAMPLE_24BIT, I2S_BITS_PER_SAMPLE_32BIT)
*
* @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO)
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Parameter error
* - ESP_ERR_NO_MEM Out of memory
*/
esp_err_t i2s_custom_set_clk (i2s_port_t i2s_num, uint32_t rate,
i2s_bits_per_sample_t bits, i2s_channel_t ch);
/**
* @brief get clock set on particular port number.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - actual clock set by i2s driver
*/
float i2s_custom_get_clk(i2s_port_t i2s_num);
/**
* @brief get clock set on particular port number.
*
* @param i2s_num I2S_NUM_0, I2S_NUM_1
*
* @return
* - actual clock set by i2s driver
*/
float i2s_custom_get_clk (i2s_port_t i2s_num);
#ifdef __cplusplus
}

View File

@@ -0,0 +1,20 @@
IF ( NOT (CONFIG_IDF_TARGET MATCHES "esp32s2"))
set(COMPONENT_ADD_INCLUDEDIRS driver/i2c_bus)
ELSEIF (CONFIG_IDF_TARGET MATCHES "esp32s2")
set(COMPONENT_ADD_INCLUDEDIRS driver/i2c_bus)
ENDIF ( NOT (CONFIG_IDF_TARGET MATCHES "esp32s2"))
# Edit following two lines to set component requirements (see docs)
set(COMPONENT_REQUIRES driver audio_hal audio_sal audio_board )
set(COMPONENT_PRIV_REQUIRES )
IF ( NOT (CONFIG_IDF_TARGET MATCHES "esp32s2"))
set(COMPONENT_SRCS driver/i2c_bus/i2c_bus.c)
ELSEIF (CONFIG_IDF_TARGET MATCHES "esp32s2")
set(COMPONENT_SRCS driver/i2c_bus/i2c_bus.c )
ENDIF ( NOT (CONFIG_IDF_TARGET MATCHES "esp32s2"))
register_component()
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3)

View File

@@ -0,0 +1,10 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
COMPONENT_ADD_INCLUDEDIRS := ./include ./lib/adc_button ./lib/gpio_isr ./driver/i2c_bus ./lib/aw2013
COMPONENT_SRCDIRS := . ./lib ./lib/sdcard ./lib/button ./lib/touch ./lib/blufi ./lib/adc_button ./lib/IS31FL3216 ./driver/i2c_bus ./lib/gpio_isr ./lib/aw2013
COMPONENT_PRIV_INCLUDEDIRS := ./lib/sdcard ./lib/button ./lib/touch ./lib/blufi ./lib/IS31FL3216 ./driver/i2c_bus
CFLAGS+=-D__FILENAME__=\"$(<F)\"

View File

@@ -0,0 +1,206 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2017 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "i2c_bus.h"
#include "audio_mem.h"
#include "audio_mutex.h"
#include "driver/i2c.h"
#include "esp_log.h"
#include <stdio.h>
#define ESP_INTR_FLG_DEFAULT (0)
#define ESP_I2C_MASTER_BUF_LEN (0)
#define I2C_ACK_CHECK_EN 1
#define I2C_BUS_CHECK(a, str, ret) \
if (!(a)) \
{ \
ESP_LOGE (TAG, "%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
return (ret); \
}
typedef struct
{
i2c_config_t i2c_conf; /*!<I2C bus parameters*/
i2c_port_t i2c_port; /*!<I2C port number */
} i2c_bus_t;
static const char *TAG = "I2C_BUS";
static i2c_bus_t *i2c_bus[I2C_NUM_MAX];
static xSemaphoreHandle _busLock;
i2c_bus_handle_t
i2c_bus_create (i2c_port_t port, i2c_config_t *conf)
{
I2C_BUS_CHECK (port < I2C_NUM_MAX, "I2C port error", NULL);
I2C_BUS_CHECK (conf != NULL, "Configuration not initialized", NULL);
if (i2c_bus[port])
{
ESP_LOGW (TAG, "%s:%d: I2C bus has been already created, [port:%d]",
__FUNCTION__, __LINE__, port);
return i2c_bus[port];
}
i2c_bus[port] = (i2c_bus_t *)audio_calloc (1, sizeof (i2c_bus_t));
i2c_bus[port]->i2c_conf = *conf;
i2c_bus[port]->i2c_port = port;
esp_err_t ret
= i2c_param_config (i2c_bus[port]->i2c_port, &i2c_bus[port]->i2c_conf);
if (ret != ESP_OK)
{
goto error;
}
ret = i2c_driver_install (
i2c_bus[port]->i2c_port, i2c_bus[port]->i2c_conf.mode,
ESP_I2C_MASTER_BUF_LEN, ESP_I2C_MASTER_BUF_LEN, ESP_INTR_FLG_DEFAULT);
if (ret != ESP_OK)
{
goto error;
}
if (_busLock)
{
mutex_destroy (_busLock);
}
_busLock = mutex_create ();
return (i2c_bus_handle_t)i2c_bus[port];
error:
if (i2c_bus[port])
{
audio_free (i2c_bus[port]);
}
return NULL;
}
esp_err_t
i2c_bus_write_bytes (i2c_bus_handle_t bus, int addr, uint8_t *reg, int regLen,
uint8_t *data, int datalen)
{
I2C_BUS_CHECK (bus != NULL, "Handle error", ESP_FAIL);
i2c_bus_t *p_bus = (i2c_bus_t *)bus;
I2C_BUS_CHECK (p_bus->i2c_port < I2C_NUM_MAX, "I2C port error", ESP_FAIL);
I2C_BUS_CHECK (data != NULL, "Not initialized input data pointer", ESP_FAIL);
esp_err_t ret = ESP_OK;
mutex_lock (_busLock);
i2c_cmd_handle_t cmd = i2c_cmd_link_create ();
ret |= i2c_master_start (cmd);
ret |= i2c_master_write_byte (cmd, addr, 1);
ret |= i2c_master_write (cmd, reg, regLen, I2C_ACK_CHECK_EN);
ret |= i2c_master_write (cmd, data, datalen, I2C_ACK_CHECK_EN);
ret |= i2c_master_stop (cmd);
ret |= i2c_master_cmd_begin (p_bus->i2c_port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete (cmd);
mutex_unlock (_busLock);
I2C_BUS_CHECK (ret == 0, "I2C Bus WriteReg Error", ESP_FAIL);
return ret;
}
esp_err_t
i2c_bus_write_data (i2c_bus_handle_t bus, int addr, uint8_t *data, int datalen)
{
I2C_BUS_CHECK (bus != NULL, "Handle error", ESP_FAIL);
i2c_bus_t *p_bus = (i2c_bus_t *)bus;
I2C_BUS_CHECK (p_bus->i2c_port < I2C_NUM_MAX, "I2C port error", ESP_FAIL);
I2C_BUS_CHECK (data != NULL, "Not initialized input data pointer", ESP_FAIL);
esp_err_t ret = ESP_OK;
mutex_lock (_busLock);
i2c_cmd_handle_t cmd = i2c_cmd_link_create ();
ret |= i2c_master_start (cmd);
ret |= i2c_master_write_byte (cmd, addr, 1);
ret |= i2c_master_write (cmd, data, datalen, I2C_ACK_CHECK_EN);
ret |= i2c_master_stop (cmd);
ret |= i2c_master_cmd_begin (p_bus->i2c_port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete (cmd);
mutex_unlock (_busLock);
I2C_BUS_CHECK (ret == 0, "I2C Bus WriteReg Error", ESP_FAIL);
return ret;
}
esp_err_t
i2c_bus_read_bytes (i2c_bus_handle_t bus, int addr, uint8_t *reg, int reglen,
uint8_t *outdata, int datalen)
{
I2C_BUS_CHECK (bus != NULL, "Handle error", ESP_FAIL);
i2c_bus_t *p_bus = (i2c_bus_t *)bus;
I2C_BUS_CHECK (p_bus->i2c_port < I2C_NUM_MAX, "I2C port error", ESP_FAIL);
I2C_BUS_CHECK (outdata != NULL, "Not initialized output data buffer pointer",
ESP_FAIL);
esp_err_t ret = ESP_OK;
mutex_lock (_busLock);
i2c_cmd_handle_t cmd;
cmd = i2c_cmd_link_create ();
ret |= i2c_master_start (cmd);
ret |= i2c_master_write_byte (cmd, addr, I2C_ACK_CHECK_EN);
ret |= i2c_master_write (cmd, reg, reglen, I2C_ACK_CHECK_EN);
ret |= i2c_master_stop (cmd);
ret |= i2c_master_cmd_begin (p_bus->i2c_port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete (cmd);
cmd = i2c_cmd_link_create ();
ret |= i2c_master_start (cmd);
ret |= i2c_master_write_byte (cmd, addr | 0x01, I2C_ACK_CHECK_EN);
for (int i = 0; i < datalen - 1; i++)
{
ret |= i2c_master_read_byte (cmd, &outdata[i], 0);
}
ret |= i2c_master_read_byte (cmd, &outdata[datalen - 1], 1);
ret = i2c_master_stop (cmd);
ret = i2c_master_cmd_begin (p_bus->i2c_port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete (cmd);
mutex_unlock (_busLock);
I2C_BUS_CHECK (ret == 0, "I2C Bus ReadReg Error", ESP_FAIL);
return ret;
}
esp_err_t
i2c_bus_delete (i2c_bus_handle_t bus)
{
I2C_BUS_CHECK (bus != NULL, "Handle error", ESP_FAIL);
i2c_bus_t *p_bus = (i2c_bus_t *)bus;
i2c_driver_delete (p_bus->i2c_port);
i2c_bus[p_bus->i2c_port] = NULL;
audio_free (p_bus);
mutex_destroy (_busLock);
_busLock = NULL;
return ESP_OK;
}
esp_err_t
i2c_bus_cmd_begin (i2c_bus_handle_t bus, i2c_cmd_handle_t cmd,
portBASE_TYPE ticks_to_wait)
{
I2C_BUS_CHECK (bus != NULL, "Handle error", ESP_FAIL);
I2C_BUS_CHECK (cmd != NULL, "I2C cmd error", ESP_FAIL);
i2c_bus_t *p_bus = (i2c_bus_t *)bus;
esp_err_t ret = i2c_master_cmd_begin (p_bus->i2c_port, cmd, ticks_to_wait);
return ret;
}

View File

@@ -0,0 +1,127 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2017 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _IOT_I2C_BUS_H_
#define _IOT_I2C_BUS_H_
#include "driver/i2c.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef void *i2c_bus_handle_t;
/**
* @brief Create and init I2C bus and return a I2C bus handle
*
* @param port I2C port number
* @param conf Pointer to I2C parameters
*
* @return
* - I2C bus handle
*/
i2c_bus_handle_t i2c_bus_create (i2c_port_t port, i2c_config_t *conf);
/**
* @brief Write bytes to I2C bus
*
* @param bus I2C bus handle
* @param addr The address of the device
* @param reg The register of the device
* @param regLen The length of register
* @param data The data pointer
* @param datalen The length of data
*
* @return
* - NULL Fail
* - Others Success
*/
esp_err_t i2c_bus_write_bytes (i2c_bus_handle_t bus, int addr, uint8_t *reg,
int regLen, uint8_t *data, int datalen);
/**
* @brief Write data to I2C bus
*
* @param bus I2C bus handle
* @param addr The address of the device
* @param data The data pointer
* @param datalen The length of data
*
* @return
* - NULL Fail
* - Others Success
*/
esp_err_t i2c_bus_write_data (i2c_bus_handle_t bus, int addr, uint8_t *data,
int datalen);
/**
* @brief Read bytes to I2C bus
*
* @param bus I2C bus handle
* @param addr The address of the device
* @param reg The register of the device
* @param regLen The length of register
* @param outdata The outdata pointer
* @param datalen The length of outdata
*
* @return
* - NULL Fail
* - Others Success
*/
esp_err_t i2c_bus_read_bytes (i2c_bus_handle_t bus, int addr, uint8_t *reg,
int reglen, uint8_t *outdata, int datalen);
/**
* @brief Delete and release the I2C bus object
*
* @param bus I2C bus handle
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t i2c_bus_delete (i2c_bus_handle_t bus);
/**
* @brief I2C start sending buffered commands
*
* @param bus I2C bus handle
* @param cmd I2C cmd handle
* @param ticks_to_wait Maximum blocking time
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t i2c_bus_cmd_begin (i2c_bus_handle_t bus, i2c_cmd_handle_t cmd,
portBASE_TYPE ticks_to_wait);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,579 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "esp_peripherals.h"
#include "audio_event_iface.h"
#include "audio_mem.h"
#include "audio_mutex.h"
#include "audio_thread.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "sys/queue.h"
#include <string.h>
static const char *TAG = "ESP_PERIPH";
#define DEFAULT_ESP_PERIPH_WAIT_TICK (10 / portTICK_RATE_MS)
struct esp_periph
{
char *tag;
bool disabled;
esp_periph_id_t periph_id;
esp_periph_func init;
esp_periph_run_func run;
esp_periph_func destroy;
esp_periph_state_t state;
void *source;
void *periph_data;
esp_periph_event_t *on_evt;
TimerHandle_t timer;
STAILQ_ENTRY (esp_periph) entries;
};
typedef struct esp_periph_sets
{
EventGroupHandle_t state_event_bits;
xSemaphoreHandle lock;
int task_stack;
int task_prio;
int task_core;
audio_thread_t audio_thread;
bool ext_stack;
bool run;
esp_periph_event_t event_handle;
STAILQ_HEAD (esp_periph_list_item, esp_periph) periph_list;
} esp_periph_set_t;
static const int STARTED_BIT = BIT0;
static const int STOPPED_BIT = BIT1;
static esp_err_t
esp_periph_wait_for_stop (esp_periph_set_handle_t periph_set_handle,
TickType_t ticks_to_wait);
static esp_err_t
process_peripheral_event (audio_event_iface_msg_t *msg, void *context)
{
esp_periph_handle_t periph_evt = (esp_periph_handle_t)msg->source;
esp_periph_handle_t periph;
esp_periph_set_t *sets = context;
STAILQ_FOREACH (periph, &sets->periph_list, entries)
{
if (periph->periph_id == periph_evt->periph_id
&& periph_evt->state == PERIPH_STATE_RUNNING && periph_evt->run
&& !periph_evt->disabled)
{
return periph_evt->run (periph_evt, msg);
}
}
return ESP_OK;
}
static void
esp_periph_task (void *pv)
{
esp_periph_handle_t periph;
esp_periph_set_handle_t periph_set_handle = (esp_periph_set_handle_t)pv;
ESP_LOGD (TAG, "esp_periph_task is running, handle:%p", periph_set_handle);
xEventGroupSetBits (periph_set_handle->state_event_bits, STARTED_BIT);
xEventGroupClearBits (periph_set_handle->state_event_bits, STOPPED_BIT);
while (periph_set_handle->run)
{
mutex_lock (periph_set_handle->lock);
STAILQ_FOREACH (periph, &periph_set_handle->periph_list, entries)
{
if (periph->disabled)
{
continue;
}
if (periph->state == PERIPH_STATE_INIT && periph->init)
{
ESP_LOGD (TAG, "PERIPH[%s]->init", periph->tag);
if (periph->init (periph) == ESP_OK)
{
periph->state = PERIPH_STATE_RUNNING;
}
else
{
periph->state = PERIPH_STATE_ERROR;
}
}
}
mutex_unlock (periph_set_handle->lock);
audio_event_iface_waiting_cmd_msg (
esp_periph_set_get_event_iface (periph_set_handle));
}
STAILQ_FOREACH (periph, &periph_set_handle->periph_list, entries)
{
esp_periph_stop_timer (periph);
if (periph->destroy)
{
periph->destroy (periph);
}
}
xEventGroupClearBits (periph_set_handle->state_event_bits, STARTED_BIT);
xEventGroupSetBits (periph_set_handle->state_event_bits, STOPPED_BIT);
vTaskDelete (NULL);
}
esp_periph_set_handle_t
esp_periph_set_init (esp_periph_config_t *config)
{
esp_periph_set_t *periph_sets = NULL;
int _err_step = 1;
bool _success = ((periph_sets = audio_calloc (1, sizeof (esp_periph_set_t)))
&& _err_step++
&& (periph_sets->state_event_bits = xEventGroupCreate ())
&& _err_step++ && (periph_sets->lock = mutex_create ())
&& _err_step++);
AUDIO_MEM_CHECK (TAG, _success, { goto _periph_init_failed; });
STAILQ_INIT (&periph_sets->periph_list);
// TODO: Should we uninstall gpio isr service??
// TODO: Because gpio need for sdcard and gpio, then install isr here
gpio_install_isr_service (ESP_INTR_FLAG_LEVEL1);
periph_sets->run = false;
xEventGroupClearBits (periph_sets->state_event_bits, STARTED_BIT);
xEventGroupSetBits (periph_sets->state_event_bits, STOPPED_BIT);
periph_sets->task_stack = config->task_stack;
periph_sets->task_prio = config->task_prio;
periph_sets->task_core = config->task_core;
periph_sets->ext_stack = config->extern_stack;
audio_event_iface_cfg_t event_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG ();
event_cfg.queue_set_size = 0;
event_cfg.context = periph_sets;
event_cfg.on_cmd = process_peripheral_event;
periph_sets->event_handle.iface = audio_event_iface_init (&event_cfg);
AUDIO_MEM_CHECK (TAG, periph_sets->event_handle.iface,
goto _periph_init_failed);
audio_event_iface_set_cmd_waiting_timeout (periph_sets->event_handle.iface,
DEFAULT_ESP_PERIPH_WAIT_TICK);
return periph_sets;
_periph_init_failed:
if (periph_sets)
{
mutex_destroy (periph_sets->lock);
vEventGroupDelete (periph_sets->state_event_bits);
if (periph_sets->event_handle.iface)
{
audio_event_iface_destroy (periph_sets->event_handle.iface);
}
audio_free (periph_sets);
periph_sets = NULL;
}
return NULL;
}
esp_err_t
esp_periph_set_destroy (esp_periph_set_handle_t periph_set_handle)
{
if (periph_set_handle == NULL)
{
AUDIO_ERROR (TAG, "Peripherals have not been initialized");
return ESP_FAIL;
}
periph_set_handle->run = false;
esp_periph_wait_for_stop (periph_set_handle, portMAX_DELAY);
esp_periph_handle_t item, tmp;
STAILQ_FOREACH_SAFE (item, &periph_set_handle->periph_list, entries, tmp)
{
STAILQ_REMOVE (&periph_set_handle->periph_list, item, esp_periph, entries);
audio_free (item->tag);
audio_free (item);
}
mutex_destroy (periph_set_handle->lock);
vEventGroupDelete (periph_set_handle->state_event_bits);
gpio_uninstall_isr_service ();
audio_event_iface_destroy (periph_set_handle->event_handle.iface);
audio_free (periph_set_handle);
periph_set_handle = NULL;
return ESP_OK;
}
esp_err_t
esp_periph_set_stop_all (esp_periph_set_handle_t periph_set_handle)
{
if (periph_set_handle == NULL)
{
AUDIO_ERROR (TAG, "Peripherals have not been initialized");
return ESP_FAIL;
}
esp_periph_handle_t periph;
STAILQ_FOREACH (periph, &periph_set_handle->periph_list, entries)
{
periph->disabled = true;
}
return ESP_OK;
}
esp_periph_handle_t
esp_periph_set_get_by_id (esp_periph_set_handle_t periph_set_handle,
int periph_id)
{
esp_periph_handle_t periph;
if (periph_set_handle == NULL)
{
AUDIO_ERROR (TAG, "Peripherals have not been initialized");
return NULL;
}
mutex_lock (periph_set_handle->lock);
STAILQ_FOREACH (periph, &periph_set_handle->periph_list, entries)
{
if (periph->periph_id == periph_id)
{
mutex_unlock (periph_set_handle->lock);
return periph;
}
}
ESP_LOGD (TAG, "Periph id %d not found", periph_id);
mutex_unlock (periph_set_handle->lock);
return NULL;
}
audio_event_iface_handle_t
esp_periph_set_get_event_iface (esp_periph_set_handle_t periph_set_handle)
{
return periph_set_handle->event_handle.iface;
}
esp_err_t
esp_periph_set_register_callback (esp_periph_set_handle_t periph_set_handle,
esp_periph_event_handle_t cb,
void *user_context)
{
if (periph_set_handle == NULL)
{
return ESP_FAIL;
}
else
{
periph_set_handle->event_handle.cb = cb;
periph_set_handle->event_handle.user_ctx = user_context;
return ESP_OK;
}
}
QueueHandle_t
esp_periph_set_get_queue (esp_periph_set_handle_t periph_set_handle)
{
return audio_event_iface_get_queue_handle (
periph_set_handle->event_handle.iface);
}
esp_err_t
esp_periph_wait_for_stop (esp_periph_set_handle_t periph_set_handle,
TickType_t ticks_to_wait)
{
EventGroupHandle_t ev_bits = periph_set_handle->state_event_bits;
EventBits_t uxBits
= xEventGroupWaitBits (ev_bits, STOPPED_BIT, false, true, ticks_to_wait);
if (uxBits & STOPPED_BIT)
{
return ESP_OK;
}
return ESP_FAIL;
}
esp_err_t
esp_periph_set_list_init (esp_periph_set_handle_t periph_set)
{
esp_periph_handle_t periph;
STAILQ_FOREACH (periph, &periph_set->periph_list, entries)
{
if (periph->init)
{
periph->init (periph);
}
}
return ESP_OK;
}
esp_err_t
esp_periph_set_list_run (esp_periph_set_handle_t periph_set,
audio_event_iface_msg_t msg)
{
esp_periph_handle_t periph;
STAILQ_FOREACH (periph, &periph_set->periph_list, entries)
{
if (periph->run)
{
periph->run (periph, &msg);
}
}
return ESP_OK;
}
esp_err_t
esp_periph_set_list_destroy (esp_periph_set_handle_t periph_set)
{
esp_periph_handle_t periph;
STAILQ_FOREACH (periph, &periph_set->periph_list, entries)
{
if (periph->destroy)
{
periph->destroy (periph);
}
}
return ESP_OK;
}
esp_periph_handle_t
esp_periph_create (int periph_id, const char *tag)
{
esp_periph_handle_t new_entry = audio_calloc (1, sizeof (struct esp_periph));
AUDIO_MEM_CHECK (TAG, new_entry, return NULL);
if (tag)
{
new_entry->tag = audio_strdup (tag);
}
else
{
new_entry->tag = audio_strdup ("periph");
}
AUDIO_MEM_CHECK (TAG, new_entry->tag, {
audio_free (new_entry);
return NULL;
})
new_entry->state = PERIPH_STATE_INIT;
new_entry->periph_id = periph_id;
return new_entry;
}
esp_err_t
esp_periph_set_function (esp_periph_handle_t periph, esp_periph_func init,
esp_periph_run_func run, esp_periph_func destroy)
{
periph->init = init;
periph->run = run;
periph->destroy = destroy;
return ESP_OK;
}
esp_err_t
esp_periph_start (esp_periph_set_handle_t periph_set_handle,
esp_periph_handle_t periph)
{
if (periph_set_handle == NULL)
{
AUDIO_ERROR (TAG, "Peripherals have not been initialized");
return ESP_FAIL;
}
if (esp_periph_set_get_by_id (periph_set_handle, periph->periph_id) != NULL)
{
ESP_LOGI (TAG, "This peripheral has been added");
periph->disabled = false;
}
else
{
esp_periph_register_on_events (periph, &periph_set_handle->event_handle);
STAILQ_INSERT_TAIL (&periph_set_handle->periph_list, periph, entries);
}
if (periph_set_handle->run == false && periph_set_handle->task_stack > 0)
{
periph_set_handle->run = true;
if (audio_thread_create (
&periph_set_handle->audio_thread, "esp_periph", esp_periph_task,
periph_set_handle, periph_set_handle->task_stack,
periph_set_handle->task_prio, periph_set_handle->ext_stack,
periph_set_handle->task_core)
!= ESP_OK)
{
ESP_LOGE (TAG, "Create [%s] task failed", periph->tag);
return ESP_FAIL;
}
}
return ESP_OK;
}
esp_err_t
esp_periph_stop (esp_periph_handle_t periph)
{
if (periph)
{
periph->disabled = true;
return ESP_OK;
}
return ESP_OK;
}
esp_err_t
esp_periph_send_cmd (esp_periph_handle_t periph, int cmd, void *data,
int data_len)
{
if (periph->on_evt == NULL)
{
return ESP_FAIL;
}
audio_event_iface_msg_t msg;
msg.cmd = cmd;
msg.source = periph;
msg.source_type = periph->periph_id;
msg.data = (void *)data;
msg.data_len = data_len;
return audio_event_iface_cmd (periph->on_evt->iface, &msg);
}
esp_err_t
esp_periph_send_cmd_from_isr (esp_periph_handle_t periph, int cmd, void *data,
int data_len)
{
if (periph->on_evt == NULL)
{
return ESP_FAIL;
}
audio_event_iface_msg_t msg;
msg.cmd = cmd;
msg.source = periph;
msg.source_type = periph->periph_id;
msg.data = (void *)data;
msg.data_len = data_len;
return audio_event_iface_cmd_from_isr (periph->on_evt->iface, &msg);
}
esp_err_t
esp_periph_send_event (esp_periph_handle_t periph, int event_id, void *data,
int data_len)
{
if (periph->on_evt == NULL)
{
return ESP_FAIL;
}
audio_event_iface_msg_t msg;
msg.source_type = periph->periph_id;
msg.cmd = event_id;
msg.data = data;
msg.data_len = data_len;
msg.need_free_data = false;
msg.source = periph;
if (periph->on_evt->cb)
{
periph->on_evt->cb (&msg, periph->on_evt->user_ctx);
}
return audio_event_iface_sendout (periph->on_evt->iface, &msg);
}
esp_err_t
esp_periph_start_timer (esp_periph_handle_t periph, TickType_t interval_tick,
timer_callback callback)
{
if (periph->timer == NULL)
{
periph->timer = xTimerCreate ("periph_itmer", interval_tick, pdTRUE,
periph, callback);
if (xTimerStart (periph->timer, 0) != pdTRUE)
{
AUDIO_ERROR (TAG, "Error to starting timer");
return ESP_FAIL;
}
}
return ESP_OK;
}
esp_err_t
esp_periph_stop_timer (esp_periph_handle_t periph)
{
if (periph->timer)
{
xTimerStop (periph->timer, portMAX_DELAY);
xTimerDelete (periph->timer, portMAX_DELAY);
periph->timer = NULL;
}
return ESP_OK;
}
esp_err_t
esp_periph_set_data (esp_periph_handle_t periph, void *data)
{
periph->periph_data = data;
return ESP_OK;
}
void *
esp_periph_get_data (esp_periph_handle_t periph)
{
return periph->periph_data;
}
esp_periph_state_t
esp_periph_get_state (esp_periph_handle_t periph)
{
return periph->state;
}
esp_periph_id_t
esp_periph_get_id (esp_periph_handle_t periph)
{
return periph->periph_id;
}
esp_err_t
esp_periph_set_id (esp_periph_handle_t periph, esp_periph_id_t periph_id)
{
periph->periph_id = periph_id;
return ESP_OK;
}
esp_err_t
esp_periph_init (esp_periph_handle_t periph)
{
return periph->init (periph);
}
esp_err_t
esp_periph_run (esp_periph_handle_t periph)
{
return periph->run (periph, NULL);
}
esp_err_t
esp_periph_destroy (esp_periph_handle_t periph)
{
return periph->destroy (periph);
}
esp_err_t
esp_periph_register_on_events (esp_periph_handle_t periph,
esp_periph_event_t *evts)
{
periph->on_evt = evts;
return ESP_OK;
}

View File

@@ -0,0 +1,510 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _ESP_PERIPHERALS_H_
#define _ESP_PERIPHERALS_H_
#include "audio_common.h"
#include "audio_error.h"
#include "audio_event_iface.h"
#include "freertos/event_groups.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Peripheral Identify, this must be unique for each peripheral added
* to the peripherals list
*/
typedef enum
{
PERIPH_ID_BUTTON = AUDIO_ELEMENT_TYPE_PERIPH + 1,
PERIPH_ID_TOUCH = AUDIO_ELEMENT_TYPE_PERIPH + 2,
PERIPH_ID_SDCARD = AUDIO_ELEMENT_TYPE_PERIPH + 3,
PERIPH_ID_WIFI = AUDIO_ELEMENT_TYPE_PERIPH + 4,
PERIPH_ID_FLASH = AUDIO_ELEMENT_TYPE_PERIPH + 5,
PERIPH_ID_AUXIN = AUDIO_ELEMENT_TYPE_PERIPH + 6,
PERIPH_ID_ADC = AUDIO_ELEMENT_TYPE_PERIPH + 7,
PERIPH_ID_CONSOLE = AUDIO_ELEMENT_TYPE_PERIPH + 8,
PERIPH_ID_BLUETOOTH = AUDIO_ELEMENT_TYPE_PERIPH + 9,
PERIPH_ID_LED = AUDIO_ELEMENT_TYPE_PERIPH + 10,
PERIPH_ID_SPIFFS = AUDIO_ELEMENT_TYPE_PERIPH + 11,
PERIPH_ID_ADC_BTN = AUDIO_ELEMENT_TYPE_PERIPH + 12,
PERIPH_ID_IS31FL3216 = AUDIO_ELEMENT_TYPE_PERIPH + 13,
PERIPH_ID_GPIO_ISR = AUDIO_ELEMENT_TYPE_PERIPH + 14,
PERIPH_ID_WS2812 = AUDIO_ELEMENT_TYPE_PERIPH + 15,
PERIPH_ID_AW2013 = AUDIO_ELEMENT_TYPE_PERIPH + 16
} esp_periph_id_t;
/**
* @brief Peripheral working state
*/
typedef enum
{
PERIPH_STATE_NULL,
PERIPH_STATE_INIT,
PERIPH_STATE_RUNNING,
PERIPH_STATE_PAUSE,
PERIPH_STATE_STOPPING,
PERIPH_STATE_ERROR,
PERIPH_STATE_STATUS_MAX,
} esp_periph_state_t;
typedef struct esp_periph_sets *esp_periph_set_handle_t;
typedef struct esp_periph *esp_periph_handle_t;
typedef esp_err_t (*esp_periph_func) (esp_periph_handle_t periph);
typedef esp_err_t (*esp_periph_run_func) (esp_periph_handle_t periph,
audio_event_iface_msg_t *msg);
typedef esp_err_t (*esp_periph_event_handle_t) (
audio_event_iface_msg_t *event, void *context);
typedef void (*timer_callback) (xTimerHandle tmr);
/**
* @brief Common peripherals configurations
*/
typedef struct
{
int task_stack; /*!< >0 Service task stack size; =0 without task created */
int task_prio; /*!< Service task priority (based on freeRTOS priority) */
int task_core; /*!< Service task running in core (0 or 1) */
bool extern_stack; /*!< Service task stack allocate on extern ram */
} esp_periph_config_t;
/**
* @brief peripheral events
*/
typedef struct esp_periph_event
{
void *user_ctx; /*!< peripheral context data */
esp_periph_event_handle_t cb; /*!< peripheral callback function */
audio_event_iface_handle_t iface; /*!< peripheral event */
} esp_periph_event_t;
#define DEFAULT_ESP_PERIPH_STACK_SIZE (4 * 1024)
#define DEFAULT_ESP_PERIPH_TASK_PRIO (5)
#define DEFAULT_ESP_PERIPH_TASK_CORE (0)
#define DEFAULT_ESP_PERIPH_SET_CONFIG() \
{ \
.task_stack = DEFAULT_ESP_PERIPH_STACK_SIZE, \
.task_prio = DEFAULT_ESP_PERIPH_TASK_PRIO, \
.task_core = DEFAULT_ESP_PERIPH_TASK_CORE, .extern_stack = false, \
}
/**
* @brief Initialize esp_peripheral sets, create empty peripherals list.
* Call this function before starting any peripherals (with
* `esp_periph_start`). This call will initialize the data needed for
* esp_peripherals to work, but does not actually create the task. The
* `event_handle` is optional if you want to receive events from this
* callback function. The esp_peripherals task will send all events out to
* event_iface, can be listen by event_iface by `esp_periph_get_event_iface`.
* The `user_context` will sent `esp_periph_event_handle_t` as *context
* parameter.
*
* @param[in] config The configurations
*
* @return The peripheral sets instance
*/
esp_periph_set_handle_t esp_periph_set_init (esp_periph_config_t *config);
/**
* @brief This function will stop and kill the monitor task, calling all
* destroy callback functions of the peripheral (so you do not need to
* destroy the peripheral object manually). It will also remove all memory
* allocated to the peripherals list, so you need to call the
* `esp_periph_set_init` function again if you want to use it.
*
* @param periph_set_handle The esp_periph_set_handle_t instance
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_set_destroy (esp_periph_set_handle_t periph_set_handle);
/**
* @brief Stop monitoring all peripherals, the peripheral state is still
* kept. This funciton only temporary disables the peripheral.
*
* @param periph_set_handle The esp_periph_set_handle_t instance
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t
esp_periph_set_stop_all (esp_periph_set_handle_t periph_set_handle);
/**
* @brief Get the peripheral handle by Peripheral ID
*
* @param periph_set_handle The esp_periph_set_handle_t instance
*
* @param[in] periph_id as esp_periph_id_t, or any ID you use when calling
* `esp_periph_create`
*
*
* @return The esp_periph_handle_t
*/
esp_periph_handle_t
esp_periph_set_get_by_id (esp_periph_set_handle_t periph_set_handle,
int periph_id);
/**
* @brief Return the event_iface used by this esp_peripherals
*
* @param periph_set_handle The esp_periph_set_handle_t instance
*
* @return The audio event iface handle
*/
audio_event_iface_handle_t
esp_periph_set_get_event_iface (esp_periph_set_handle_t periph_set_handle);
/**
* @brief Register peripheral sets event callback function.
*
* @param periph_set_handle The esp_periph_set_handle_t instance
* @param cb The event handle callback function
* @param user_context The user context pointer
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t
esp_periph_set_register_callback (esp_periph_set_handle_t periph_set_handle,
esp_periph_event_handle_t cb,
void *user_context);
/**
* @brief Peripheral is using event_iface to control the event, all
* events are send out to event_iface queue. This function will be useful in
* case we want to read events directly from the event_iface queue.
*
* @param periph_set_handle The esp_periph_set_handle_t instance
*
* @return The queue handle
*/
QueueHandle_t
esp_periph_set_get_queue (esp_periph_set_handle_t periph_set_handle);
/**
* @brief Call this function to initialize all the listed peripherals.
* @note Work with no task peripheral set only
*
* @param periph_set_handle The esp_periph_set_handle_t instance
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t
esp_periph_set_list_init (esp_periph_set_handle_t periph_set_handle);
/**
* @brief Call this function to run all the listed peripherals.
* @note Work with no task peripheral set only
*
* @param periph_set_handle The esp_periph_set_handle_t instance
* @param msg The audio_event_iface_msg_t handle
* message
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_set_list_run (esp_periph_set_handle_t periph_set_handle,
audio_event_iface_msg_t msg);
/**
* @brief Call this function to destroy all the listed peripherals.
* @note Work with no task peripheral set only
*
* @param periph_set_handle The esp_periph_set_handle_t instance
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t
esp_periph_set_list_destroy (esp_periph_set_handle_t periph_set_handle);
/**
* @brief Call this function to initialize a new peripheral
*
* @param[in] periph_id The periph identifier
* @param[in] tag The tag name, we named it easy to get in debug logs
*
* @return The peripheral handle
*/
esp_periph_handle_t esp_periph_create (int periph_id, const char *tag);
/**
* @brief Each peripheral has a cycle of sequential operations from
* initialization, execution of commands to destroying the peripheral. These
* operations are represented by functions passed as call parameters to this
* function.
*
* @param[in] periph The periph
* @param[in] init The initialize
* @param[in] run The run
* @param[in] destroy The destroy
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_set_function (esp_periph_handle_t periph,
esp_periph_func init,
esp_periph_run_func run,
esp_periph_func destroy);
/**
* @brief Add the peripheral to peripherals list, enable and start
* monitor task (if task stack size > 0)
*
* @param[in] periph_set_handle The esp_periph_set_handle_t instance
* @param[in] periph The peripheral instance
*
* @note
* This peripheral must be first created by calling
* `esp_periph_create`
*
* @return
* - ESP_OK on success
* - ESP_FAIL when any errors
*/
esp_err_t esp_periph_start (esp_periph_set_handle_t periph_set_handle,
esp_periph_handle_t periph);
/**
* @brief Stop monitoring the peripheral, the peripheral state is still
* kept. This funciton only temporary disables the peripheral.
*
* @param[in] periph The periph
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_stop (esp_periph_handle_t periph);
/**
* @brief When this function is called, the command is passed to the
* event_iface command queue, and the `esp_periph_run_func` of this
* peripheral will be executed in the main peripheral task. This function can
* be called from any task, basically it only sends a queue to the main
* peripheral task
*
* @param[in] periph The periph
* @param[in] cmd The command
* @param data The data
* @param[in] data_len The data length
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_send_cmd (esp_periph_handle_t periph, int cmd,
void *data, int data_len);
/**
* @brief Similar to `esp_periph_send_cmd`, but it can be called in the
* hardware interrupt handle
*
* @param[in] periph The periph
* @param[in] cmd The command
* @param data The data
* @param[in] data_len The data length
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_send_cmd_from_isr (esp_periph_handle_t periph, int cmd,
void *data, int data_len);
/**
* @brief In addition to sending an event via event_iface, this function
* will dispatch the `event_handle` callback if the event_handle callback is
* provided at `esp_periph_init`
*
* @param[in] periph The peripheral
* @param[in] event_id The event identifier
* @param data The data
* @param[in] data_len The data length
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_send_event (esp_periph_handle_t periph, int event_id,
void *data, int data_len);
/**
* @brief Each peripheral can initialize a timer, which is by default
* NULL. When this function is called, the timer for the peripheral is
* created and it invokes the callback function every interval tick.
*
* @note
* - You do not need to stop or destroy the timer, when the
* `esp_periph_destroy` function is called, it will stop and destroy all
* - This timer using FreeRTOS Timer, with autoreload = true
*
* @param[in] periph The peripheral
* @param[in] interval_tick The interval tick
* @param[in] callback The callback
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_start_timer (esp_periph_handle_t periph,
TickType_t interval_tick,
timer_callback callback);
/**
* @brief Stop peripheral timer
*
* @param[in] periph The peripheral
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_stop_timer (esp_periph_handle_t periph);
/**
* @brief Set the user data
*
* @note Make sure the `data` lifetime is sufficient, this function
* does not copy all data, it only stores the data pointer
*
* @param[in] periph The peripheral
* @param data The data
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_set_data (esp_periph_handle_t periph, void *data);
/**
* @brief Get the user data stored in the peripheral
*
* @param[in] periph The peripheral
*
* @return Peripheral data pointer
*/
void *esp_periph_get_data (esp_periph_handle_t periph);
/**
* @brief Get the current state of peripheral.
*
* @param[in] periph The handle of peripheral
*
* @return The peripharal working state
*/
esp_periph_state_t esp_periph_get_state (esp_periph_handle_t periph);
/**
* @brief Get Peripheral identifier
*
* @param[in] periph The peripheral
*
* @return The peripheral identifier
*/
esp_periph_id_t esp_periph_get_id (esp_periph_handle_t periph);
/**
* @brief Set Peripheral identifier
*
* @param[in] periph The peripheral
* @param[in] periph_id The peripheral identifier
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_set_id (esp_periph_handle_t periph,
esp_periph_id_t periph_id);
/**
* @brief Call this to execute `init` function of peripheral instance
*
* @param periph The peripheral handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_init (esp_periph_handle_t periph);
/**
* @brief Call this to execute `run` function of peripheral instance
*
* @param periph The peripheral handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_run (esp_periph_handle_t periph);
/**
* @brief Call this to execute `destroy` function of peripheral instance
*
* @param periph The peripheral handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_destroy (esp_periph_handle_t periph);
/**
* @brief Rigster peripheral on event handle
*
* @param periph The peripheral handle
* @param evts The esp_periph_event_t handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t esp_periph_register_on_events (esp_periph_handle_t periph,
esp_periph_event_t *evts);
#define periph_tick_get esp_periph_tick_get
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,107 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _PERIPH_ADC_BUTTON_H_
#define _PERIPH_ADC_BUTTON_H_
#include "adc_button.h"
#include "driver/adc.h"
#include "esp_peripherals.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define ADC_BUTTON_STACK_SIZE 2500
#define ADC_BUTTON_TASK_PRIORITY 10
#define ADC_BUTTON_TASK_CORE_ID 0
/**
* @brief The configuration of ADC Button
*/
typedef struct
{
adc_arr_t *arr; /*!< An array with configuration of buttons */
int arr_size; /*!< The array size */
adc_btn_task_cfg_t task_cfg; /*!< Adc button task configuration */
} periph_adc_button_cfg_t;
#define PERIPH_ADC_BUTTON_DEFAULT_CONFIG() \
{ \
.task_cfg \
= {.task_stack = ADC_BUTTON_STACK_SIZE, \
.task_core = ADC_BUTTON_TASK_CORE_ID, \
.task_prio = ADC_BUTTON_TASK_PRIORITY, \
.ext_stack = false } \
}
typedef enum
{
PERIPH_ADC_BUTTON_IDLE = 0,
PERIPH_ADC_BUTTON_PRESSED,
PERIPH_ADC_BUTTON_RELEASE,
PERIPH_ADC_BUTTON_LONG_PRESSED,
PERIPH_ADC_BUTTON_LONG_RELEASE,
} periph_adc_button_event_id_t;
/**
* ESP32 ADC1 channels and GPIO table
* ADC1_CHANNEL_0 - GPIO36
* ADC1_CHANNEL_1 - GPIO37
* ADC1_CHANNEL_2 - GPIO38
* ADC1_CHANNEL_3 - GPIO39
* ADC1_CHANNEL_4 - GPIO32
* ADC1_CHANNEL_5 - GPIO33
* ADC1_CHANNEL_6 - GPIO34
* ADC1_CHANNEL_7 - GPIO35
*
**/
#define ADC_DEFAULT_ARR() \
{ \
.adc_ch = ADC1_CHANNEL_3, .adc_level_step = NULL, .total_steps = 6, \
.press_judge_time = 3000, \
}
/**
* @brief Create the button peripheral handle for esp_peripherals.
*
* @note The handle created by this function is automatically destroyed
* when esp_periph_destroy is called.
*
* @param btn_cfg The button configuration.
*
* @return The esp peripheral handle.
*/
esp_periph_handle_t
periph_adc_button_init (periph_adc_button_cfg_t *btn_cfg);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,137 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _PERIPH_AW2013_H_
#define _PERIPH_AW2013_H_
#include "aw2013.h"
#include "esp_peripherals.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef enum
{
AW2013_MODE_LED,
AW2013_MODE_FADE,
AW2013_MODE_AUTO
} periph_aw2013_mode_t;
/**
* @brief Configuration of aw2013
*/
typedef struct
{
periph_aw2013_mode_t mode; /*!< Work mode of aw2013 */
aw2013_brightness_t bright; /*!< The brightness of aw2013 */
uint32_t rgb_value; /*!< rgb value to be set */
} periph_aw2013_cfg_t;
/**
* @brief Initializate aw2013
*
* @param aw2013_cfg Parameters of aw2013
*
* @return
* - NULL Error
* - others Success
*/
esp_periph_handle_t periph_aw2013_init (periph_aw2013_cfg_t *aw2013_cfg);
/**
* @brief Set the brightness of aw2013
*
* @param periph The aw2013's handle
* @param bright The brightness to be set
*
* @return
* - ESP_OK Success
* - ESP_FAIL Error
*/
esp_err_t periph_aw2013_set_brightless (esp_periph_handle_t periph,
aw2013_brightness_t bright);
/**
* @brief Set the time periods of aw2013
*
* @param periph The aw2013's handle
* @param time The time period to be set
* @param level The time value to be set
*
* @return
* - ESP_OK Success
* - ESP_FAIL Error
*/
esp_err_t periph_aw2013_set_time (esp_periph_handle_t periph,
aw2013_time_t time,
aw2013_time_level_t level);
/**
* @brief Set the work mode of aw2013
*
* @param periph The aw2013's handle
* @param mode The work mode to be set
*
* @return
* - ESP_OK Success
* - ESP_FAIL Error
*/
esp_err_t periph_aw2013_set_mode (esp_periph_handle_t periph,
periph_aw2013_mode_t mode);
/**
* @brief Set the rgb value of aw2013
*
* @param periph The aw2013's handle
* @param value The value for rgb to be set
*
* @return
* - ESP_OK Success
* - ESP_FAIL Error
*/
esp_err_t periph_aw2013_set_rgb_value (esp_periph_handle_t periph,
uint32_t value);
/**
* @brief Set the repeat time in auto flash mode
*
* @param periph The aw2013's handle
* @param cnt Cycle times to be set
*
* @return
* - ESP_OK Success
* - ESP_FAIL Error
*/
esp_err_t periph_aw2013_set_repeat_time (esp_periph_handle_t periph,
uint8_t cnt);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,81 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _BUTTON_DEV_H_
#define _BUTTON_DEV_H_
#include "audio_common.h"
#include "audio_error.h"
#include "esp_peripherals.h"
#include "sys/queue.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief The Button peripheral configuration
*/
typedef struct
{
uint64_t gpio_mask; /*!< GPIO Mask using for this Button peripheral, it is
BIT(GPIO_NUM), ex: GPIO_SEL_36 | GPIO_SEL_36 */
int long_press_time_ms; /*!< Long press duration in milliseconds, default
is 2000ms */
} periph_button_cfg_t;
/**
* @brief Peripheral button event id
*/
typedef enum
{
PERIPH_BUTTON_UNCHANGE = 0, /*!< No event */
PERIPH_BUTTON_PRESSED, /*!< When button is pressed */
PERIPH_BUTTON_RELEASE, /*!< When button is released */
PERIPH_BUTTON_LONG_PRESSED, /*!< When button is pressed and kept for more
than `long_press_time_ms` */
PERIPH_BUTTON_LONG_RELEASE, /*!< When button is released and event
PERIPH_BUTTON_LONG_PRESSED happened */
} periph_button_event_id_t;
/**
* @brief Create the button peripheral handle for esp_peripherals.
*
* @note The handle was created by this function automatically destroy
* when `esp_periph_destroy` is called
*
* @param but_cfg The but configuration
*
* @return The esp peripheral handle
*/
esp_periph_handle_t periph_button_init (periph_button_cfg_t *but_cfg);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,89 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _PERIPH_CONSOLE_H_
#define _PERIPH_CONSOLE_H_
#include "audio_error.h"
#include "esp_peripherals.h"
#include "sys/queue.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef esp_err_t (*console_cmd_callback_t) (esp_periph_handle_t periph,
int argc, char *argv[]);
#define CONSOLE_DEFAULT_TASK_PRIO (5)
#define CONSOLE_DEFAULT_TASK_STACK (1024 * 5)
#define CONSOLE_DEFAULT_BUFFER_SIZE (256)
#define CONSOLE_DEFAULT_PROMPT_STRING "esp32>"
/**
* @brief Command structure
*/
typedef struct
{
const char *cmd; /*!< Name of command, must be unique */
int id; /*!< Command ID will be sent together when the command is matched
*/
const char *help; /*!< Explanation of the command */
console_cmd_callback_t func; /*!< Function callback for the command */
} periph_console_cmd_t;
/**
* @brief Console Peripheral configuration
*/
typedef struct
{
int command_num; /*!< Total number of commands */
const periph_console_cmd_t *commands; /*!< Pointer to array of commands */
int task_stack; /*!< Console task stack, using default if the value is zero
*/
int task_prio; /*!< Console task priority (based on freeRTOS priority),
using default if the value is zero */
int buffer_size; /*!< Size of console input buffer */
const char
*prompt_string; /*!< Console prompt string, using default
CONSOLE_PROMPT_STRING if the pointer is NULL */
} periph_console_cfg_t;
/**
* @brief Initialize Console Peripheral
*
* @param config The configuration
*
* @return The esp peripheral handle
*/
esp_periph_handle_t periph_console_init (periph_console_cfg_t *config);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,93 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _PERIPH_GPIO_ISR_H_
#define _PERIPH_GPIO_ISR_H_
#include "driver/gpio.h"
#include "esp_peripherals.h"
#include "gpio_isr.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @breif Set the gpio number and gpio interruption type
*/
typedef struct
{
int gpio_num; /*!< gpio number */
gpio_int_type_t type; /*!< interruption type */
} gpio_isr_info_t;
/**
* @brief The configuration of gpio isr
*/
typedef struct
{
int info_size; /*!< number of gpio to be register */
gpio_isr_info_t *gpio_isr_info; /*!< an array of gpio's infomation */
} periph_gpio_isr_cfg_t;
/**
* @brief Create the gpio's interrupt service routines handle for
* esp_peripherals
*
* @param isr_config The gpio isr configuration
*
* @return The esp peripheral handle
*/
esp_periph_handle_t periph_gpio_isr_init (periph_gpio_isr_cfg_t *isr_config);
/**
* @breif Add a gpio to isr
*
* @param gpio_info The gpio interruption type and gpio number
*
* @return
* - ESP_OK success
* - ESP_FAIL fail
*/
esp_err_t periph_gpio_isr_add (gpio_isr_info_t *gpio_info);
/**
* @brief Unregister a gpio from isr
*
* @param The number of gpio to be unregistered
*
*@return
* - ESP_OK success
* - ESP_FAIL failed
*/
esp_err_t periph_gpio_isr_delete (int gpio_num);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,191 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef __PERIPH_IS31FL3216_H__
#define __PERIPH_IS31FL3216_H__
#include "esp_peripherals.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define IS31FL3216_CH_NUM 16 // Should be less than or equal to 16
#define BLUE_LED_MAX_NUM 12
typedef enum
{
IS31FL3216_STATE_UNKNOWN,
IS31FL3216_STATE_OFF,
IS31FL3216_STATE_ON,
IS31FL3216_STATE_FLASH,
IS31FL3216_STATE_BY_AUDIO,
IS31FL3216_STATE_SHIFT,
} periph_is31fl3216_state_t;
typedef enum
{
PERIPH_IS31_SHIFT_MODE_UNKNOWN,
PERIPH_IS31_SHIFT_MODE_ACC, /*!< accumulation mode */
PERIPH_IS31_SHIFT_MODE_SINGLE,
} periph_is31_shift_mode_t;
/**
* @brief The configuration of is31fl3216
*/
typedef struct
{
uint32_t duty[IS31FL3216_CH_NUM]; /*!<An array of the is31fl3216's duty*/
uint16_t is31fl3216_pattern; /*!<Current enable channel*/
periph_is31fl3216_state_t state; /*!<The state of all the channels*/
} periph_is31fl3216_cfg_t;
/**
* @brief Initializate the is31fl3216
*
* @param is31fl3216_config
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_periph_handle_t
periph_is31fl3216_init (periph_is31fl3216_cfg_t *is31fl3216_config);
/**
* @brief Set the state of all the channels
*
* @param periph The is31fl3216 handle
* @param state The state of all channels
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t periph_is31fl3216_set_state (esp_periph_handle_t periph,
periph_is31fl3216_state_t state);
/**
* @brief Set the current enable channels
*
* @param periph The is31fl3216 handle
* @param blink_pattern The bit pattern of enabled channels
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t periph_is31fl3216_set_blink_pattern (esp_periph_handle_t periph,
uint16_t blink_pattern);
/**
* @brief Set the duty of the channel
*
* @param periph The is31fl3216 handle
* @param index The channel number
* @param value The value of the channel's duty to be
* set
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t periph_is31fl3216_set_duty (esp_periph_handle_t periph,
uint8_t index, uint8_t value);
/**
* @brief Set the duty step of flash
*
* @param periph The is31fl3216 handle
* @param step The step of flash
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t periph_is31fl3216_set_duty_step (esp_periph_handle_t periph,
uint8_t step);
/**
* @brief Set the internval time
*
* @param periph The is31fl3216 handle
* @param interval_ms Time of interval
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t periph_is31fl3216_set_interval (esp_periph_handle_t periph,
uint16_t interval_ms);
/**
* @brief Set the shift mode
*
* @param periph The is31fl3216 handle
* @param mode Mode of periph_is31_shift_mode_t
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t periph_is31fl3216_set_shift_mode (esp_periph_handle_t periph,
periph_is31_shift_mode_t mode);
/**
* @brief Set the light on numbers
*
* @param periph The is31fl3216 handle
* @param light_on_num Enabled led number
* @param max_light_num Maximum led number
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t periph_is31fl3216_set_light_on_num (esp_periph_handle_t periph,
uint16_t light_on_num,
uint16_t max_light_num);
/**
* @brief Set the action time
*
* @param periph The is31fl3216 handle
* @param act_ms Action time, unit is millisecond, 0 is
* infinite
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t periph_is31fl3216_set_act_time (esp_periph_handle_t periph,
uint16_t act_ms);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,128 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _PERIPH_LED_H_
#define _PERIPH_LED_H_
#include "audio_common.h"
#include "driver/ledc.h"
#include "esp_err.h"
#include "esp_peripherals.h"
#include "sys/queue.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Peripheral LED event id
*/
typedef enum
{
PERIPH_LED_UNCHANGE = 0, /*!< No event */
PERIPH_LED_BLINK_FINISH, /*!< When LED blink is finished */
} periph_led_event_id_t;
/**
* @brief Peripheral LED idle output level
*/
typedef enum
{
PERIPH_LED_IDLE_LEVEL_LOW, /*!< Low level output */
PERIPH_LED_IDLE_LEVEL_HIGH /*!< High level output */
} periph_led_idle_level_t;
/**
* @brief The LED peripheral configuration
*/
typedef struct
{
ledc_mode_t led_speed_mode; /*!< LEDC speed speed_mode, high-speed mode or
low-speed mode */
ledc_timer_bit_t led_duty_resolution; /*!< LEDC channel duty resolution */
ledc_timer_t
led_timer_num; /*!< Select the timer source of channel (0 - 3) */
uint32_t led_freq_hz; /*!< LEDC timer frequency (Hz) */
int gpio_num; /*!< Optional, < 0 invalid gpio number */
} periph_led_cfg_t;
/**
* @brief Create the LED peripheral handle for esp_peripherals
*
* @note The handle was created by this function automatically destroy
* when `esp_periph_destroy` is called
*
* @param config The configuration
*
* @return The esp peripheral handle
*/
esp_periph_handle_t periph_led_init (periph_led_cfg_t *config);
/**
* @brief Bink LED Peripheral, this function will automatically
* configure the gpio_num to control the LED, with `time_on_ms` as the time
* (in milliseconds) switch from OFF to ON (or ON if fade is disabled), and
* `time_off_ms` as the time (in milliseconds) switch from ON to OFF (or OFF
* if fade is disabled). When switching from ON -> OFF and vice versa, the
* loop decreases once, and will turn off the effect when the loop is 0. With
* a loop value less than 0, the LED effect will loop endlessly.
* PERIPH_LED_BLINK_FINISH events will be sent at each end of
* loop
*
* @param[in] periph The LED periph
* @param[in] gpio_num The gpio number
* @param[in] time_on_ms The time on milliseconds
* @param[in] time_off_ms The time off milliseconds
* @param[in] fade Fading enabled
* @param[in] loop Loop
* @param[in] level idle level
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t periph_led_blink (esp_periph_handle_t periph, int gpio_num,
int time_on_ms, int time_off_ms, bool fade,
int loop, periph_led_idle_level_t level);
/**
* @brief Stop Blink the LED
*
* @param[in] periph The periph
* @param[in] gpio_num The gpio number
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t periph_led_stop (esp_periph_handle_t periph, int gpio_num);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,101 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _SDCARD_DEV_H_
#define _SDCARD_DEV_H_
#include "audio_common.h"
#include "audio_error.h"
#include "esp_peripherals.h"
#include "sys/queue.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Peripheral sdcard event id
*/
typedef enum
{
SDCARD_STATUS_UNKNOWN, /*!< No event */
SDCARD_STATUS_CARD_DETECT_CHANGE, /*!< Detect changes in the card_detect
pin */
SDCARD_STATUS_MOUNTED, /*!< SDCARD mounted successfully */
SDCARD_STATUS_UNMOUNTED, /*!< SDCARD unmounted successfully */
SDCARD_STATUS_MOUNT_ERROR, /*!< SDCARD mount error */
SDCARD_STATUS_UNMOUNT_ERROR, /*!< SDCARD unmount error */
} periph_sdcard_event_id_t;
/**
* @brief SD card mode, SPI, 1-line SD mode, 4-line SD mode
*
*/
typedef enum
{
SD_MODE_SPI = 0x0, /*!< sd_card SPI*/
SD_MODE_1_LINE = 0x1, /*!< sd_card 1-line SD mode*/
SD_MODE_4_LINE = 0x2, /*!< sd_card 4-line SD mode*/
SD_MODE_MAX,
} periph_sdcard_mode_t;
/**
* @brief The SD Card Peripheral configuration
*/
typedef struct
{
int card_detect_pin; /*!< Card detect gpio number */
const char *root; /*!< Base path for vfs */
periph_sdcard_mode_t mode; /*!< card mode*/
} periph_sdcard_cfg_t;
/**
* @brief Create the sdcard peripheral handle for esp_peripherals
*
* @note The handle was created by this function automatically destroy
* when `esp_periph_destroy` is called
*
* @param sdcard_config The sdcard configuration
*
* @return The esp peripheral handle
*/
esp_periph_handle_t periph_sdcard_init (periph_sdcard_cfg_t *sdcard_config);
/**
* @brief Check the sdcard is mounted or not.
*
* @param[in] periph The periph
*
* @return SDCARD mounted state
*/
bool periph_sdcard_is_mounted (esp_periph_handle_t periph);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,92 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _SPIFFS_DEV_H_
#define _SPIFFS_DEV_H_
#include "audio_common.h"
#include "audio_error.h"
#include "esp_peripherals.h"
#include "sys/queue.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Peripheral spiffs event id
*/
typedef enum
{
SPIFFS_STATUS_UNKNOWN, /*!< No event */
SPIFFS_STATUS_MOUNTED, /*!< SPIFFS mounted successfully */
SPIFFS_STATUS_UNMOUNTED, /*!< SPIFFS unmounted successfully */
SPIFFS_STATUS_MOUNT_ERROR, /*!< SPIFFS mount error */
SPIFFS_STATUS_UNMOUNT_ERROR, /*!< SPIFFS unmount error */
} periph_spiffs_event_id_t;
/**
* @brief The SPIFFS Peripheral configuration
*/
typedef struct
{
const char *root; /*!< Base path for vfs */
const char *partition_label; /*!< Optional, label of SPIFFS partition to
use. If set to NULL, first partition with
subtype=spiffs will be used. */
size_t max_files; /*!< Maximum number of files that could be open at the
same time. */
bool format_if_mount_failed; /*!< If true, it will format the file system
if it fails to mount. */
} periph_spiffs_cfg_t;
/**
* @brief Create the spiffs peripheral handle for esp_peripherals
*
* @note The handle created by this function will be automatically
* destroyed when `esp_periph_destroy` is called
*
* @param spiffs_config The spiffs configuration
*
* @return The esp peripheral handle
*/
esp_periph_handle_t periph_spiffs_init (periph_spiffs_cfg_t *spiffs_config);
/**
* @brief Check if the SPIFFS is mounted or not.
*
* @param[in] periph The periph
*
* @return SPIFFS mounted state
*/
bool periph_spiffs_is_mounted (esp_periph_handle_t periph);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,102 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _TOUCH_DEV_H_
#define _TOUCH_DEV_H_
#include "audio_common.h"
#include "audio_error.h"
#include "esp_peripherals.h"
#include "sys/queue.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Touch pad selection
*/
typedef enum
{
TOUCH_PAD_SEL0 = BIT (0),
TOUCH_PAD_SEL1 = BIT (1),
TOUCH_PAD_SEL2 = BIT (2),
TOUCH_PAD_SEL3 = BIT (3),
TOUCH_PAD_SEL4 = BIT (4),
TOUCH_PAD_SEL5 = BIT (5),
TOUCH_PAD_SEL6 = BIT (6),
TOUCH_PAD_SEL7 = BIT (7),
TOUCH_PAD_SEL8 = BIT (8),
TOUCH_PAD_SEL9 = BIT (9),
} esp_touch_pad_sel_t;
/**
* @brief The Touch peripheral configuration
*/
typedef struct
{
int touch_mask; /*!< Touch pad mask using for this Touch peripheral, ex:
TOUCH_PAD_SEL0 | TOUCH_PAD_SEL1 */
int tap_threshold_percent; /*!< Tap threshold percent, Tap event will be
determined if the percentage value is less
than the non-touch value */
int long_tap_time_ms; /*!< Long tap duration in milliseconds, default is
2000ms, PERIPH_TOUCH_LONG_TAP will be occurred if
TAP and time hold longer than this value */
} periph_touch_cfg_t;
/**
* @brief Peripheral touch event id
*/
typedef enum
{
PERIPH_TOUCH_UNCHANGE = 0, /*!< No event */
PERIPH_TOUCH_TAP, /*!< When touch pad is tapped */
PERIPH_TOUCH_RELEASE, /*!< When touch pad is released after tap */
PERIPH_TOUCH_LONG_TAP, /*!< When touch pad is tapped and held after
`long_tap_time_ms` time */
PERIPH_TOUCH_LONG_RELEASE, /*!< When touch pad is released after long tap
*/
} periph_touch_event_id_t;
/**
* @brief Create the touch peripheral handle for esp_peripherals
*
* @note The handle was created by this function automatically destroy
* when `esp_periph_destroy` is called
*
* @param config The configuration
*
* @return The esp peripheral handle
*/
esp_periph_handle_t periph_touch_init (periph_touch_cfg_t *config);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,164 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _DEV_WIFI_H_
#define _DEV_WIFI_H_
#include "audio_common.h"
#include "audio_error.h"
#include "esp_peripherals.h"
#include "sys/queue.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Peripheral Wi-Fi event id
*/
typedef enum
{
PERIPH_WIFI_UNCHANGE = 0,
PERIPH_WIFI_CONNECTING,
PERIPH_WIFI_CONNECTED,
PERIPH_WIFI_DISCONNECTED,
PERIPH_WIFI_SETTING,
PERIPH_WIFI_CONFIG_DONE,
PERIPH_WIFI_CONFIG_ERROR,
PERIPH_WIFI_ERROR,
} periph_wifi_state_t;
/**
* @brief Wi-Fi setup mode type
*/
typedef enum
{
WIFI_CONFIG_ESPTOUCH, /*!< Using smartconfig with ESPTOUCH protocol */
WIFI_CONFIG_AIRKISS, /*!< Using smartconfig with AIRKISS protocol */
WIFI_CONFIG_ESPTOUCH_AIRKISS, /*!< Using smartconfig with ESPTOUCH_AIRKISS
protocol */
WIFI_CONFIG_WPS, /*!< Using WPS (not support) */
WIFI_CONFIG_BLUEFI, /*!< Using BLUEFI*/
WIFI_CONFIG_WEB, /*!< Using HTTP Server (not support) */
} periph_wifi_config_mode_t;
/**
* @brief The WPA2 enterprise peripheral configuration
*/
typedef struct
{
bool diasble_wpa2_e; /*!< Disable wpa2 enterprise */
int eap_method; /*!< TLS: 0, PEAP: 1, TTLS: 2 */
char *ca_pem_start; /*!< binary wpa2 ca pem start */
char *ca_pem_end; /*!< binary wpa2 ca pem end */
char *wpa2_e_cert_start; /*!< binary wpa2 cert start */
char *wpa2_e_cert_end; /*!< binary wpa2 cert end */
char *wpa2_e_key_start; /*!< binary wpa2 key start */
char *wpa2_e_key_end; /*!< binary wpa2 key end */
const char *eap_id; /*!< Identity in phase 1 of EAP procedure */
const char *eap_username; /*!< Username for EAP method (PEAP and TTLS) */
const char *eap_password; /*!< Password for EAP method (PEAP and TTLS) */
} periph_wpa2_enterprise_cfg_t;
/**
* @brief The Wi-Fi peripheral configuration
*/
typedef struct
{
bool disable_auto_reconnect; /*!< Disable Wi-Fi auto reconnect */
int reconnect_timeout_ms; /*!< The reconnect timeout after disconnected
from Wi-Fi network */
const char *ssid; /*!< SSID of target AP */
const char *password; /*!< password of target AP */
periph_wpa2_enterprise_cfg_t wpa2_e_cfg; /*!< wpa2 enterprise config */
} periph_wifi_cfg_t;
/**
* @brief Create the wifi peripheral handle for esp_peripherals
*
* @note The handle was created by this function automatically destroy
* when `esp_periph_destroy` is called
*
* @param config The configuration
*
* @return The esp peripheral handle
*/
esp_periph_handle_t periph_wifi_init (periph_wifi_cfg_t *config);
/**
* @brief This function will block current thread (in `tick_to_wait`
* tick) and wait until ESP32 connected to the Wi-Fi network, and got ip
*
* @param[in] periph The periph
* @param[in] tick_to_wait The tick to wait
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t periph_wifi_wait_for_connected (esp_periph_handle_t periph,
TickType_t tick_to_wait);
/**
* @brief Check the Wi-Fi connection status
*
* @param[in] periph The periph
*
* @return Wi-Fi network status
*/
periph_wifi_state_t periph_wifi_is_connected (esp_periph_handle_t periph);
/**
* @brief Start Wi-Fi network setup in `mode`
*
* @param[in] periph The periph
* @param[in] mode The mode
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t periph_wifi_config_start (esp_periph_handle_t periph,
periph_wifi_config_mode_t mode);
/**
* @brief Wait for Wi-Fi setup done
* @param[in] periph The periph
* @param[in] tick_to_wait The tick to wait
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t periph_wifi_config_wait_done (esp_periph_handle_t periph,
TickType_t tick_to_wait);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,129 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _PERIPH_WS2812_DRIVER_H
#define _PERIPH_WS2812_DRIVER_H
#include "esp_peripherals.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief The RGB peripheral value
*/
typedef uint32_t periph_rgb_value;
#define make_rgb_value(x, y, z) (((int)(z) << 16) + ((int)(y) << 8) + (x))
#define LED2812_COLOR_BLACK make_rgb_value (0, 0, 0)
#define LED2812_COLOR_BLUE make_rgb_value (0, 0, 255)
#define LED2812_COLOR_GREEN make_rgb_value (0, 255, 0)
#define LED2812_COLOR_CYAN make_rgb_value (0, 255, 255)
#define LED2812_COLOR_RED make_rgb_value (255, 0, 0)
#define LED2812_COLOR_PURPLE make_rgb_value (255, 0, 255)
#define LED2812_COLOR_YELLOW make_rgb_value (255, 255, 0)
#define LED2812_COLOR_WHITE make_rgb_value (255, 255, 255)
#define LED2812_COLOR_ORANGE make_rgb_value (255, 165, 0)
/**
* @brief The ws2812 peripheral configuration
*/
typedef struct
{
int gpio_num; /*!< The GPIO number of ws2812*/
int led_num; /*!< The number of ws2812 */
} periph_ws2812_cfg_t;
/**
* @brief The periph ws2812 mode
*/
typedef enum
{
PERIPH_WS2812_BLINK,
PERIPH_WS2812_FADE,
PERIPH_WS2812_ONE,
} periph_ws2812_mode_t;
/**
* @brief The periph ws2812 control config
*/
typedef struct periph_ws2812_ctrl_cfg
{
periph_rgb_value color; /*!< The RGB value */
uint32_t
time_on_ms; /*!< The time on milliseconds, suggest min is 100 ms */
uint32_t
time_off_ms; /*!< The time off milliseconds, suggest min is 100 ms */
uint32_t loop; /*!< The times offloop */
periph_ws2812_mode_t
mode; /*!< ws2812 mode (setting color, blink or fade) */
} periph_ws2812_ctrl_cfg_t;
/**
* @brief Create the ws2812 peripheral handle for esp_peripherals
*
* @note The handle was created by this function automatically destroy
* when `esp_periph_destroy` is called
*
* @param config The configuration
*
* @return The esp peripheral handle
*/
esp_periph_handle_t periph_ws2812_init (periph_ws2812_cfg_t *config);
/**
* @brief Control ws2812 Peripheral
*
* @param[in] periph The ws2812 periph
* @param[in] control_cfg The ws2812 color config
* @param[in] ctx The ctx
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t periph_ws2812_control (esp_periph_handle_t periph,
periph_ws2812_ctrl_cfg_t *control_cfg,
void *ctx);
/**
* @brief Stop ws2812
*
* @param[in] periph The periph
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t periph_ws2812_stop (esp_periph_handle_t periph);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,445 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "IS31FL3216.h"
#include "audio_mem.h"
#include "driver/i2c.h"
#include "esp_log.h"
#include "i2c_bus.h"
#include <stdio.h>
#include <string.h>
#define IS31FL3216_WRITE_BIT 0x00
#define I2C_MASTER_SCL_IO 23 /*!< gpio number for I2C master clock */
#define I2C_MASTER_SDA_IO 18 /*!< gpio number for I2C master data */
#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */
#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */
#define IS31FL3216_ADDRESS 0xE8 /*!< I2C Addr*/
#define IS31_ERROR_CHECK(con) \
if (!(con)) \
{ \
ESP_LOGE (TAG, "err line: %d", __LINE__); \
}
#define IS31_PARAM_CHECK(con) \
if (!(con)) \
{ \
ESP_LOGE (TAG, "Parameter error: %d", __LINE__); \
}
#define IS31_CHECK_I2C_RES(res) \
if (ret == ESP_FAIL) \
{ \
ESP_LOGE (TAG, "Is31fl3216[%s]: FAIL\n", __FUNCTION__); \
} \
else if (ret == ESP_ERR_TIMEOUT) \
{ \
ESP_LOGE (TAG, "Is31fl3216[%s]: TIMEOUT\n", __FUNCTION__); \
}
typedef struct
{
i2c_bus_handle_t bus;
uint16_t addr;
} is31fl3216_dev_t;
uint8_t Is31Value[10]
= { 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static char *TAG = "IS31";
/**
* @brief set software shutdown mode
*/
static esp_err_t
is31fl3216_write_reg (is31fl3216_handle_t handle, is31fl3216_reg_t regAddr,
uint8_t *data, uint8_t data_num)
{
IS31_PARAM_CHECK (NULL != data);
is31fl3216_dev_t *dev = (is31fl3216_dev_t *)handle;
esp_err_t ret = i2c_bus_write_bytes (
dev->bus, IS31FL3216_ADDRESS | IS31FL3216_WRITE_BIT, (uint8_t *)&regAddr,
1, data, data_num);
return ret;
}
/**
* @brief change channels PWM duty cycle data register
*/
static esp_err_t
is31fl3218S_channel_duty_by_bits (is31fl3216_handle_t handle, uint32_t by_bits,
uint8_t duty)
{
for (int i = 0; i < IS31FL3216_CH_NUM_MAX; i++)
{
if ((by_bits >> i) & 0x1)
{
esp_err_t ret = is31fl3216_write_reg (
handle, IS31FL3216_REG_PWM_16 + (IS31FL3216_CH_NUM_MAX - i - 1),
&duty, 1);
if (ret == ESP_OK)
{
// PASS
}
else
{
IS31_CHECK_I2C_RES (ret);
return ret;
}
}
}
return ESP_OK;
}
/**
* @brief Load PWM Register and LED Control Registers data
*/
esp_err_t
is31fl3216_update_reg (is31fl3216_handle_t handle)
{
IS31_PARAM_CHECK (NULL != handle);
uint8_t m = 0;
return is31fl3216_write_reg (handle, IS31FL3216_REG_UPDATE, &m, 1);
}
/**
* @brief set software shutdown mode
*/
esp_err_t
is31fl3216_power (is31fl3216_handle_t handle, is31fl3216_pwr_t mode)
{
IS31_PARAM_CHECK (NULL != handle);
if (IS31FL3216_PWR_SHUTDOWN == mode)
{
Is31Value[IS31FL3216_REG_CONFIG]
= (Is31Value[IS31FL3216_REG_CONFIG] & (~(1 << 7))) | (1 << 7);
}
else if (IS31FL3216_PWR_NORMAL == mode)
{
Is31Value[IS31FL3216_REG_CONFIG]
= (Is31Value[IS31FL3216_REG_CONFIG] & (~(1 << 7)));
}
else
{
return ESP_FAIL;
}
esp_err_t ret
= is31fl3216_write_reg (handle, IS31FL3216_REG_CONFIG,
(uint8_t *)&Is31Value[IS31FL3216_REG_CONFIG], 1);
return ret;
}
esp_err_t
is31fl3216_work_mode_set (is31fl3216_handle_t handle,
is31fl3216_work_mode_t mode)
{
IS31_PARAM_CHECK (NULL != handle);
if (IS31FL3216_MODE_PWM == mode)
{
Is31Value[IS31FL3216_REG_CONFIG]
= (Is31Value[IS31FL3216_REG_CONFIG] & (~(3 << 5)));
}
else if (IS31FL3216_MODE_AUTO_FRAME == mode)
{
Is31Value[IS31FL3216_REG_CONFIG]
= (Is31Value[IS31FL3216_REG_CONFIG] & (~(3 << 5))) | (1 << 5);
}
else if (IS31FL3216_MODE_FRAME == mode)
{
Is31Value[IS31FL3216_REG_CONFIG]
= (Is31Value[IS31FL3216_REG_CONFIG] & (~(3 << 5))) | (2 << 5);
}
else
{
return ESP_FAIL;
}
esp_err_t ret
= is31fl3216_write_reg (handle, IS31FL3216_REG_CONFIG,
(uint8_t *)&Is31Value[IS31FL3216_REG_CONFIG], 1);
return ret;
}
/**
* @brief change channels PWM duty cycle data register
*/
esp_err_t
is31fl3216_ch_duty_set (is31fl3216_handle_t handle, is31_pwm_channel_t ch_bits,
uint8_t duty)
{
esp_err_t ret = ESP_OK;
IS31_PARAM_CHECK (NULL != handle);
ret = is31fl3218S_channel_duty_by_bits (handle, ch_bits, duty);
if (ret != ESP_OK)
{
IS31_CHECK_I2C_RES (ret);
return ret;
}
ret = is31fl3216_update_reg (handle);
if (ret != ESP_OK)
{
IS31_CHECK_I2C_RES (ret);
return ret;
}
return ESP_OK;
}
/**
* @brief change channels PWM duty cycle data register
*/
esp_err_t
is31fl3216_ch_enable (is31fl3216_handle_t handle, is31_pwm_channel_t ch_bits)
{
esp_err_t ret = ESP_OK;
IS31_PARAM_CHECK (NULL != handle);
uint16_t value = 0;
for (int i = 0; i < IS31FL3216_CH_NUM_MAX; ++i)
{
if ((ch_bits >> i) & 0x01)
{
value |= (1 << i);
}
}
Is31Value[IS31FL3216_REG_LED_CTRL_H] |= value >> 8;
Is31Value[IS31FL3216_REG_LED_CTRL_L] |= value;
ret = is31fl3216_write_reg (handle, IS31FL3216_REG_LED_CTRL_H,
&Is31Value[IS31FL3216_REG_LED_CTRL_H], 2);
return ret;
}
/**
* @brief change channels PWM duty cycle data register
*/
esp_err_t
is31fl3216_ch_disable (is31fl3216_handle_t handle, is31_pwm_channel_t ch_bits)
{
esp_err_t ret = ESP_OK;
IS31_PARAM_CHECK (NULL != handle);
uint16_t value = ((uint16_t)Is31Value[IS31FL3216_REG_LED_CTRL_H]) << 8;
value |= Is31Value[IS31FL3216_REG_LED_CTRL_L];
for (int i = 0; i < IS31FL3216_CH_NUM_MAX; ++i)
{
if ((ch_bits >> i) & 0x01)
{
value = value & (~(1 << i));
}
}
Is31Value[IS31FL3216_REG_LED_CTRL_H] = value >> 8;
Is31Value[IS31FL3216_REG_LED_CTRL_L] = value;
ret = is31fl3216_write_reg (handle, IS31FL3216_REG_LED_CTRL_H,
&Is31Value[IS31FL3216_REG_LED_CTRL_H], 2);
return ret;
}
esp_err_t
is31fl3216_cur_mode_set (is31fl3216_handle_t handle,
is31fl3216_cur_mode_t mode)
{
IS31_PARAM_CHECK (NULL != handle);
if (IS31FL3216_CUR_MODE_REXT == mode)
{
Is31Value[IS31FL3216_REG_CONFIG]
= (Is31Value[IS31FL3216_REG_CONFIG] & (~(1 << 4)));
}
else if (IS31FL3216_CUR_MODE_AUDIO == mode)
{
Is31Value[IS31FL3216_REG_CONFIG]
= (Is31Value[IS31FL3216_REG_CONFIG] & (~(1 << 4))) | (1 << 4);
}
else
{
return ESP_FAIL;
}
esp_err_t ret
= is31fl3216_write_reg (handle, IS31FL3216_REG_CONFIG,
(uint8_t *)&Is31Value[IS31FL3216_REG_CONFIG], 1);
return ret;
}
esp_err_t
is31fl3216_cur_value_set (is31fl3216_handle_t handle,
is31fl3216_cur_value_t value)
{
IS31_PARAM_CHECK (NULL != handle);
Is31Value[IS31FL3216_REG_LED_EFFECT]
= (Is31Value[IS31FL3216_REG_LED_EFFECT] & (~(7 << 4))) | value << 4;
esp_err_t ret
= is31fl3216_write_reg (handle, IS31FL3216_REG_LED_EFFECT,
&Is31Value[IS31FL3216_REG_LED_EFFECT], 1);
return ret;
}
esp_err_t
is31fl3216_ags_value_set (is31fl3216_handle_t handle,
is31fl3216_ags_value_t value)
{
IS31_PARAM_CHECK (NULL != handle);
Is31Value[IS31FL3216_REG_LED_EFFECT]
= (Is31Value[IS31FL3216_REG_LED_EFFECT] & (~(7 << 0))) | value << 0;
esp_err_t ret
= is31fl3216_write_reg (handle, IS31FL3216_REG_LED_EFFECT,
&Is31Value[IS31FL3216_REG_LED_EFFECT], 1);
return ret;
}
esp_err_t
is31fl3216_agc_cfg (is31fl3216_handle_t handle, uint32_t en)
{
IS31_PARAM_CHECK (NULL != handle);
Is31Value[IS31FL3216_REG_LED_EFFECT]
= (Is31Value[IS31FL3216_REG_LED_EFFECT] & (~(1 << 3))) | en << 3;
esp_err_t ret
= is31fl3216_write_reg (handle, IS31FL3216_REG_LED_EFFECT,
&Is31Value[IS31FL3216_REG_LED_EFFECT], 1);
return ret;
}
esp_err_t
is31fl3216_cascade_mode_set (is31fl3216_handle_t handle,
is31fl3216_cascade_mode_t mode)
{
IS31_PARAM_CHECK (NULL != handle);
Is31Value[IS31FL3216_REG_LED_EFFECT]
= (Is31Value[IS31FL3216_REG_LED_EFFECT] & (~(1 << 7))) | mode << 7;
esp_err_t ret
= is31fl3216_write_reg (handle, IS31FL3216_REG_LED_EFFECT,
&Is31Value[IS31FL3216_REG_LED_EFFECT], 1);
return ret;
}
esp_err_t
is31fl3216_sample_rate_set (is31fl3216_handle_t handle, uint32_t value)
{
IS31_PARAM_CHECK (NULL != handle);
uint8_t dat = value;
esp_err_t ret
= is31fl3216_write_reg (handle, IS31FL3216_REG_ADC_RATE, &dat, 1);
return ret;
}
esp_err_t
is31fl3216_frame_time_set (is31fl3216_handle_t handle,
is31fl3216_delay_time_t time)
{
IS31_PARAM_CHECK (NULL != handle);
uint8_t dat = time << 5;
esp_err_t ret
= is31fl3216_write_reg (handle, IS31FL3216_REG_FRAME_DELAY, &dat, 1);
return ret;
}
esp_err_t
is31fl3216_first_frame_set (is31fl3216_handle_t handle, uint32_t frame)
{
IS31_PARAM_CHECK (NULL != handle);
uint8_t dat = frame << 5;
esp_err_t ret
= is31fl3216_write_reg (handle, IS31FL3216_REG_FRAME_START, &dat, 1);
return ret;
}
esp_err_t
is31fl3216_frame_value_set (is31fl3216_handle_t handle, uint32_t num,
uint8_t *data, uint32_t len)
{
IS31_PARAM_CHECK (NULL != handle);
IS31_PARAM_CHECK (NULL != data);
uint8_t startAddr = IS31FL3216_REG_FRAME1_CTRL + (num - 1) * 18;
esp_err_t ret = is31fl3216_write_reg (handle, startAddr, data, len);
return ret;
}
esp_err_t
is31fl3216_reset (is31fl3216_handle_t handle)
{
esp_err_t ret = ESP_OK;
uint8_t dat = 0x00;
IS31_PARAM_CHECK (NULL != handle);
ret = is31fl3216_power (handle, IS31FL3216_PWR_NORMAL);
if (ret)
{
return ret;
}
for (int i = 0; i < IS31FL3216_CH_NUM_MAX; ++i)
{
ret = is31fl3216_ch_duty_set (handle, 1 << i, 0);
if (ret)
{
return ret;
}
}
ret = is31fl3216_ch_enable (handle, IS31FL3216_CH_ALL);
if (ret)
{
return ret;
}
ret = is31fl3216_write_reg (handle, IS31FL3216_REG_LED_EFFECT, &dat, 1);
if (ret)
{
return ret;
}
ret = is31fl3216_write_reg (handle, IS31FL3216_REG_CH_CONFIG, &dat, 1);
return ret;
}
/**
* @brief i2c master initialization
*/
is31fl3216_handle_t
is31fl3216_init (void)
{
i2c_config_t conf = { 0 };
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = I2C_MASTER_SDA_IO;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_io_num = I2C_MASTER_SCL_IO;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
is31fl3216_dev_t *led
= (is31fl3216_dev_t *)audio_calloc (1, sizeof (is31fl3216_dev_t));
led->bus = i2c_bus_create (I2C_MASTER_NUM, &conf);
led->addr = IS31FL3216_ADDRESS;
IS31_ERROR_CHECK (ESP_OK == is31fl3216_power (led, IS31FL3216_PWR_NORMAL));
IS31_ERROR_CHECK (
ESP_OK == is31fl3216_cur_mode_set (led, IS31FL3216_CUR_MODE_REXT));
IS31_ERROR_CHECK (ESP_OK
== is31fl3216_cur_value_set (led, IS31FL3216_CUR_0_75));
return (is31fl3216_handle_t)led;
}
esp_err_t
is31fl3216_deinit (is31fl3216_handle_t handle)
{
is31fl3216_dev_t *dev = (is31fl3216_dev_t *)handle;
if (dev->bus)
{
i2c_bus_delete (dev->bus);
dev->bus = NULL;
}
audio_free (dev);
return ESP_OK;
}

View File

@@ -0,0 +1,433 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _IOT_IS31FL3216_H_
#define _IOT_IS31FL3216_H_
#include "driver/i2c.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define IS31FL3216_CH_NUM_MAX 16
#define IS31FL3216_DUTY_MAX 255
typedef enum
{
IS31FL3216_PWR_NORMAL = 0, /**< Normal operation */
IS31FL3216_PWR_SHUTDOWN, /**< Software shutdown mode */
IS31FL3216_PWR_MAX,
} is31fl3216_pwr_t;
typedef enum
{
IS31FL3216_MODE_PWM = 0, /**< PWM control mode operation*/
IS31FL3216_MODE_AUTO_FRAME, /**< Auto frame play mode operation */
IS31FL3216_MODE_FRAME, /**< Audio frame mode operation */
IS31FL3216_MODE_MAX,
} is31fl3216_work_mode_t;
typedef enum
{
IS31FL3216_CUR_MODE_REXT = 0, /**< Output current is set by register */
IS31FL3216_CUR_MODE_AUDIO, /**< Output current is modulated by audio signal
*/
IS31FL3216_CUR_MODE_MAX,
} is31fl3216_cur_mode_t;
typedef enum
{
IS31FL3216_CUR_1_00 = 0, /**< Output Current Selection */
IS31FL3216_CUR_0_75,
IS31FL3216_CUR_0_50,
IS31FL3216_CUR_0_25,
IS31FL3216_CUR_2_00,
IS31FL3216_CUR_1_75,
IS31FL3216_CUR_1_50,
IS31FL3216_CUR_1_25,
IS31FL3216_CUR_MAX,
} is31fl3216_cur_value_t;
typedef enum
{
IS31FL3216_CASCADE_MASTER = 0, /**< Chip Cascade Mode */
IS31FL3216_CASCADE_SLAVE,
} is31fl3216_cascade_mode_t;
typedef enum
{
IS31FL3216_AGS_0DB = 0, /**< Audio Gain Selection */
IS31FL3216_AGS_3DB,
IS31FL3216_AGS_6DB,
IS31FL3216_AGS_9DB,
IS31FL3216_AGS_12DB,
IS31FL3216_AGS_15DB,
IS31FL3216_AGS_18DB,
IS31FL3216_AGS_21DB,
IS31FL3216_AGS_MAX,
} is31fl3216_ags_value_t;
typedef enum
{
IS31FL3216_TIME_32MS = 0, /**< Frame Delay Time */
IS31FL3216_TIME_64MS,
IS31FL3216_TIME_128MS,
IS31FL3216_TIME_256MS,
IS31FL3216_TIME_512MS,
IS31FL3216_TIME_1024MS,
IS31FL3216_TIME_2048MS,
IS31FL3216_TIME_4096MS,
IS31FL3216_TIME_MAX,
} is31fl3216_delay_time_t;
typedef enum
{
IS31FL3216_REG_CONFIG = 0x00, /* Configuration register */
IS31FL3216_REG_LED_CTRL_H
= 0x01, /* LED control register OUT9-OUT16 enable bit */
IS31FL3216_REG_LED_CTRL_L
= 0x02, /* LED control register OUT1-OUT8 enable bit */
IS31FL3216_REG_LED_EFFECT
= 0x03, /* Set the output current and the audio gain */
IS31FL3216_REG_CH_CONFIG = 0x04, /* Set the operating mode of OUT9~OUT16 */
IS31FL3216_REG_GPIO_CONFIG
= 0x05, /* Set the operating mode of OUT9~OUT16 as the GPIO port */
IS31FL3216_REG_OUTPUT
= 0x06, /* Set the logic level of OUT9~OUT16 as the output port */
IS31FL3216_REG_INPUT_CTRL
= 0x07, /* Set the interrupt function of OUT9~OUT16 */
IS31FL3216_REG_STATE
= 0x08, /* Store the state of OUT9~OUT16 as the input port */
IS31FL3216_REG_ADC_RATE
= 0x09, /* Set the ADC sample rate of the input signal */
IS31FL3216_REG_PWM_16 = 0x10, /* Set the PWM duty cycle data */
IS31FL3216_REG_PWM_15,
IS31FL3216_REG_PWM_14,
IS31FL3216_REG_PWM_13,
IS31FL3216_REG_PWM_12,
IS31FL3216_REG_PWM_11,
IS31FL3216_REG_PWM_10,
IS31FL3216_REG_PWM_09,
IS31FL3216_REG_PWM_08,
IS31FL3216_REG_PWM_07,
IS31FL3216_REG_PWM_06,
IS31FL3216_REG_PWM_05,
IS31FL3216_REG_PWM_04,
IS31FL3216_REG_PWM_03,
IS31FL3216_REG_PWM_02,
IS31FL3216_REG_PWM_01,
IS31FL3216_REG_FRAME1_CTRL = 0x20, /* Store the data of 8 frames */
IS31FL3216_REG_FRAME1_PWM = 0x22,
IS31FL3216_REG_FRAME2_CTRL = 0x32,
IS31FL3216_REG_FRAME2_PWM = 0x34,
IS31FL3216_REG_FRAME3_CTRL = 0x44,
IS31FL3216_REG_FRAME3_PWM = 0x46,
IS31FL3216_REG_FRAME4_CTRL = 0x56,
IS31FL3216_REG_FRAME4_PWM = 0x58,
IS31FL3216_REG_FRAME5_CTRL = 0x68,
IS31FL3216_REG_FRAME5_PWM = 0x6A,
IS31FL3216_REG_FRAME6_CTRL = 0x7A,
IS31FL3216_REG_FRAME6_PWM = 0x7C,
IS31FL3216_REG_FRAME7_CTRL = 0x8C,
IS31FL3216_REG_FRAME7_PWM = 0x8E,
IS31FL3216_REG_FRAME8_CTRL = 0x9E,
IS31FL3216_REG_FRAME8_PWM = 0xA0,
IS31FL3216_REG_UPDATE = 0xB0, /* Load PWM Register data */
IS31FL3216_REG_FRAME_DELAY
= 0xB6, /* Set the delay time between each frame */
IS31FL3216_REG_FRAME_START
= 0xB7, /* Set the start frame in Auto Frame Play Mode */
IS31FL3216_REG_MAX,
} is31fl3216_reg_t;
typedef enum
{
IS31FL3216_CH_1 = 0x0001, /**< channel by bit shit */
IS31FL3216_CH_2 = 0x0002,
IS31FL3216_CH_3 = 0x0004,
IS31FL3216_CH_4 = 0x0008,
IS31FL3216_CH_5 = 0x0010,
IS31FL3216_CH_6 = 0x0020,
IS31FL3216_CH_7 = 0x0040,
IS31FL3216_CH_8 = 0x0080,
IS31FL3216_CH_9 = 0x0100,
IS31FL3216_CH_10 = 0x0200,
IS31FL3216_CH_11 = 0x0400,
IS31FL3216_CH_12 = 0x0800,
IS31FL3216_CH_13 = 0x1000,
IS31FL3216_CH_14 = 0x2000,
IS31FL3216_CH_15 = 0x4000,
IS31FL3216_CH_16 = 0x8000,
IS31FL3216_CH_ALL = 0xFFFF,
} is31_pwm_channel_t;
typedef void *is31fl3216_handle_t;
/**
* @brief The Shutdown Register sets software shutdown mode of IS31FL3216.
*
* @param handle led dev handle
* @param mode shutdown mode or Normal
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
* - ESP_ERR_TIMEOUT timeout
*/
esp_err_t is31fl3216_power (is31fl3216_handle_t handle,
is31fl3216_pwr_t mode);
/**
* @brief set the duty for the channels
*
* @param handle led dev handle
* @param ch_bits the sequence num of channels //e.g.: 1UL << the number of
* channel
* @param duty set the duty between 0-255
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t is31fl3216_ch_duty_set (is31fl3216_handle_t handle,
is31_pwm_channel_t ch_bits, uint8_t duty);
/**
* @brief set the work mode of channels
*
* @param handle led dev handle
* @param mode led work mode
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t is31fl3216_work_mode_set (is31fl3216_handle_t handle,
is31fl3216_work_mode_t mode);
/**
* @brief enable the channels
*
* @param handle led dev handle
* @param ch_bits the sequence num of channels //e.g.: ch_bits = 1UL << the
* number of channel
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t is31fl3216_ch_enable (is31fl3216_handle_t handle,
is31_pwm_channel_t ch_bits);
/**
* @brief disable the channels
*
* @param handle led dev handle
* @param ch_bits the sequence num of channels //e.g.: chbits = 1UL << the
* number of channel
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t is31fl3216_ch_disable (is31fl3216_handle_t handle,
is31_pwm_channel_t ch_bits);
/**
* @brief set the mode of output current
*
* @param handle led dev handle
* @param mode output current mode
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t is31fl3216_cur_mode_set (is31fl3216_handle_t handle,
is31fl3216_cur_mode_t mode);
/**
* @brief set the value of output current
*
* @param handle led dev handle
* @param value output current value
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t is31fl3216_cur_value_set (is31fl3216_handle_t handle,
is31fl3216_cur_value_t value);
/**
* @brief choose the audio gain
*
* @param handle led dev handle
* @param value selection of audio gain
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t is31fl3216_ags_value_set (is31fl3216_handle_t handle,
is31fl3216_ags_value_t value);
/**
* @brief enable or disable audio gain
*
* @param handle led dev handle
* @param en 0 or 1 to switch the audio gain
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t is31fl3216_agc_cfg (is31fl3216_handle_t handle, uint32_t en);
/**
* @brief set the mode of chip cascade
*
* @param handle led dev handle
* @param mode chip cascade mode
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t is31fl3216_cascade_mode_set (is31fl3216_handle_t handle,
is31fl3216_cascade_mode_t mode);
/**
* @brief update the register
*
* @param handle led dev handle
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t is31fl3216_update_reg (is31fl3216_handle_t handle);
/**
* @brief set the sample rate
*
* @param handle led dev handle
* @param value set value
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t is31fl3216_sample_rate_set (is31fl3216_handle_t handle,
uint32_t value);
/**
* @brief set the frame time
*
* @param handle led dev handle
* @param time time to set
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t is31fl3216_frame_time_set (is31fl3216_handle_t handle,
is31fl3216_delay_time_t time);
/**
* @brief choose the first frame to play
*
* @param handle led dev handle
* @param frame the seqence num of frame
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t is31fl3216_first_frame_set (is31fl3216_handle_t handle,
uint32_t frame);
/**
* @brief write frame data
*
* @param handle led dev handle
* @param num the seqence num of frame
* @param data data to write
* @param len the length of data
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t is31fl3216_frame_value_set (is31fl3216_handle_t handle,
uint32_t num, uint8_t *data,
uint32_t len);
/**
* @brief IS31FL3216 will reset all registers to default value.
*
* @param handle led dev handle
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
* - ESP_ERR_TIMEOUT timeout
*/
esp_err_t is31fl3216_reset (is31fl3216_handle_t handle);
/**
* @brief Create and init sensor object and return a led handle
*
* @param bus I2C bus object handle
*
* @return
* - NULL Fail
* - Others Success
*/
is31fl3216_handle_t is31fl3216_init (void);
/**
* @brief Delete and release a LED object
*
* @param sensor object handle of Is31fl3216
* @param del_bus Whether to delete the I2C bus
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t is31fl3216_deinit (is31fl3216_handle_t handle);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,505 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "audio_mem.h"
#include "driver/adc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "math.h"
#include <stdio.h>
#include <stdlib.h>
#if CONFIG_IDF_TARGET_ESP32
#include "esp_adc_cal.h"
#endif
#include "adc_button.h"
#include "audio_thread.h"
#include "esp_log.h"
#include "string.h"
#define V_REF 1100
#define ADC_SAMPLES_NUM 10
#define ADC_SAMPLE_INTERVAL_TIME_MS 20
#define DIAL_VOL_INTERVAL_TIME_MS 150
#define ADC_BTN_INVALID_ID -1
#define ADC_BTN_INVALID_ACT_ID -2
#define ADC_BTN_DETECT_TIME_MS 20
#ifndef ENABLE_ADC_VOLUME
#define USER_KEY_MAX 7
#endif
static char *TAG = "ADC_BTN";
static EventGroupHandle_t g_event_bit;
typedef struct
{
adc_button_callback btn_callback;
adc_btn_list *head;
void *user_data;
audio_thread_t audio_thread;
} adc_btn_tag_t;
static const int default_step_level[USER_KEY_MAX]
= { 0, 683, 1193, 1631, 2090, 2578, 3103 };
static const int DESTROY_BIT = BIT0;
static bool _task_flag;
adc_btn_list *
adc_btn_create_list (adc_arr_t *adc_conf, int channels)
{
adc_btn_list *head = NULL;
adc_btn_list *node = NULL;
adc_btn_list *find = NULL;
for (int i = 0; i < channels; i++)
{
node = (adc_btn_list *)audio_calloc (1, sizeof (adc_btn_list));
if (NULL == node)
{
ESP_LOGE (TAG, "Memory allocation failed! Line: %d", __LINE__);
return NULL;
}
memset (node, 0, sizeof (adc_btn_list));
adc_arr_t *info = &(node->adc_info);
memcpy (info, adc_conf + i, sizeof (adc_arr_t));
info->adc_level_step
= (int *)audio_calloc (1, (info->total_steps + 1) * sizeof (int));
memset (info->adc_level_step, 0, (info->total_steps + 1) * sizeof (int));
if (NULL == info->adc_level_step)
{
ESP_LOGE (TAG, "Memory allocation failed! Line: %d", __LINE__);
audio_free (node);
return NULL;
}
if (adc_conf[i].adc_level_step == NULL)
{
memcpy (info->adc_level_step, default_step_level,
USER_KEY_MAX * sizeof (int));
}
else
{
memcpy (info->adc_level_step, adc_conf[i].adc_level_step,
(adc_conf[i].total_steps + 1) * sizeof (int));
}
if (info->total_steps > USER_KEY_MAX)
{
ESP_LOGE (TAG, "The total_steps should be less than USER_KEY_MAX");
audio_free (info->adc_level_step);
audio_free (node);
}
node->btn_dscp = (btn_decription *)audio_calloc (
1, sizeof (btn_decription) * (adc_conf[i].total_steps));
if (NULL == node->btn_dscp)
{
ESP_LOGE (TAG, "Memory allocation failed! Line: %d", __LINE__);
audio_free (info->adc_level_step);
audio_free (node);
}
memset (node->btn_dscp, 0,
sizeof (btn_decription) * (adc_conf[i].total_steps));
node->next = NULL;
if (NULL == head)
{
head = node;
find = head;
}
else
{
find->next = node;
find = node;
}
}
return head;
}
esp_err_t
adc_btn_destroy_list (adc_btn_list *head)
{
if (head == NULL)
{
ESP_LOGD (TAG, "The head of list is null");
return ESP_OK;
}
adc_btn_list *find = head;
adc_btn_list *tmp = find;
while (find)
{
adc_arr_t *info = &(find->adc_info);
tmp = find->next;
audio_free (find->btn_dscp);
audio_free (info->adc_level_step);
audio_free (find);
find = tmp;
}
return ESP_OK;
}
static int
get_adc_voltage (int channel)
{
uint32_t data[ADC_SAMPLES_NUM] = { 0 };
uint32_t sum = 0;
int tmp = 0;
#if CONFIG_IDF_TARGET_ESP32
esp_adc_cal_characteristics_t characteristics;
esp_adc_cal_characterize (ADC_UNIT_1, ADC_ATTEN_11db, ADC_WIDTH_12Bit, V_REF,
&characteristics);
for (int i = 0; i < ADC_SAMPLES_NUM; ++i)
{
esp_adc_cal_get_voltage (channel, &characteristics, &data[i]);
}
#elif CONFIG_IDF_TARGET_ESP32S2
for (int i = 0; i < ADC_SAMPLES_NUM; i++)
{
data[i] = adc1_get_raw ((adc1_channel_t)channel);
}
#endif
for (int j = 0; j < ADC_SAMPLES_NUM - 1; j++)
{
for (int i = 0; i < ADC_SAMPLES_NUM - j - 1; i++)
{
if (data[i] > data[i + 1])
{
tmp = data[i];
data[i] = data[i + 1];
data[i + 1] = tmp;
}
}
}
for (int num = 1; num < ADC_SAMPLES_NUM - 1; num++)
sum += data[num];
return (sum / (ADC_SAMPLES_NUM - 2));
}
static int
get_button_id (adc_btn_list *node, int adc)
{
int m = ADC_BTN_INVALID_ID;
adc_arr_t *info = &(node->adc_info);
for (int i = 0; i < info->total_steps; i++)
{
ESP_LOGV (TAG, "max:%d, adc:%d, i:%d, %d, %d", info->total_steps, adc, i,
info->adc_level_step[i], info->adc_level_step[i + 1]);
if ((adc > info->adc_level_step[i])
&& (adc <= info->adc_level_step[i + 1]))
{
m = i;
break;
}
}
return m;
}
static void
reset_btn (btn_decription *btn_dscp, int btn_num)
{
memset (btn_dscp, 0, sizeof (btn_decription) * btn_num);
for (int i = 0; i < btn_num; ++i)
{
btn_dscp[i].active_id = ADC_BTN_INVALID_ID;
}
}
static adc_btn_state_t
get_adc_btn_state (int adc_value, int act_id, adc_btn_list *node)
{
adc_btn_state_t st = ADC_BTN_STATE_IDLE;
adc_arr_t *info = &(node->adc_info);
btn_decription *btn_dscp = node->btn_dscp;
int id = get_button_id (node, adc_value);
if (id == ADC_BTN_INVALID_ID)
{
if (act_id == ADC_BTN_INVALID_ACT_ID)
{
// No old act id and new act id.
return ADC_BTN_STATE_IDLE;
}
if (btn_dscp[act_id].click_cnt <= 1)
{
return ADC_BTN_STATE_IDLE;
}
// Have old act ID, new id is invalid
// Need to send release event
if (btn_dscp[act_id].click_cnt
< (info->press_judge_time / ADC_BTN_DETECT_TIME_MS))
{
ESP_LOGD (TAG, "pressed: Act ID:%d, ID:%d, Cnt:%d", act_id, id,
btn_dscp[act_id].click_cnt);
st = ADC_BTN_STATE_RELEASE;
}
else
{
ESP_LOGD (TAG, "long press release: Act ID:%d, ID:%d, Cnt:%d",
act_id, id, btn_dscp[act_id].click_cnt);
st = ADC_BTN_STATE_LONG_RELEASE;
}
btn_dscp[act_id].active_id = -1;
btn_dscp[act_id].long_click = 0;
btn_dscp[act_id].click_cnt = 0;
return st;
}
// 1.ID is valid and act ID is invalid.
if (act_id == ADC_BTN_INVALID_ACT_ID)
{
// First new act id
btn_dscp[id].active_id = id;
return ADC_BTN_STATE_IDLE;
}
// 2.ID and act ID are valid, but not equal.
if (id != act_id)
{
ESP_LOGW (TAG, "Old ID:%d, New ID:%d", act_id, id);
// Invalid the act ID
btn_dscp[act_id].active_id = -1;
btn_dscp[act_id].long_click = 0;
btn_dscp[act_id].click_cnt = 0;
// Set the new id act ID
btn_dscp[id].active_id = id;
// Maybe need to check release long pressed.
return ADC_BTN_STATE_IDLE;
}
// 3.ID and act ID are valid, and equal.
btn_dscp[act_id].click_cnt++;
if (btn_dscp[act_id].click_cnt == 3)
{
return ADC_BTN_STATE_PRESSED;
}
if (btn_dscp[act_id].long_click)
{
return ADC_BTN_STATE_IDLE;
}
if (btn_dscp[act_id].click_cnt
>= (info->press_judge_time / ADC_BTN_DETECT_TIME_MS))
{
// Send long click event.
ESP_LOGD (TAG, "long press: Act ID:%d, ID:%d, Cnt:%d", act_id, id,
btn_dscp[act_id].click_cnt);
st = ADC_BTN_STATE_LONG_PRESSED;
btn_dscp[act_id].long_click = 1;
}
return st;
}
static void
button_task (void *parameters)
{
_task_flag = true;
adc_btn_tag_t *tag = (adc_btn_tag_t *)parameters;
adc_btn_list *head = tag->head;
adc_btn_list *find = head;
xEventGroupClearBits (g_event_bit, DESTROY_BIT);
#if CONFIG_IDF_TARGET_ESP32
adc1_config_width (ADC_WIDTH_BIT_12);
#elif CONFIG_IDF_TARGET_ESP32S2
adc1_config_width (ADC_WIDTH_BIT_13);
#endif
while (find)
{
adc_arr_t *info = &(find->adc_info);
reset_btn (find->btn_dscp, info->total_steps);
adc1_config_channel_atten (info->adc_ch, ADC_ATTEN_11db);
find = find->next;
}
find = head;
#if defined ENABLE_ADC_VOLUME
adc1_config_channel_atten (DIAL_adc_ch, ADC_ATTEN_11db);
short adc_vol_prev = ADC_BTN_INVALID_ID;
short adc_vol_cur = ADC_BTN_INVALID_ID;
short internal_time_ms = DIAL_VOL_INTERVAL_TIME_MS
/ ADC_SAMPLE_INTERVAL_TIME_MS; /// 10 * 10 = 100ms
static bool empty_flag;
static bool full_flag;
bool is_first_time = true;
#endif // ENABLE_ADC_VOLUME
static adc_btn_state_t cur_state = ADC_BTN_STATE_ADC;
adc_btn_state_t btn_st = ADC_BTN_STATE_IDLE;
int cur_act_id = ADC_BTN_INVALID_ACT_ID;
while (_task_flag)
{
#if defined ENABLE_ADC_VOLUME
if (internal_time_ms == 0)
{
adc_vol_cur = get_adc_voltage (DIAL_adc_ch);
internal_time_ms
= DIAL_VOL_INTERVAL_TIME_MS / ADC_SAMPLE_INTERVAL_TIME_MS;
if (adc_vol_prev > 0)
{
short n = abs (adc_vol_cur - adc_vol_prev);
if (is_first_time)
{
is_first_time = false;
}
if (adc_vol_cur < 200)
{
if (empty_flag == false)
{
ESP_LOGI (TAG, "ABS_LOW:%d, %d->0", n, adc_vol_cur / 25);
empty_flag = true;
}
}
else if (adc_vol_cur > 2500)
{
if (full_flag == false)
{
ESP_LOGI (TAG, "ABS_HIGH:%d, %d->100", n,
adc_vol_cur / 25);
full_flag = true;
}
}
else if (n > 80)
{
empty_flag = false;
full_flag = false;
}
}
adc_vol_prev = adc_vol_cur;
}
internal_time_ms--;
#else
find = head;
while (find)
{
adc_arr_t *info = &(find->adc_info);
int act_id = ADC_BTN_INVALID_ACT_ID;
btn_decription *btn_dscp = find->btn_dscp;
switch (cur_state)
{
case ADC_BTN_STATE_ADC:
{
int adc = get_adc_voltage (info->adc_ch);
ESP_LOGD (TAG, "ADC:%d", adc);
for (int i = 0; i < info->total_steps; ++i)
{
if (btn_dscp[i].active_id > ADC_BTN_INVALID_ID)
{
act_id = i;
break;
}
}
btn_st = get_adc_btn_state (adc, act_id, find);
if (btn_st != ADC_BTN_STATE_IDLE)
{
cur_act_id = act_id;
cur_state = btn_st;
ESP_LOGD (TAG, "ADC ID:%d", act_id);
}
break;
}
case ADC_BTN_STATE_PRESSED:
{
tag->btn_callback ((void *)tag->user_data, info->adc_ch,
cur_act_id, ADC_BTN_STATE_PRESSED);
cur_state = ADC_BTN_STATE_ADC;
break;
}
case ADC_BTN_STATE_LONG_PRESSED:
{
tag->btn_callback ((void *)tag->user_data, info->adc_ch,
cur_act_id, ADC_BTN_STATE_LONG_PRESSED);
cur_state = ADC_BTN_STATE_ADC;
break;
}
case ADC_BTN_STATE_LONG_RELEASE:
{
tag->btn_callback ((void *)tag->user_data, info->adc_ch,
cur_act_id, ADC_BTN_STATE_LONG_RELEASE);
cur_state = ADC_BTN_STATE_ADC;
break;
}
case ADC_BTN_STATE_RELEASE:
{
tag->btn_callback ((void *)tag->user_data, info->adc_ch,
cur_act_id, ADC_BTN_STATE_RELEASE);
cur_state = ADC_BTN_STATE_ADC;
break;
}
default:
ESP_LOGE (TAG, "Not support state %d", cur_state);
break;
}
find = find->next;
}
#endif // ENABLE_ADC_VOLUME
vTaskDelay (ADC_SAMPLE_INTERVAL_TIME_MS / portTICK_PERIOD_MS);
}
if (g_event_bit)
{
xEventGroupSetBits (g_event_bit, DESTROY_BIT);
}
audio_free (tag);
vTaskDelete (NULL);
}
void
adc_btn_delete_task (void)
{
if (_task_flag)
{
_task_flag = false;
}
if (g_event_bit)
{
xEventGroupWaitBits (g_event_bit, DESTROY_BIT, pdTRUE, pdFALSE,
portMAX_DELAY);
vEventGroupDelete (g_event_bit);
g_event_bit = NULL;
}
}
void
adc_btn_init (void *user_data, adc_button_callback cb, adc_btn_list *head,
adc_btn_task_cfg_t *task_cfg)
{
adc_btn_tag_t *tag = audio_calloc (1, sizeof (adc_btn_tag_t));
if (NULL == tag)
{
ESP_LOGE (TAG, "Memory allocation failed! Line: %d", __LINE__);
return;
}
tag->user_data = user_data;
tag->head = head;
tag->btn_callback = cb;
g_event_bit = xEventGroupCreate ();
audio_thread_create (&tag->audio_thread, "button_task", button_task,
(void *)tag, task_cfg->task_stack, task_cfg->task_prio,
task_cfg->ext_stack, task_cfg->task_core);
}

View File

@@ -0,0 +1,105 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _ADC_BUTTON_H_
#define _ADC_BUTTON_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include "esp_err.h"
typedef enum
{
USER_KEY_ID0,
USER_KEY_ID1,
USER_KEY_ID2,
USER_KEY_ID3,
USER_KEY_ID4,
USER_KEY_ID5,
USER_KEY_ID6,
USER_KEY_MAX,
} user_key_id_num;
typedef struct
{
int adc_ch;
int *adc_level_step;
int total_steps;
int press_judge_time;
} adc_arr_t;
typedef enum
{
ADC_BTN_STATE_IDLE, // 0: idle
ADC_BTN_STATE_ADC, // 1: detect
ADC_BTN_STATE_PRESSED, // 2: pressed
ADC_BTN_STATE_RELEASE, // 3: press released
ADC_BTN_STATE_LONG_PRESSED, // 4: long pressed
ADC_BTN_STATE_LONG_RELEASE, // 5: long Press released
} adc_btn_state_t;
typedef struct
{
int active_id;
int click_cnt; // Timer tick count
int long_click;
} btn_decription;
typedef struct adc_btn
{
adc_arr_t adc_info;
btn_decription *btn_dscp;
struct adc_btn *next;
} adc_btn_list;
typedef struct
{
int task_stack;
int task_prio;
int task_core;
bool ext_stack;
} adc_btn_task_cfg_t;
typedef void (*adc_button_callback) (void *user_data, int adc, int id,
adc_btn_state_t state);
void adc_btn_init (void *user_data, adc_button_callback cb,
adc_btn_list *head, adc_btn_task_cfg_t *task_cfg);
adc_btn_list *adc_btn_create_list (adc_arr_t *adc_conf, int channels);
esp_err_t adc_btn_destroy_list (adc_btn_list *head);
void adc_btn_delete_task (void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,333 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "aw2013.h"
#include "board.h"
#include "esp_log.h"
#include "i2c_bus.h"
#include <string.h>
#define AW2013_ADDR 0x8a
#define AW2013_MAX_LED_NUM 3
#define AW2013_MAX_REPEAT_TIME 15
static const char *TAG = "AW2013";
static i2c_bus_handle_t i2c_handle;
esp_err_t
aw2013_set_repeat_time (uint8_t cnt)
{
esp_err_t ret = ESP_OK;
AUDIO_NULL_CHECK (TAG, i2c_handle, return ESP_FAIL);
uint8_t reg_val = 0;
uint8_t reg_addr = 0x0;
cnt %= AW2013_MAX_REPEAT_TIME;
for (int i = 0; i < AW2013_MAX_LED_NUM; i++)
{
reg_addr = AW2013_REG_LED0T0CNT + AW2013_MAX_LED_NUM * i;
ret |= i2c_bus_read_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
reg_val &= 0xf0;
reg_val |= cnt;
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
}
return ret;
}
esp_err_t
aw2013_set_time (aw2013_time_t time, aw2013_time_level_t level)
{
if (level > AW2013_TIME_LEVEL_8 || time > AW2013_TIME_4)
{
ESP_LOGE (TAG, "Invalid parameters, time: %d, level: %d", time, level);
return ESP_FAIL;
}
uint8_t reg_val = 0;
uint8_t reg_addr = 0x0;
esp_err_t ret = ESP_OK;
AUDIO_NULL_CHECK (TAG, i2c_handle, return ESP_FAIL);
for (int i = 0; i < AW2013_MAX_LED_NUM; i++)
{
switch (time)
{
case AW2013_TIME_0:
{
reg_addr = AW2013_REG_LED0T0CNT + AW2013_MAX_LED_NUM * i;
ret |= i2c_bus_read_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
reg_val &= 0x0f;
reg_val |= (level << 4);
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
break;
}
case AW2013_TIME_1:
{
if (level > AW2013_TIME_LEVEL_7)
{
level = AW2013_TIME_LEVEL_7;
}
reg_addr = AW2013_REG_LED0T1T2 + AW2013_MAX_LED_NUM * i;
ret |= i2c_bus_read_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
reg_val &= 0x8f;
reg_val |= (level << 4);
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
break;
}
case AW2013_TIME_2:
{
if (level > AW2013_TIME_LEVEL_5)
{
level = AW2013_TIME_LEVEL_5;
}
reg_addr = AW2013_REG_LED0T1T2 + AW2013_MAX_LED_NUM * i;
ret |= i2c_bus_read_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
reg_val &= 0xf8;
reg_val |= level;
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
break;
}
case AW2013_TIME_3:
{
if (level > 7)
{
level = 7;
}
reg_addr = AW2013_REG_LED0T3T4 + AW2013_MAX_LED_NUM * i;
ret |= i2c_bus_read_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
reg_val &= 0x8f;
reg_val |= (level << 4);
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
break;
}
case AW2013_TIME_4:
{
if (level > 7)
{
level = 7;
}
reg_addr = AW2013_REG_LED0T3T4 + AW2013_MAX_LED_NUM * i;
ret |= i2c_bus_read_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
reg_val &= 0xf8;
reg_val |= level;
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
break;
}
default:
{
return ESP_FAIL;
}
}
}
return ret;
}
esp_err_t
aw2013_enable_fade_mode (bool en)
{
esp_err_t ret = ESP_OK;
uint8_t reg_val = 0;
uint8_t reg_addr = 0x0;
AUDIO_NULL_CHECK (TAG, i2c_handle, return ESP_FAIL);
if (en)
{
for (int i = 0; i < AW2013_MAX_LED_NUM; i++)
{
reg_addr = AW2013_REG_LCFG0 + i;
ret |= i2c_bus_read_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
reg_val &= ~(0x01 << 4);
reg_val |= (0x03 << 5);
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
}
}
else
{
for (int i = 0; i < AW2013_MAX_LED_NUM; i++)
{
reg_addr = AW2013_REG_LCFG0 + i;
ret |= i2c_bus_read_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
reg_val &= ~(0x03 << 5);
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
}
}
return ret;
}
esp_err_t
aw2013_enable_auto_flash (bool en)
{
esp_err_t ret = ESP_OK;
uint8_t reg_val = 0;
uint8_t reg_addr = 0x0;
AUDIO_NULL_CHECK (TAG, i2c_handle, return ESP_FAIL);
if (en)
{
for (int i = 0; i < AW2013_MAX_LED_NUM; i++)
{
reg_addr = AW2013_REG_LCFG0 + i;
ret |= i2c_bus_read_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
reg_val |= (0x01 << 4);
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
}
}
else
{
for (int i = 0; i < AW2013_MAX_LED_NUM; i++)
{
reg_addr = AW2013_REG_LCFG0 + i;
ret |= i2c_bus_read_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
reg_val &= ~(0x01 << 4);
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
}
}
return ret;
}
esp_err_t
aw2013_set_pwm_value (uint32_t value)
{
esp_err_t ret = ESP_OK;
uint8_t reg_val = 0;
uint8_t reg_addr = 0x0;
AUDIO_NULL_CHECK (TAG, i2c_handle, return ESP_FAIL);
reg_addr = AW2013_REG_PWM0;
reg_val = (value >> 16) & 0xff;
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_val,
1);
reg_addr = AW2013_REG_PWM1;
reg_val = (value >> 8) & 0xff;
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_val,
1);
reg_addr = AW2013_REG_PWM2;
reg_val = value & 0xff;
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_val,
1);
return ret;
}
esp_err_t
aw2013_set_brightness (aw2013_brightness_t bright)
{
esp_err_t ret = ESP_OK;
uint8_t reg_val = 0;
uint8_t reg_addr = 0x0;
AUDIO_NULL_CHECK (TAG, i2c_handle, return ESP_FAIL);
if (bright > AW2013_BRIGHT_3)
{
bright = AW2013_BRIGHT_3;
}
for (int i = 0; i < AW2013_MAX_LED_NUM; i++)
{
reg_addr = AW2013_REG_LCFG0 + i;
ret |= i2c_bus_read_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
reg_val &= 0xfc;
reg_val |= bright;
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1,
&reg_val, 1);
}
return ret;
}
esp_err_t
aw2013_reset (void)
{
esp_err_t ret = ESP_OK;
uint8_t reg_val = 0;
uint8_t reg_addr = 0x0;
AUDIO_NULL_CHECK (TAG, i2c_handle, return ESP_FAIL);
reg_addr = AW2013_REG_RESET;
reg_addr = AW2013_RESET_VALUE;
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_val,
1);
reg_addr = AW2013_REG_GCR;
reg_val = 0x01;
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_val,
1);
reg_addr = AW2013_REG_LCTR;
reg_val = 0x07;
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_val,
1);
ret |= aw2013_set_brightness (1);
return ret;
}
esp_err_t
aw2013_init (void)
{
esp_err_t ret = ESP_OK;
i2c_config_t config
= { .mode = I2C_MODE_MASTER, .master.clk_speed = 100000 };
ret |= get_i2c_pins (AW2013_I2C_PORT, &config);
i2c_handle = i2c_bus_create (AW2013_I2C_PORT, &config);
ret |= aw2013_reset ();
if (ret != ESP_OK)
{
ESP_LOGE (TAG, "Fail to init aw2013");
}
return ret;
}
esp_err_t
aw2013_deinit (void)
{
esp_err_t ret = ESP_OK;
uint8_t reg_addr = AW2013_REG_RESET;
uint8_t reg_val = AW2013_RESET_VALUE;
AUDIO_NULL_CHECK (TAG, i2c_handle, return ESP_FAIL);
ret |= i2c_bus_write_bytes (i2c_handle, AW2013_ADDR, &reg_addr, 1, &reg_val,
1);
ret |= i2c_bus_delete (i2c_handle);
return ret;
}

View File

@@ -0,0 +1,205 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _AW2013_H_
#define _AW2013_H_
#include "esp_err.h"
#include "esp_log.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define AW2013_I2C_PORT I2C_NUM_0
#define AW2013_RESET_VALUE 0x55
#define AW2013_REG_RESET 0x00
#define AW2013_REG_GCR 0x01
#define AW2013_REG_LCTR 0x30
#define AW2013_REG_LCFG0 0x31
#define AW2013_REG_LCFG1 0x32
#define AW2013_REG_LCFG2 0x33
#define AW2013_REG_PWM0 0x34
#define AW2013_REG_PWM1 0x35
#define AW2013_REG_PWM2 0x36
#define AW2013_REG_LED0T1T2 0x37
#define AW2013_REG_LED1T1T2 0x3A
#define AW2013_REG_LED2T1T2 0x3D
#define AW2013_REG_LED0T3T4 0x38
#define AW2013_REG_LED1T3T4 0x3B
#define AW2013_REG_LED2T3T4 0x3E
#define AW2013_REG_LED0T0CNT 0x39
#define AW2013_REG_LED1T0CNT 0x3C
#define AW2013_REG_LED2T0CNT 0x3F
typedef enum
{
AW2013_BRIGHT_0, // Turn off the lights, the electric current is 0mA
AW2013_BRIGHT_1, // 5mA
AW2013_BRIGHT_2, // 10mA
AW2013_BRIGHT_3, // 15mA
} aw2013_brightness_t;
// Time periods of a auto flash cycle
/*-------------------------------------------*\
| __________ |
| /| |\ |
| / | | \ |
| / | | \ |
| ________/ | | \__________ |
| | | | | | | |
| |<--t0->|t1 |<--t2-->|t3 |<--t4-->| |
\*-------------------------------------------*/
typedef enum
{
AW2013_TIME_0, // T0
AW2013_TIME_1, // T1
AW2013_TIME_2, // T2
AW2013_TIME_3, // T3
AW2013_TIME_4 // T4
} aw2013_time_t;
typedef enum
{ // T1-T4 T0
AW2013_TIME_LEVEL_0, // 0.13s (T0 0s)
AW2013_TIME_LEVEL_1, // 0.26s (T0 0.13s)
AW2013_TIME_LEVEL_2, // 0.52s (T0 0.26s)
AW2013_TIME_LEVEL_3, // 1.04s (T0 0.52s)
AW2013_TIME_LEVEL_4, // 2.08s (T0 1.04s)
AW2013_TIME_LEVEL_5, // 4.16s (T0 2.08s)
AW2013_TIME_LEVEL_6, // 8.32s (T0 4.16s)
AW2013_TIME_LEVEL_7, // 16.64s (T0 8.32s)
AW2013_TIME_LEVEL_8, // (T0 16.64s)
} aw2013_time_level_t;
/**
* @brief Initialize the aw2013 chip
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t aw2013_init (void);
/**
* @brief Deinitialize the aw2013 chip
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t aw2013_deinit (void);
/**
* @brief Reset the aw2013 chip
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t aw2013_reset (void);
/**
* @brief Set rgb value for the aw2013
*
* @param value The value to be set
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t aw2013_set_pwm_value (uint32_t value);
/**
* @brief Set repeat times for auto flash
*
* @param cnt Number of repetitions
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t aw2013_set_repeat_time (uint8_t cnt);
/**
* @brief Set the time for each time period for auto flash
*
* @param time The time period
* @param level The time to be set
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t aw2013_set_time (aw2013_time_t time, aw2013_time_level_t level);
/**
* @brief Set the brightness
*
* @param bright The brightness to be set
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t aw2013_set_brightness (aw2013_brightness_t bright);
/**
* @brief Enable the auto flash fuction
*
* @param en Whether to enable
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t aw2013_enable_auto_flash (bool en);
/**
* @brief Enable the fade fuction
*
* @param en Whether to enable
*
* @return
* - ESP_OK Success
* - ESP_FAIL error
*/
esp_err_t aw2013_enable_fade_mode (bool en);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,276 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "audio_mem.h"
#include "sdkconfig.h"
#ifdef CONFIG_BLUEDROID_ENABLED
#include "esp_log.h"
#include "esp_system.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mbedtls/aes.h"
#include "mbedtls/dhm.h"
#include "mbedtls/md5.h"
#if __has_include("esp_idf_version.h")
#include "esp_idf_version.h"
#else
#define ESP_IDF_VERSION_VAL(major, minor, patch) 1
#endif
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
#ifdef CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/crc.h"
#else
#include "esp32s2beta/rom/crc.h"
#endif // CONFIG_IDF_TARGET_ESP32
#else
#include "rom/crc.h"
#endif //(ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
#define BLUFI_SECURITY_TAG "BLUFI_SECURITY"
/*
The SEC_TYPE_xxx is for self-defined packet data type in the procedure of
"BLUFI negotiate key" If using other negotiation procedure to exchange (or
generate) a key, the user should redefine the type by yourself.
*/
#define SEC_TYPE_DH_PARAM_LEN 0x00
#define SEC_TYPE_DH_PARAM_DATA 0x01
#define SEC_TYPE_DH_P 0x02
#define SEC_TYPE_DH_G 0x03
#define SEC_TYPE_DH_PUBLIC 0x04
struct blufi_security
{
#define DH_SELF_PUB_KEY_LEN 128
#define DH_SELF_PUB_KEY_BIT_LEN (DH_SELF_PUB_KEY_LEN * 8)
uint8_t self_public_key[DH_SELF_PUB_KEY_LEN];
#define SHARE_KEY_LEN 128
#define SHARE_KEY_BIT_LEN (SHARE_KEY_LEN * 8)
uint8_t share_key[SHARE_KEY_LEN];
size_t share_len;
#define PSK_LEN 16
uint8_t psk[PSK_LEN];
uint8_t *dh_param;
int dh_param_len;
uint8_t iv[16];
mbedtls_dhm_context dhm;
mbedtls_aes_context aes;
};
static struct blufi_security *blufi_sec;
static int
myrand (void *rng_state, unsigned char *output, size_t len)
{
size_t i;
for (i = 0; i < len; ++i)
{
output[i] = esp_random ();
}
return ESP_OK;
}
void
blufi_dh_negotiate_data_handler (uint8_t *data, int len, uint8_t **output_data,
int *output_len, bool *need_free)
{
int ret;
uint8_t type = data[0];
if (blufi_sec == NULL)
{
ESP_LOGE (BLUFI_SECURITY_TAG, "BLUFI Security is not initialized");
return;
}
switch (type)
{
case SEC_TYPE_DH_PARAM_LEN:
blufi_sec->dh_param_len = ((data[1] << 8) | data[2]);
if (blufi_sec->dh_param)
{
audio_free (blufi_sec->dh_param);
blufi_sec->dh_param = NULL;
}
blufi_sec->dh_param
= (uint8_t *)audio_calloc (1, blufi_sec->dh_param_len);
if (blufi_sec->dh_param == NULL)
{
ESP_LOGE (BLUFI_SECURITY_TAG, "%s, Malloc failed", __func__);
return;
}
break;
case SEC_TYPE_DH_PARAM_DATA:
{
if (blufi_sec->dh_param == NULL)
{
ESP_LOGE (BLUFI_SECURITY_TAG, "%s, Blufi_sec->dh_param == NULL",
__func__);
return;
}
uint8_t *param = blufi_sec->dh_param;
memcpy (blufi_sec->dh_param, &data[1], blufi_sec->dh_param_len);
ret = mbedtls_dhm_read_params (&blufi_sec->dhm, &param,
&param[blufi_sec->dh_param_len]);
if (ret)
{
ESP_LOGE (BLUFI_SECURITY_TAG, "%s Read param failed %d", __func__,
ret);
return;
}
audio_free (blufi_sec->dh_param);
blufi_sec->dh_param = NULL;
ret = mbedtls_dhm_make_public (
&blufi_sec->dhm, (int)mbedtls_mpi_size (&blufi_sec->dhm.P),
blufi_sec->self_public_key, blufi_sec->dhm.len, myrand, NULL);
if (ret)
{
ESP_LOGE (BLUFI_SECURITY_TAG, "%s Make public failed %d", __func__,
ret);
return;
}
mbedtls_dhm_calc_secret (&blufi_sec->dhm, blufi_sec->share_key,
SHARE_KEY_BIT_LEN, &blufi_sec->share_len,
NULL, NULL);
mbedtls_md5 (blufi_sec->share_key, blufi_sec->share_len,
blufi_sec->psk);
mbedtls_aes_setkey_enc (&blufi_sec->aes, blufi_sec->psk, 128);
/* Alloc output data */
*output_data = &blufi_sec->self_public_key[0];
*output_len = blufi_sec->dhm.len;
*need_free = false;
}
break;
case SEC_TYPE_DH_P:
break;
case SEC_TYPE_DH_G:
break;
case SEC_TYPE_DH_PUBLIC:
break;
}
}
int
blufi_aes_encrypt (uint8_t iv8, uint8_t *crypt_data, int crypt_len)
{
int ret;
size_t iv_offset = 0;
uint8_t iv0[16];
memcpy (iv0, blufi_sec->iv, sizeof (blufi_sec->iv));
/* Set iv8 as the iv0[0] */
iv0[0] = iv8;
ret = mbedtls_aes_crypt_cfb128 (&blufi_sec->aes, MBEDTLS_AES_ENCRYPT,
crypt_len, &iv_offset, iv0, crypt_data,
crypt_data);
if (ret)
{
return ESP_FAIL;
}
return crypt_len;
}
int
blufi_aes_decrypt (uint8_t iv8, uint8_t *crypt_data, int crypt_len)
{
int ret;
size_t iv_offset = 0;
uint8_t iv0[16];
memcpy (iv0, blufi_sec->iv, sizeof (blufi_sec->iv));
/* Set iv8 as the iv0[0] */
iv0[0] = iv8;
ret = mbedtls_aes_crypt_cfb128 (&blufi_sec->aes, MBEDTLS_AES_DECRYPT,
crypt_len, &iv_offset, iv0, crypt_data,
crypt_data);
if (ret)
{
return ESP_FAIL;
}
return crypt_len;
}
uint16_t
blufi_crc_checksum (uint8_t iv8, uint8_t *data, int len)
{
/* This iv8 ignore, not used */
return crc16_be (0, data, len);
}
esp_err_t
blufi_security_init (void)
{
blufi_sec = (struct blufi_security *)audio_calloc (
1, sizeof (struct blufi_security));
if (blufi_sec == NULL)
{
return ESP_FAIL;
}
mbedtls_dhm_init (&blufi_sec->dhm);
mbedtls_aes_init (&blufi_sec->aes);
memset (blufi_sec->iv, 0x0, 16);
return ESP_OK;
}
esp_err_t
blufi_security_deinit (void)
{
if (blufi_sec == NULL)
{
return ESP_FAIL;
}
if (blufi_sec->dh_param)
{
audio_free (blufi_sec->dh_param);
blufi_sec->dh_param = NULL;
}
mbedtls_dhm_free (&blufi_sec->dhm);
mbedtls_aes_free (&blufi_sec->aes);
memset (blufi_sec, 0x0, sizeof (struct blufi_security));
audio_free (blufi_sec);
blufi_sec = NULL;
return ESP_OK;
}
#endif

View File

@@ -0,0 +1,111 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _BLUFI_SECURITY_H_
#define _BLUFI_SECURITY_H_
#include "esp_log.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief BLUFI negotiate data handler
*
* @param[in] data data from phone
* @param[in] len length of data from phone
* @param[in] output_data data to be sent to phone
* @param[in] output_len length of data to be sent to phone
*/
void blufi_dh_negotiate_data_handler (uint8_t *data, int len,
uint8_t **output_data, int *output_len,
bool *need_free);
/**
* @brief BLUFI encrypt the data after negotiating a share key
*
* @param[in] iv8 initial vector(8bit), normally, blufi core will
* input packet sequence number
* @param[in] crypt_data plain text and encrypted data, the encrypt
* function must support autochthonous encrypt
* @param[in] crypt_len length of plain text
*
* @return Nonnegative number is encrypted length, if error, return negative
* number;
*/
int blufi_aes_encrypt (uint8_t iv8, uint8_t *crypt_data, int crypt_len);
/**
* @brief BLUFI decrypt the data after negotiating a share key
*
* @param[in] iv8 initial vector(8bit), normally, blufi core will
* input packet sequence number
* @param[in] crypt_data encrypted data and plain text, the encrypt
* function must support autochthonous decrypt
* @param[in] crypt_len length of encrypted text
*
* @return Nonnegative number is decrypted length, if error, return negative
* number;
*/
int blufi_aes_decrypt (uint8_t iv8, uint8_t *crypt_data, int crypt_len);
/**
* @brief BLUFI CRC check sum function
*
* @param[in] iv8 initial vector(8bit), normally, blufi core will input
* packet sequence number
* @param[in] data data need to checksum
* @param[in] len length of data
*
* @return None
*/
uint16_t blufi_crc_checksum (uint8_t iv8, uint8_t *data, int len);
/**
* @brief Initialize and allocate the resource for BLUFI security
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t blufi_security_init (void);
/**
* @brief Uninitialize and free the resource for BLUFI security
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t blufi_security_deinit (void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,288 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "audio_mem.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef CONFIG_BLUEDROID_ENABLED
#include "audio_error.h"
#include "blufi_security.h"
#include "esp_blufi_api.h"
#include "esp_bt.h"
#include "esp_bt_defs.h"
#include "esp_bt_device.h"
#include "esp_bt_main.h"
#include "esp_gap_ble_api.h"
#include "esp_gap_bt_api.h"
#include "esp_log.h"
#include "esp_smartconfig.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "periph_wifi.h"
#include "wifibleconfig.h"
#define WIFI_BLE_TAG "WIFI_BLE_CONFIG"
#define BLUFI_DEVICE_NAME "BLUFI_DEVICE"
#define WIFI_LIST_NUM (10)
static uint8_t wifi_ble_service_uuid128[32] = {
/* LSB
<-------------------------------------------------------------------------------->
MSB */
// first uuid, 16bit, [12],[13] is the value
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
0x00, 0x10, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
};
typedef struct wifi_ble_config
{
uint8_t ble_server_if;
uint16_t ble_conn_id;
wifi_config_t sta_config;
esp_periph_handle_t periph;
} wifi_ble_config_t;
static wifi_ble_config_t *g_wifi_ble_config = NULL;
static void wifi_ble_event_callback (esp_blufi_cb_event_t event,
esp_blufi_cb_param_t *param);
static esp_ble_adv_data_t wifi_ble_adv_data = {
.set_scan_rsp = false,
.include_name = true,
.include_txpower = true,
.min_interval = 0x100,
.max_interval = 0x100,
.appearance = 0x00,
.manufacturer_len = 0,
.p_manufacturer_data = NULL,
.service_data_len = 0,
.p_service_data = NULL,
.service_uuid_len = 16,
.p_service_uuid = wifi_ble_service_uuid128,
.flag = 0x6,
};
static esp_ble_adv_params_t wifi_ble_adv_params = {
.adv_int_min = 0x100,
.adv_int_max = 0x100,
.adv_type = ADV_TYPE_IND,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
static esp_blufi_callbacks_t wifi_ble_callbacks = {
.event_cb = wifi_ble_event_callback,
.negotiate_data_handler = blufi_dh_negotiate_data_handler,
.encrypt_func = blufi_aes_encrypt,
.decrypt_func = blufi_aes_decrypt,
.checksum_func = blufi_crc_checksum,
};
static void
wifi_ble_gap_event_handler (esp_gap_ble_cb_event_t event,
esp_ble_gap_cb_param_t *param)
{
switch (event)
{
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
esp_ble_gap_start_advertising (&wifi_ble_adv_params);
break;
default:
break;
}
}
esp_err_t
ble_config_stop (void)
{
if (g_wifi_ble_config != NULL)
{
audio_free (g_wifi_ble_config);
g_wifi_ble_config = NULL;
}
blufi_security_deinit ();
esp_blufi_profile_deinit ();
esp_bluedroid_disable ();
esp_bluedroid_deinit ();
return ESP_OK;
}
static void
wifi_ble_event_callback (esp_blufi_cb_event_t event,
esp_blufi_cb_param_t *param)
{
/* actually, should post to blufi_task handle the procedure,
* now, as a audio_ble, we do it more simply */
esp_err_t ret;
switch (event)
{
case ESP_BLUFI_EVENT_INIT_FINISH:
ESP_LOGI (WIFI_BLE_TAG, "BLUFI init finish");
esp_ble_gap_set_device_name (BLUFI_DEVICE_NAME);
esp_ble_gap_config_adv_data (&wifi_ble_adv_data);
break;
case ESP_BLUFI_EVENT_DEINIT_FINISH:
ESP_LOGI (WIFI_BLE_TAG, "BLUFI deinit finish");
break;
case ESP_BLUFI_EVENT_BLE_CONNECT:
ESP_LOGI (WIFI_BLE_TAG, "BLUFI ble connect");
esp_smartconfig_stop ();
g_wifi_ble_config->ble_server_if = param->connect.server_if;
g_wifi_ble_config->ble_conn_id = param->connect.conn_id;
break;
case ESP_BLUFI_EVENT_BLE_DISCONNECT:
ESP_LOGI (WIFI_BLE_TAG, "BLUFI ble disconnect");
break;
case ESP_BLUFI_EVENT_SET_WIFI_OPMODE:
ESP_LOGI (WIFI_BLE_TAG, "BLUFI Set WIFI opmode %d",
param->wifi_mode.op_mode);
ESP_ERROR_CHECK (esp_wifi_set_mode (param->wifi_mode.op_mode));
break;
case ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP:
ESP_LOGI (WIFI_BLE_TAG, "BLUFI request wifi connect to AP");
esp_wifi_disconnect ();
if (ESP_OK != esp_wifi_connect ())
{
esp_periph_send_event (g_wifi_ble_config->periph,
PERIPH_WIFI_CONFIG_ERROR, NULL, 0);
}
else
{
esp_periph_send_event (g_wifi_ble_config->periph,
PERIPH_WIFI_CONFIG_DONE, NULL, 0);
ble_config_stop ();
}
break;
case ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP:
ESP_LOGI (WIFI_BLE_TAG, "BLUFI request wifi disconnect from AP");
esp_wifi_disconnect ();
break;
case ESP_BLUFI_EVENT_GET_WIFI_STATUS:
{
wifi_mode_t mode;
esp_blufi_extra_info_t info;
esp_wifi_get_mode (&mode);
memset (&info, 0, sizeof (esp_blufi_extra_info_t));
info.sta_bssid_set = true;
info.sta_ssid = g_wifi_ble_config->sta_config.sta.ssid;
esp_blufi_send_wifi_conn_report (mode, ESP_BLUFI_STA_CONN_SUCCESS, 0,
&info);
ESP_LOGI (WIFI_BLE_TAG, "BLUFI get wifi status from AP");
break;
}
case ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE:
ESP_LOGI (WIFI_BLE_TAG, "BLUFI close a gatt connection");
esp_blufi_close (g_wifi_ble_config->ble_server_if,
g_wifi_ble_config->ble_conn_id);
break;
case ESP_BLUFI_EVENT_DEAUTHENTICATE_STA:
/* TODO */
break;
case ESP_BLUFI_EVENT_RECV_STA_BSSID:
memcpy (g_wifi_ble_config->sta_config.sta.bssid, param->sta_bssid.bssid,
6);
g_wifi_ble_config->sta_config.sta.bssid_set = 1;
esp_wifi_set_config (WIFI_IF_STA, &g_wifi_ble_config->sta_config);
ESP_LOGI (WIFI_BLE_TAG, "Recv STA BSSID %s",
g_wifi_ble_config->sta_config.sta.bssid);
break;
case ESP_BLUFI_EVENT_RECV_STA_SSID:
strncpy ((char *)g_wifi_ble_config->sta_config.sta.ssid,
(char *)param->sta_ssid.ssid, param->sta_ssid.ssid_len);
g_wifi_ble_config->sta_config.sta.ssid[param->sta_ssid.ssid_len] = '\0';
ret = esp_wifi_set_config (WIFI_IF_STA, &g_wifi_ble_config->sta_config);
ESP_LOGI (WIFI_BLE_TAG, "Recv STA SSID ret %d %s", ret,
g_wifi_ble_config->sta_config.sta.ssid);
break;
case ESP_BLUFI_EVENT_RECV_STA_PASSWD:
strncpy ((char *)g_wifi_ble_config->sta_config.sta.password,
(char *)param->sta_passwd.passwd, param->sta_passwd.passwd_len);
g_wifi_ble_config->sta_config.sta.password[param->sta_passwd.passwd_len]
= '\0';
esp_wifi_set_config (WIFI_IF_STA, &g_wifi_ble_config->sta_config);
ESP_LOGI (WIFI_BLE_TAG, "Recv STA PASSWORD %s",
g_wifi_ble_config->sta_config.sta.password);
break;
default:
ESP_LOGE (WIFI_BLE_TAG, "Event %d is not supported", event);
break;
}
}
esp_err_t
ble_config_start (esp_periph_handle_t periph)
{
ESP_LOGI (WIFI_BLE_TAG, "ble_config_start");
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT ();
if (esp_bt_controller_get_status () == ESP_BT_CONTROLLER_STATUS_IDLE)
{
if (esp_bt_controller_init (&bt_cfg) != ESP_OK)
{
ESP_LOGE (WIFI_BLE_TAG, "%s initialize controller failed", __func__);
return ESP_FAIL;
}
if (esp_bt_controller_enable (ESP_BT_MODE_BLE) != ESP_OK)
{
ESP_LOGE (WIFI_BLE_TAG, "%s enable controller failed", __func__);
return ESP_FAIL;
}
}
if (esp_bluedroid_get_status () == ESP_BLUEDROID_STATUS_UNINITIALIZED)
{
if (esp_bluedroid_init () != ESP_OK)
{
ESP_LOGE (WIFI_BLE_TAG, "%s esp_bluedroid_init failed", __func__);
return ESP_FAIL;
}
if (esp_bluedroid_enable () != ESP_OK)
{
ESP_LOGE (WIFI_BLE_TAG, "%s esp_bluedroid_enable failed", __func__);
return ESP_FAIL;
}
}
ESP_LOGI (WIFI_BLE_TAG, "BD ADDR: " ESP_BD_ADDR_STR "",
ESP_BD_ADDR_HEX (esp_bt_dev_get_address ()));
ESP_LOGI (WIFI_BLE_TAG, "BLUFI VERSION %04x", esp_blufi_get_version ());
g_wifi_ble_config = audio_calloc (1, sizeof (wifi_ble_config_t));
AUDIO_MEM_CHECK (WIFI_BLE_TAG, g_wifi_ble_config, return ESP_FAIL);
g_wifi_ble_config->periph = periph;
blufi_security_init ();
esp_ble_gap_register_callback (wifi_ble_gap_event_handler);
esp_blufi_register_callbacks (&wifi_ble_callbacks);
esp_blufi_profile_init ();
return ESP_OK;
}
#endif

View File

@@ -0,0 +1,62 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _WIFI_BLECONFIG_H_
#define _WIFI_BLECONFIG_H_
#include "esp_err.h"
#include "esp_peripherals.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Start Wi-Fi BLE config
*
* @param[in] periph The peripheral handle
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t ble_config_start (esp_periph_handle_t periph);
/**
* @brief Stop Wi-Fi BLE config.
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t ble_config_stop (void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,224 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include "audio_mem.h"
#include "button.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "sys/queue.h"
#ifdef periph_tick_get
#define tick_get periph_tick_get
#else
static long long
tick_get ()
{
struct timeval te;
gettimeofday (&te, NULL);
long long milliseconds = te.tv_sec * 1000LL + te.tv_usec / 1000;
return milliseconds;
}
#endif
static const char *TAG = "BUTTON";
typedef struct esp_button_item
{
int gpio_num;
long long last_press_tick;
bool long_pressed;
STAILQ_ENTRY (esp_button_item) entry;
} esp_button_item_t;
struct esp_button
{
int long_press_time_ms;
uint64_t gpio_mask;
STAILQ_HEAD (esp_button_list, esp_button_item) btn_list;
};
static button_status_t
button_get_state (esp_button_handle_t button, esp_button_item_t *btn_item)
{
int level = gpio_get_level (btn_item->gpio_num);
int active_level = 0;
int deactive_level = 1;
if (btn_item->last_press_tick == 0 && level == active_level)
{
btn_item->last_press_tick = tick_get ();
btn_item->long_pressed = false;
return BTN_PRESSED;
}
if (level == deactive_level && btn_item->last_press_tick
&& tick_get () - btn_item->last_press_tick > button->long_press_time_ms)
{
btn_item->last_press_tick = 0;
btn_item->long_pressed = false;
return BTN_LONG_RELEASE;
}
if (level == deactive_level && btn_item->last_press_tick)
{
btn_item->last_press_tick = 0;
btn_item->long_pressed = false;
return BTN_RELEASE;
}
if (btn_item->long_pressed == false && level == active_level
&& tick_get () - btn_item->last_press_tick > button->long_press_time_ms)
{
btn_item->long_pressed = true;
return BTN_LONG_PRESS;
}
return BTN_UNCHANGE;
}
esp_button_handle_t
button_init (button_config_t *config)
{
esp_button_handle_t btn = audio_calloc (1, sizeof (struct esp_button));
AUDIO_MEM_CHECK (TAG, btn, return NULL);
if (config->gpio_mask <= 0)
{
ESP_LOGE (TAG, "required at least 1 gpio");
return NULL;
}
btn->gpio_mask = config->gpio_mask;
btn->long_press_time_ms = config->long_press_time_ms;
if (btn->long_press_time_ms == 0)
{
btn->long_press_time_ms = DEFAULT_LONG_PRESS_TIME_MS;
}
gpio_config_t gpiocfg = {
.pin_bit_mask = btn->gpio_mask,
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_ANYEDGE,
};
gpio_config (&gpiocfg);
uint64_t gpio_mask = btn->gpio_mask;
int gpio_num = 0;
STAILQ_INIT (&btn->btn_list);
while (gpio_mask)
{
if (gpio_mask & 0x01)
{
ESP_LOGD (TAG, "Mask = %llx, current_mask = %llx, idx=%d",
btn->gpio_mask, gpio_mask, gpio_num);
esp_button_item_t *new_btn
= audio_calloc (1, sizeof (esp_button_item_t));
AUDIO_MEM_CHECK (TAG, new_btn, {
button_destroy (btn);
return NULL;
});
new_btn->gpio_num = gpio_num;
if (config->button_intr_handler)
{
gpio_set_intr_type (gpio_num, GPIO_INTR_ANYEDGE);
gpio_isr_handler_add (gpio_num, config->button_intr_handler,
config->intr_context);
gpio_intr_enable (gpio_num);
}
STAILQ_INSERT_TAIL (&btn->btn_list, new_btn, entry);
}
gpio_mask >>= 1;
gpio_num++;
}
return btn;
}
bool
button_read (esp_button_handle_t button, button_result_t *result)
{
esp_button_item_t *btn_item;
button_status_t btn_status;
bool changed = false;
memset (result, 0, sizeof (button_result_t));
uint64_t tmp;
STAILQ_FOREACH (btn_item, &button->btn_list, entry)
{
btn_status = button_get_state (button, btn_item);
switch (btn_status)
{
case BTN_UNCHANGE:
break;
case BTN_PRESSED:
changed = true;
tmp = 0x01;
tmp <<= btn_item->gpio_num;
result->press_mask |= tmp;
break;
case BTN_RELEASE:
changed = true;
tmp = 0x01;
tmp <<= btn_item->gpio_num;
result->release_mask |= tmp;
break;
case BTN_LONG_RELEASE:
changed = true;
tmp = 0x01;
tmp <<= btn_item->gpio_num;
result->long_release_mask |= tmp;
break;
case BTN_LONG_PRESS:
changed = true;
tmp = 0x01;
tmp <<= btn_item->gpio_num;
result->long_press_mask |= tmp;
break;
}
}
return changed;
}
esp_err_t
button_destroy (esp_button_handle_t button)
{
esp_button_item_t *btn_item, *tmp;
STAILQ_FOREACH_SAFE (btn_item, &button->btn_list, entry, tmp)
{
gpio_intr_disable (btn_item->gpio_num);
gpio_isr_handler_remove (btn_item->gpio_num);
STAILQ_REMOVE (&button->btn_list, btn_item, esp_button_item, entry);
audio_free (btn_item);
}
audio_free (button);
return ESP_OK;
}

View File

@@ -0,0 +1,109 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _ESP_BUTTON_
#define _ESP_BUTTON_
#include "audio_error.h"
#include "driver/gpio.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief { item_description }
*/
typedef enum
{
BTN_UNCHANGE = 0,
BTN_PRESSED,
BTN_RELEASE,
BTN_LONG_PRESS,
BTN_LONG_RELEASE,
} button_status_t;
/**
* @brief { item_description }
*/
typedef struct
{
uint64_t press_mask;
uint64_t release_mask;
uint64_t long_press_mask;
uint64_t long_release_mask;
} button_result_t;
typedef struct esp_button *esp_button_handle_t;
typedef void (*gpio_intr_handler) (void *);
/**
* @brief { item_description }
*/
typedef struct
{
int long_press_time_ms;
uint64_t gpio_mask;
gpio_intr_handler button_intr_handler;
void *intr_context;
} button_config_t;
#define DEFAULT_LONG_PRESS_TIME_MS (2 * 1000)
/**
* @brief { function_description }
*
* @param config The configuration
*
* @return { description_of_the_return_value }
*/
esp_button_handle_t button_init (button_config_t *config);
/**
* @brief { function_description }
*
* @param[in] button The button
* @param result The result
*
* @return { description_of_the_return_value }
*/
bool button_read (esp_button_handle_t button, button_result_t *result);
/**
* @brief { function_description }
*
* @param[in] button The button
*
* @return { description_of_the_return_value }
*/
esp_err_t button_destroy (esp_button_handle_t button);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,61 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "driver/gpio.h"
#include "esp_log.h"
static const char *TAG = "GPIO_ISR";
esp_err_t
gpio_isr_init (int gpio_num, gpio_int_type_t type,
gpio_isr_t gpio_isr_handle_func, void *isr_param)
{
esp_err_t ret = ESP_OK;
if (gpio_num < 0 || NULL == gpio_isr_handle_func)
{
ESP_LOGE (TAG, "Please check the parameters!");
return ESP_OK;
}
ret |= gpio_set_direction (gpio_num, GPIO_MODE_INPUT);
ret |= gpio_set_intr_type (gpio_num, type);
ret |= gpio_isr_handler_add (gpio_num, gpio_isr_handle_func, isr_param);
ret |= gpio_intr_enable (gpio_num);
return ret;
}
esp_err_t
gpio_isr_deinit (int gpio_num)
{
esp_err_t ret = ESP_OK;
if (gpio_num < 0)
{
ESP_LOGE (TAG, "The gpio number should greater than or equal to 0");
return ESP_FAIL;
}
ret |= gpio_isr_handler_remove (gpio_num);
ret |= gpio_intr_disable (gpio_num);
return ret;
}

View File

@@ -0,0 +1,66 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _GPIO_ISR_H_
#define _GPIO_ISR_H_
#include "driver/gpio.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Initialize the gpio's interrupt service routines.
*
* @param gpio_num The number of gpio to be initialized
* @param type The type of interrupts
* @param gpio_isr_handle_func Interrupt handler
* @param isr_param The parameters of interrupt handler
*
* @return
*/
esp_err_t gpio_isr_init (int gpio_num, gpio_int_type_t type,
gpio_isr_t gpio_isr_handle_func, void *isr_param);
/**
* @brief Deinitialize the gpio isr
*
* @param gpio_num The number of gpio to be deinitialized
*
* @return
* - ESP_OK on success
* - ESP_FAIL on failed
*/
esp_err_t gpio_isr_deinit (int gpio_num);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,222 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_vfs_fat.h"
#include "driver/gpio.h"
#include "driver/sdmmc_defs.h"
#include "driver/sdmmc_host.h"
#include "board.h"
#include "sdcard.h"
static const char *TAG = "SDCARD";
int g_gpio = -1;
#define PIN_NUM_MISO 2
#define PIN_NUM_MOSI 15
#define PIN_NUM_CLK 14
#define PIN_NUM_CS 13
static void
sdmmc_card_print_info (const sdmmc_card_t *card)
{
ESP_LOGD (TAG, "Name: %s\n", card->cid.name);
ESP_LOGD (TAG, "Type: %s\n",
(card->ocr & SD_OCR_SDHC_CAP) ? "SDHC/SDXC" : "SDSC");
ESP_LOGD (TAG, "Speed: %s\n",
(card->csd.tr_speed > 25000000) ? "high speed" : "default speed");
ESP_LOGD (TAG, "Size: %lluMB\n",
((uint64_t)card->csd.capacity) * card->csd.sector_size
/ (1024 * 1024));
ESP_LOGD (TAG, "CSD: ver=%d, sector_size=%d, capacity=%d read_bl_len=%d\n",
card->csd.csd_ver, card->csd.sector_size, card->csd.capacity,
card->csd.read_block_len);
ESP_LOGD (TAG, "SCR: sd_spec=%d, bus_width=%d\n", card->scr.sd_spec,
card->scr.bus_width);
}
esp_err_t
sdcard_mount (const char *base_path, periph_sdcard_mode_t mode)
{
if (mode >= SD_MODE_MAX)
{
ESP_LOGE (TAG,
"PLease select the correct sd mode: 1-line SD mode, 4-line SD "
"mode or SPI mode!, current mode is %d",
mode);
return ESP_FAIL;
}
sdmmc_card_t *card = NULL;
esp_err_t ret;
esp_vfs_fat_sdmmc_mount_config_t mount_config
= { .format_if_mount_failed = false,
.max_files = get_sdcard_open_file_num_max () };
if (mode != SD_MODE_SPI)
{
ESP_LOGI (TAG, "Using 1-line SD mode, 4-line SD mode, base path=%s",
base_path);
sdmmc_host_t host = SDMMC_HOST_DEFAULT ();
host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT ();
slot_config.gpio_cd = g_gpio;
slot_config.width = mode & 0X01;
gpio_set_pull_mode (GPIO_NUM_15, GPIO_PULLUP_ONLY);
gpio_set_pull_mode (GPIO_NUM_2, GPIO_PULLUP_ONLY);
gpio_set_pull_mode (GPIO_NUM_13, GPIO_PULLUP_ONLY);
if (mode == SD_MODE_4_LINE)
{
gpio_set_pull_mode (GPIO_NUM_4, GPIO_PULLUP_ONLY);
gpio_set_pull_mode (GPIO_NUM_12, GPIO_PULLUP_ONLY);
}
ret = esp_vfs_fat_sdmmc_mount (base_path, &host, &slot_config,
&mount_config, &card);
}
else
{
ESP_LOGI (TAG, "Using SPI mode, base path=%s", base_path);
sdmmc_host_t host = SDSPI_HOST_DEFAULT ();
sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT ();
slot_config.gpio_miso = PIN_NUM_MISO;
slot_config.gpio_mosi = PIN_NUM_MOSI;
slot_config.gpio_sck = PIN_NUM_CLK;
slot_config.gpio_cs = PIN_NUM_CS;
ret = esp_vfs_fat_sdmmc_mount (base_path, &host, &slot_config,
&mount_config, &card);
}
switch (ret)
{
case ESP_OK:
// Card has been initialized, print its properties
sdmmc_card_print_info (card);
ESP_LOGI (TAG, "CID name %s!\n", card->cid.name);
break;
case ESP_ERR_INVALID_STATE:
ESP_LOGE (TAG, "File system already mounted");
break;
case ESP_FAIL:
ESP_LOGE (TAG, "Failed to mount filesystem. If you want the card to be "
"formatted, set format_if_mount_failed = true.");
break;
default:
ESP_LOGE (TAG,
"Failed to initialize the card (%d). Make sure SD card lines "
"have pull-up resistors in place.",
ret);
break;
}
return ret;
}
esp_err_t
sdcard_unmount (void)
{
esp_err_t ret = esp_vfs_fat_sdmmc_unmount ();
if (ret == ESP_ERR_INVALID_STATE)
{
ESP_LOGE (TAG, "File system not mounted");
}
return ret;
}
bool
sdcard_is_exist ()
{
if (g_gpio >= 0)
{
return (gpio_get_level (g_gpio) == 0x00);
}
else
{
return true;
}
return false;
}
int IRAM_ATTR
sdcard_read_detect_pin (void)
{
if (g_gpio >= 0)
{
return gpio_get_level (g_gpio);
}
else
{
return -1;
}
return 0;
}
esp_err_t
sdcard_destroy ()
{
if (g_gpio >= 0)
{
return gpio_isr_handler_remove (g_gpio);
}
return ESP_OK;
}
esp_err_t
sdcard_init (int card_detect_pin, void (*detect_intr_handler) (void *),
void *isr_context)
{
esp_err_t ret = ESP_OK;
if (card_detect_pin >= 0)
{
gpio_set_direction (card_detect_pin, GPIO_MODE_INPUT);
if (detect_intr_handler)
{
gpio_set_intr_type (card_detect_pin, GPIO_INTR_ANYEDGE);
gpio_isr_handler_add (card_detect_pin, detect_intr_handler,
isr_context);
gpio_intr_enable (card_detect_pin);
}
gpio_pullup_en (card_detect_pin);
}
g_gpio = card_detect_pin;
return ret;
}

View File

@@ -0,0 +1,105 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _ESP_SDCARD_H_
#define _ESP_SDCARD_H_
#include "audio_error.h"
#include "periph_sdcard.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief { function_description }
*
* @param[in] gpio The gpio
* @param[in] detect_intr_handler The detect intr handler
* @param isr_context The isr context
*
* @return { description_of_the_return_value }
*/
esp_err_t sdcard_init (int gpio, void (*detect_intr_handler) (void *),
void *isr_context);
/**
* @brief mount sdcard to FAT filesystem
*
* @param base_path path where partition should be registered (e.g.
* "/sdcard")
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount was already called
* - ESP_ERR_NO_MEM if memory can not be allocated
* - ESP_FAIL if partition can not be mounted
* - other error codes from SDMMC or SPI drivers, SDMMC protocol, or
* FATFS drivers
*/
esp_err_t sdcard_mount (const char *base_path, periph_sdcard_mode_t mode);
/**
* @brief Unmount FAT filesystem and release resources acquired using
* esp_vfs_fat_sdmmc_mount
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if sd_card_mount hasn't been called
*/
esp_err_t sdcard_unmount (void);
/**
* @brief remove the sdcard device GPIO interruption in Audio board
*
* @return
* - ESP_OK on success
* - ESP_FAIL destory sdcard gpio handle failed
*/
esp_err_t sdcard_destroy (void);
/**
* @brief get the status of sdcard is insert or not
*
* @return
* - true sdcard is insert
* - false sdcard is unplug
*/
bool sdcard_is_exist ();
/**
* @brief Read value of CARD DETECT Pin
*
* @return value of CARD DETECT PIN
*/
int sdcard_read_detect_pin (void);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,350 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include "audio_mem.h"
#include "driver/gpio.h"
#include "driver/touch_pad.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "sys/queue.h"
#include "touch.h"
#define TOUCHPAD_TRIGGER_THRESHOLD 100
#define TOUCHPAD_FILTER_PERIOD (30)
#define TOUCHPAD_READ_INTERVAL_MS (TOUCHPAD_FILTER_PERIOD * 4)
#define TOUCHPAD_INTIALIZE_TIME_MS 1000
#define UPDATE_THRESHOLD_PERIOD_MS 200
static const char *TAG = "TOUCH";
typedef struct esp_touch_item
{
int touch_num;
long long last_tap_tick;
long long update_threshold_tick;
long long last_read_tick;
uint16_t last_read_value;
uint16_t untouch_value;
uint16_t threshold_value;
bool long_tapped;
bool tapped;
STAILQ_ENTRY (esp_touch_item) entry;
} esp_touch_item_t;
struct esp_touch
{
int long_tap_time_ms;
int touch_mask;
int tap_threshold_percent;
touch_intr_handler intr_fn;
void *intr_context;
STAILQ_HEAD (esp_touch_list, esp_touch_item) touch_list;
};
#ifdef periph_tick_get
#define tick_get periph_tick_get
#else
static long long
tick_get ()
{
struct timeval te;
gettimeofday (&te, NULL); // get current time
long long milliseconds
= te.tv_sec * 1000LL + te.tv_usec / 1000; // calculate milliseconds
return milliseconds;
}
#endif
static void
touch_pad_isr_handler (void *arg)
{
esp_touch_handle_t touch = (esp_touch_handle_t)arg;
#if CONFIG_IDF_TARGET_ESP32
touch_pad_clear_status ();
#endif
if (touch->intr_fn)
{
touch->intr_fn (touch->intr_context);
}
}
esp_touch_handle_t
esp_touch_init (touch_config_t *config)
{
esp_touch_handle_t touch = audio_calloc (1, sizeof (struct esp_touch));
AUDIO_MEM_CHECK (TAG, touch, return NULL);
if (config->touch_mask <= 0)
{
ESP_LOGE (TAG, "required at least 1 touch");
return NULL;
}
touch->touch_mask = config->touch_mask;
touch->long_tap_time_ms = config->long_tap_time_ms;
touch->tap_threshold_percent = config->tap_threshold_percent;
if (touch->long_tap_time_ms == 0)
{
touch->long_tap_time_ms = DEFAULT_LONG_TAP_TIME_MS;
}
if (touch->tap_threshold_percent == 0)
{
touch->tap_threshold_percent = DEFAULT_TOUCH_THRESHOLD_PERCENT;
}
bool _success = (touch_pad_init () == ESP_OK);
AUDIO_MEM_CHECK (TAG, _success, {
audio_free (touch);
return NULL;
});
int touch_mask = touch->touch_mask;
int touch_num = 0;
int touch_index = 0;
STAILQ_INIT (&touch->touch_list);
while (touch_mask)
{
if (touch_mask & 0x01)
{
ESP_LOGD (TAG, "Mask = %x, current_mask = %x, idx=%d",
touch->touch_mask, touch_mask, touch_num);
esp_touch_item_t *new_touch
= audio_calloc (1, sizeof (esp_touch_item_t));
AUDIO_MEM_CHECK (TAG, new_touch, {
esp_touch_destroy (touch);
audio_free (touch);
return NULL;
});
new_touch->touch_num = touch_num;
new_touch->last_read_tick = tick_get () + touch_index * 10;
#if CONFIG_IDF_TARGET_ESP32
touch_pad_config (touch_num, 0);
#elif CONFIG_IDF_TARGET_ESP32S2
touch_pad_config (touch_num);
#endif
if (config->touch_intr_handler)
{
touch_pad_set_thresh (touch_num, TOUCHPAD_TRIGGER_THRESHOLD);
}
STAILQ_INSERT_TAIL (&touch->touch_list, new_touch, entry);
touch_index++;
}
touch_mask >>= 1;
touch_num++;
}
touch->intr_fn = config->touch_intr_handler;
touch->intr_context = config->intr_context;
if (config->touch_intr_handler)
{
#if CONFIG_IDF_TARGET_ESP32
touch_pad_isr_register (touch_pad_isr_handler, touch);
touch_pad_intr_enable ();
#elif CONFIG_IDF_TARGET_ESP32S2
touch_pad_isr_register (touch_pad_isr_handler, touch,
TOUCH_PAD_INTR_MASK_ALL);
touch_pad_intr_enable (TOUCH_PAD_INTR_MASK_ALL);
#endif
}
#if CONFIG_IDF_TARGET_ESP32
touch_pad_filter_start (TOUCHPAD_FILTER_PERIOD);
#endif
return touch;
}
static touch_status_t
touch_get_state (esp_touch_handle_t touch, esp_touch_item_t *touch_item,
long long tick)
{
if (tick - touch_item->last_read_tick < TOUCHPAD_READ_INTERVAL_MS)
{
return TOUCH_UNCHANGE;
}
touch_item->last_read_tick = tick;
esp_err_t err = ESP_OK;
#if CONFIG_IDF_TARGET_ESP32
err = touch_pad_read_filtered (touch_item->touch_num,
&touch_item->last_read_value);
#elif CONFIG_IDF_TARGET_ESP32S2
err = ESP_OK;
#endif
if (err != ESP_OK)
{
return TOUCH_UNCHANGE;
}
if (touch_item->untouch_value == 0)
{
touch_item->untouch_value = touch_item->last_read_value;
int threshold_value
= touch_item->untouch_value * touch->tap_threshold_percent / 100;
touch_item->threshold_value = threshold_value;
}
if (!touch_item->tapped
&& touch_item->last_read_value < touch_item->threshold_value)
{
touch_item->tapped = true;
}
else if (touch_item->tapped
&& touch_item->last_read_value > touch_item->threshold_value)
{
touch_item->tapped = false;
}
// Update touch threshold
if (tick - touch_item->update_threshold_tick > UPDATE_THRESHOLD_PERIOD_MS
&& !touch_item->tapped)
{
touch_item->update_threshold_tick = tick;
touch_item->untouch_value += touch_item->last_read_value;
touch_item->untouch_value /= 2;
int threshold_value
= touch_item->untouch_value * touch->tap_threshold_percent / 100;
touch_item->threshold_value = threshold_value;
// ESP_LOGD(TAG, "UPDATE THRESHOLD[%d]=%d", touch_item->touch_num,
// threshold_value);
}
if (touch_item->last_tap_tick == 0 && touch_item->tapped)
{
touch_item->last_tap_tick = tick_get ();
touch_item->long_tapped = false;
ESP_LOGD (TAG, "TOUCH_TAPPED[%d] %d, threshold %d",
touch_item->touch_num, touch_item->last_read_value,
touch_item->threshold_value);
return TOUCH_TAP;
}
if (!touch_item->tapped && touch_item->last_tap_tick
&& tick_get () - touch_item->last_tap_tick > touch->long_tap_time_ms)
{
touch_item->last_tap_tick = 0;
touch_item->long_tapped = false;
ESP_LOGD (TAG, "TOUCH_LONG_RELEASE[%d] %d, threshold %d",
touch_item->touch_num, touch_item->last_read_value,
touch_item->threshold_value);
return TOUCH_LONG_RELEASE;
}
if (!touch_item->tapped && touch_item->last_tap_tick)
{
touch_item->last_tap_tick = 0;
touch_item->long_tapped = false;
ESP_LOGD (TAG, "TOUCH_RELEASE[%d] %d, threshold %d",
touch_item->touch_num, touch_item->last_read_value,
touch_item->threshold_value);
return TOUCH_RELEASE;
}
if (touch_item->long_tapped == false && touch_item->tapped
&& tick_get () - touch_item->last_tap_tick > touch->long_tap_time_ms)
{
touch_item->long_tapped = true;
ESP_LOGD (TAG, "TOUCH_LONG_TAP[%d] %d, threshold %d",
touch_item->touch_num, touch_item->last_read_value,
touch_item->threshold_value);
return TOUCH_LONG_TAP;
}
return TOUCH_UNCHANGE;
}
bool
esp_touch_read (esp_touch_handle_t touch, touch_result_t *result)
{
esp_touch_item_t *touch_item;
touch_status_t touch_status;
bool changed = false;
memset (result, 0, sizeof (touch_result_t));
int tmp;
long long tick = tick_get ();
STAILQ_FOREACH (touch_item, &touch->touch_list, entry)
{
touch_status = touch_get_state (touch, touch_item, tick);
switch (touch_status)
{
case TOUCH_UNCHANGE:
break;
case TOUCH_TAP:
changed = true;
tmp = 0x01;
tmp <<= touch_item->touch_num;
result->tap_mask |= tmp;
break;
case TOUCH_RELEASE:
changed = true;
tmp = 0x01;
tmp <<= touch_item->touch_num;
result->release_mask |= tmp;
break;
case TOUCH_LONG_RELEASE:
changed = true;
tmp = 0x01;
tmp <<= touch_item->touch_num;
result->long_release_mask |= tmp;
break;
case TOUCH_LONG_TAP:
changed = true;
tmp = 0x01;
tmp <<= touch_item->touch_num;
result->long_tap_mask |= tmp;
break;
}
}
return changed;
}
esp_err_t
esp_touch_destroy (esp_touch_handle_t touch)
{
esp_touch_item_t *touch_item, *tmp;
#if CONFIG_IDF_TARGET_ESP32
touch_pad_filter_delete ();
touch_pad_intr_disable ();
#elif CONFIG_IDF_TARGET_ESP32S2
touch_pad_intr_disable (TOUCH_PAD_INTR_MASK_ALL);
#endif
touch_pad_isr_deregister (touch_pad_isr_handler, touch);
STAILQ_FOREACH_SAFE (touch_item, &touch->touch_list, entry, tmp)
{
STAILQ_REMOVE (&touch->touch_list, touch_item, esp_touch_item, entry);
audio_free (touch_item);
}
touch_pad_deinit ();
audio_free (touch);
return ESP_OK;
}

View File

@@ -0,0 +1,110 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#ifndef _ESP_TOUCH_PAD_H_
#define _ESP_TOUCH_PAD_H_
#include "audio_error.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief { item_description }
*/
typedef enum
{
TOUCH_UNCHANGE = 0,
TOUCH_TAP,
TOUCH_RELEASE,
TOUCH_LONG_TAP,
TOUCH_LONG_RELEASE,
} touch_status_t;
/**
* @brief { item_description }
*/
typedef struct
{
int tap_mask;
int release_mask;
int long_tap_mask;
int long_release_mask;
} touch_result_t;
typedef struct esp_touch *esp_touch_handle_t;
typedef void (*touch_intr_handler) (void *);
#define DEFAULT_LONG_TAP_TIME_MS (2 * 1000)
#define DEFAULT_TOUCH_THRESHOLD_PERCENT (70)
/**
* @brief { item_description }
*/
typedef struct
{
int long_tap_time_ms;
int touch_mask;
int tap_threshold_percent;
touch_intr_handler touch_intr_handler;
void *intr_context;
} touch_config_t;
/**
* @brief { function_description }
*
* @param config The configuration
*
* @return { description_of_the_return_value }
*/
esp_touch_handle_t esp_touch_init (touch_config_t *config);
/**
* @brief { function_description }
*
* @param[in] touch The touch
* @param result The result
*
* @return { description_of_the_return_value }
*/
bool esp_touch_read (esp_touch_handle_t touch, touch_result_t *result);
/**
* @brief { function_description }
*
* @param[in] touch The touch
*
* @return { description_of_the_return_value }
*/
esp_err_t esp_touch_destroy (esp_touch_handle_t touch);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,113 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "periph_adc_button.h"
#include "audio_error.h"
#include "audio_mem.h"
#include "esp_log.h"
#include <string.h>
static const char *TAG = "PERIPH_ADC_BUTTON";
typedef struct
{
int adc_channels;
adc_btn_list *list;
adc_btn_task_cfg_t task_cfg;
} periph_adc_btn_t;
static void
btn_cb (void *user_data, int adc, int id, adc_btn_state_t state)
{
esp_periph_handle_t self = (esp_periph_handle_t)user_data;
periph_adc_button_event_id_t event_id = PERIPH_ADC_BUTTON_IDLE;
if (state == ADC_BTN_STATE_PRESSED)
{
event_id = PERIPH_ADC_BUTTON_PRESSED;
}
else if (state == ADC_BTN_STATE_LONG_PRESSED)
{
event_id = PERIPH_ADC_BUTTON_LONG_PRESSED;
}
else if (state == ADC_BTN_STATE_RELEASE)
{
event_id = PERIPH_ADC_BUTTON_RELEASE;
}
else if (state == ADC_BTN_STATE_LONG_RELEASE)
{
event_id = PERIPH_ADC_BUTTON_LONG_RELEASE;
}
// Send ID as data and ADC as data_len
esp_periph_send_event (self, event_id, (void *)id, adc);
}
static esp_err_t
_adc_button_destroy (esp_periph_handle_t self)
{
periph_adc_btn_t *periph_adc_btn = esp_periph_get_data (self);
adc_btn_delete_task ();
adc_btn_destroy_list (periph_adc_btn->list);
audio_free (periph_adc_btn);
return ESP_OK;
}
static esp_err_t
_adc_button_init (esp_periph_handle_t self)
{
periph_adc_btn_t *periph_adc_btn = esp_periph_get_data (self);
adc_btn_init ((void *)self, btn_cb, periph_adc_btn->list,
&periph_adc_btn->task_cfg);
return ESP_OK;
}
esp_periph_handle_t
periph_adc_button_init (periph_adc_button_cfg_t *config)
{
esp_periph_handle_t periph
= esp_periph_create (PERIPH_ID_ADC_BTN, "periph_adc_btn");
AUDIO_MEM_CHECK (TAG, periph, return NULL);
periph_adc_btn_t *periph_adc_btn
= audio_calloc (1, sizeof (periph_adc_btn_t));
AUDIO_MEM_CHECK (TAG, periph_adc_btn, {
audio_free (periph);
return NULL;
});
periph_adc_btn->adc_channels = config->arr_size;
periph_adc_btn->list = adc_btn_create_list (config->arr, config->arr_size);
memcpy (&periph_adc_btn->task_cfg, &config->task_cfg,
sizeof (adc_btn_task_cfg_t));
AUDIO_MEM_CHECK (TAG, periph_adc_btn->list, {
audio_free (periph);
audio_free (periph_adc_btn);
return NULL;
});
esp_periph_set_data (periph, periph_adc_btn);
esp_periph_set_function (periph, _adc_button_init, NULL,
_adc_button_destroy);
return periph;
}

View File

@@ -0,0 +1,184 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "periph_aw2013.h"
#include "audio_mem.h"
#include "aw2013.h"
#include "esp_peripherals.h"
static const char *TAG = "PERIPH_AW2013";
typedef struct
{
aw2013_time_level_t time[5];
aw2013_brightness_t bright;
periph_aw2013_mode_t mode;
uint32_t rgb_value;
uint8_t rpt_time;
} periph_aw2013_t;
static esp_err_t
_aw2013_set_mode (periph_aw2013_mode_t mode)
{
esp_err_t ret = ESP_OK;
switch (mode)
{
case AW2013_MODE_LED:
ret |= aw2013_enable_auto_flash (false);
ret |= aw2013_enable_fade_mode (false);
break;
case AW2013_MODE_FADE:
ret |= aw2013_enable_auto_flash (false);
ret |= aw2013_enable_fade_mode (true);
break;
case AW2013_MODE_AUTO:
ret |= aw2013_enable_auto_flash (true);
ret |= aw2013_enable_fade_mode (false);
break;
default:
ESP_LOGE (TAG, "Invalid mode :%d", mode);
return ESP_FAIL;
}
return ESP_OK;
}
static esp_err_t
_aw2013_init (esp_periph_handle_t self)
{
esp_err_t ret = ESP_OK;
periph_aw2013_t *aw2013 = esp_periph_get_data (self);
ret |= aw2013_init ();
for (int i = 0; i <= AW2013_TIME_4; i++)
{
ret |= aw2013_set_time (i, aw2013->time[i]);
}
ret |= aw2013_set_repeat_time (aw2013->rpt_time);
ret |= aw2013_set_brightness (aw2013->bright);
ret |= _aw2013_set_mode (aw2013->mode);
ret |= aw2013_set_pwm_value (aw2013->rgb_value);
return ret;
}
static esp_err_t
_aw2013_destroy (esp_periph_handle_t self)
{
esp_err_t ret = ESP_OK;
periph_aw2013_t *aw2013 = esp_periph_get_data (self);
ret |= aw2013_deinit ();
audio_free (aw2013);
return ret;
}
esp_err_t
periph_aw2013_set_brightless (esp_periph_handle_t periph,
aw2013_brightness_t bright)
{
periph_aw2013_t *aw2013 = esp_periph_get_data (periph);
if (bright < AW2013_BRIGHT_0 || bright > AW2013_BRIGHT_3)
{
ESP_LOGE (TAG, "Fail to set parameters, bright: %d", bright);
return ESP_FAIL;
}
aw2013->bright = bright;
return aw2013_set_brightness (bright);
}
esp_err_t
periph_aw2013_set_rgb_value (esp_periph_handle_t periph, uint32_t value)
{
periph_aw2013_t *aw2013 = esp_periph_get_data (periph);
aw2013->rgb_value = value;
return aw2013_set_pwm_value (value);
}
esp_err_t
periph_aw2013_set_repeat_time (esp_periph_handle_t periph, uint8_t cnt)
{
periph_aw2013_t *aw2013 = esp_periph_get_data (periph);
aw2013->rpt_time = cnt;
return aw2013_set_repeat_time (cnt);
}
esp_err_t
periph_aw2013_set_mode (esp_periph_handle_t periph, periph_aw2013_mode_t mode)
{
if (mode < 0 || mode > AW2013_MODE_AUTO)
{
ESP_LOGE (TAG, "Fail to set parameters, mode: %d", mode);
return ESP_FAIL;
}
periph_aw2013_t *aw2013 = esp_periph_get_data (periph);
aw2013->mode = mode;
return _aw2013_set_mode (mode);
}
esp_err_t
periph_aw2013_set_time (esp_periph_handle_t periph, aw2013_time_t time,
aw2013_time_level_t level)
{
if (time < 0 || time > AW2013_TIME_4 || level < 0
|| level > AW2013_TIME_LEVEL_8)
{
ESP_LOGE (TAG, "Fail to set parameters, time: %d, level: %d", time,
level);
return ESP_FAIL;
}
periph_aw2013_t *aw2013 = esp_periph_get_data (periph);
aw2013->time[time] = level;
return aw2013_set_time (time, level);
}
esp_periph_handle_t
periph_aw2013_init (periph_aw2013_cfg_t *aw2013_cfg)
{
esp_periph_handle_t periph
= esp_periph_create (PERIPH_ID_AW2013, "periph_aw2013");
AUDIO_NULL_CHECK (TAG, periph, return NULL);
periph_aw2013_t *aw2013 = audio_calloc (1, sizeof (periph_aw2013_t));
AUDIO_MEM_CHECK (TAG, aw2013, {
audio_free (periph);
return NULL;
});
aw2013->mode = aw2013_cfg->mode;
aw2013->bright = aw2013_cfg->bright;
aw2013->rgb_value = aw2013_cfg->rgb_value;
// Default time period
aw2013->time[0] = AW2013_TIME_LEVEL_1;
aw2013->time[1] = AW2013_TIME_LEVEL_3;
aw2013->time[2] = AW2013_TIME_LEVEL_3;
aw2013->time[3] = AW2013_TIME_LEVEL_3;
aw2013->time[4] = AW2013_TIME_LEVEL_2;
// Cycle all the time
aw2013->rpt_time = 0;
esp_periph_set_data (periph, aw2013);
esp_periph_set_function (periph, _aw2013_init, NULL, _aw2013_destroy);
return periph;
}

View File

@@ -0,0 +1,146 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "periph_button.h"
#include "audio_mem.h"
#include "button.h"
#include "esp_log.h"
static const char *TAG = "PERIPH_BUTTON";
#define VALIDATE_BTN(periph, ret) \
if (!(periph && esp_periph_get_id (periph) == PERIPH_ID_BUTTON)) \
{ \
ESP_LOGE (TAG, "Invalid BUTTON periph, at line %d", __LINE__); \
return ret; \
}
typedef struct
{
esp_button_handle_t btn;
uint64_t gpio_mask;
int long_press_time_ms;
} periph_button_t;
static void
button_send_event (esp_periph_handle_t self, int event_id, uint64_t mask)
{
int gpio_num = 0;
while (mask)
{
if (mask & 0x01)
{
esp_periph_send_event (self, event_id, (void *)gpio_num, 0);
}
mask >>= 1;
gpio_num++;
}
}
static esp_err_t
_button_run (esp_periph_handle_t self, audio_event_iface_msg_t *msg)
{
button_result_t result;
periph_button_t *periph_btn = esp_periph_get_data (self);
if (button_read (periph_btn->btn, &result))
{
ESP_LOGD (TAG,
"Button event, press_mask %llx, release_mask: %llx, "
"long_press_mask: %llx, long_release_mask: %llx",
result.press_mask, result.release_mask, result.long_press_mask,
result.long_release_mask);
button_send_event (self, PERIPH_BUTTON_PRESSED, result.press_mask);
button_send_event (self, PERIPH_BUTTON_RELEASE, result.release_mask);
button_send_event (self, PERIPH_BUTTON_LONG_PRESSED,
result.long_press_mask);
button_send_event (self, PERIPH_BUTTON_LONG_RELEASE,
result.long_release_mask);
}
return ESP_OK;
}
static esp_err_t
_button_destroy (esp_periph_handle_t self)
{
periph_button_t *periph_btn = esp_periph_get_data (self);
button_destroy (periph_btn->btn);
audio_free (periph_btn);
return ESP_OK;
}
static void IRAM_ATTR
button_intr_handler (void *param)
{
esp_periph_handle_t periph = (esp_periph_handle_t)param;
esp_periph_send_cmd_from_isr (periph, 0, NULL, 0);
}
static void
button_timer_handler (xTimerHandle tmr)
{
esp_periph_handle_t periph = (esp_periph_handle_t)pvTimerGetTimerID (tmr);
esp_periph_send_cmd_from_isr (periph, 0, NULL, 0);
}
static esp_err_t
_button_init (esp_periph_handle_t self)
{
int ret = 0;
VALIDATE_BTN (self, ESP_FAIL);
periph_button_t *periph_btn = esp_periph_get_data (self);
button_config_t btn_config = {
.gpio_mask = periph_btn->gpio_mask,
.long_press_time_ms = periph_btn->long_press_time_ms,
.button_intr_handler = button_intr_handler,
.intr_context = self,
};
periph_btn->btn = button_init (&btn_config);
esp_periph_start_timer (self, 50 / portTICK_RATE_MS, button_timer_handler);
return ret;
}
esp_periph_handle_t
periph_button_init (periph_button_cfg_t *config)
{
esp_periph_handle_t periph
= esp_periph_create (PERIPH_ID_BUTTON, "periph_btn");
AUDIO_MEM_CHECK (TAG, periph, return NULL);
periph_button_t *periph_btn = audio_calloc (1, sizeof (periph_button_t));
AUDIO_MEM_CHECK (TAG, periph_btn, {
audio_free (periph);
return NULL;
});
periph_btn->gpio_mask = config->gpio_mask;
periph_btn->long_press_time_ms = config->long_press_time_ms;
esp_periph_set_data (periph, periph_btn);
esp_periph_set_function (periph, _button_init, _button_run, _button_destroy);
return periph;
}

View File

@@ -0,0 +1,373 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "periph_console.h"
#include "argtable3/argtable3.h"
#include "audio_mem.h"
#include "driver/uart.h"
#include "esp_console.h"
#include "esp_log.h"
#include "esp_vfs_dev.h"
#include "sys/queue.h"
#include <string.h>
#if __has_include("esp_idf_version.h")
#include "esp_idf_version.h"
#else
#define ESP_IDF_VERSION_VAL(major, minor, patch) 1
#endif
#define CONSOLE_MAX_ARGUMENTS (5)
static const char *TAG = "PERIPH_CONSOLE";
static const int STOPPED_BIT = BIT1;
typedef struct periph_console *periph_console_handle_t;
typedef struct periph_console
{
char *buffer;
int total_bytes;
bool run;
const periph_console_cmd_t *commands;
int command_num;
EventGroupHandle_t state_event_bits;
int task_stack;
int task_prio;
int buffer_size;
char *prompt_string;
} periph_console_t;
static char *
conslole_parse_arguments (char *str, char **saveptr)
{
char *p;
if (str != NULL)
{
*saveptr = str;
}
p = *saveptr;
if (!p)
{
return NULL;
}
/* Skipping white space.*/
while (*p == ' ' || *p == '\t')
{
p++;
}
if (*p == '"')
{
/* If an argument starts with a double quote then its delimiter is
* another quote.*/
p++;
*saveptr = strstr (p, "\"");
}
else
{
/* The delimiter is white space.*/
*saveptr = strpbrk (p, " \t");
}
/* Replacing the delimiter with a zero.*/
if (*saveptr != NULL)
{
*(*saveptr)++ = '\0';
}
return *p != '\0' ? p : NULL;
}
bool
console_get_line (periph_console_handle_t console, unsigned max_size,
TickType_t time_to_wait)
{
char c;
char tx[3];
int nread = 0;
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
nread = uart_read_bytes (CONFIG_ESP_CONSOLE_UART_NUM, (uint8_t *)&c, 1,
time_to_wait);
#else
nread = uart_read_bytes (CONFIG_CONSOLE_UART_NUM, (uint8_t *)&c, 1,
time_to_wait);
#endif
if (nread <= 0)
{
return false;
}
if ((c == 8) || (c == 127))
{ // backspace or del
if (console->total_bytes > 0)
{
console->total_bytes--;
tx[0] = c;
tx[1] = 0x20;
tx[2] = c;
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
uart_write_bytes (CONFIG_ESP_CONSOLE_UART_NUM, (const char *)tx, 3);
#else
uart_write_bytes (CONFIG_CONSOLE_UART_NUM, (const char *)tx, 3);
#endif
}
return false;
}
if (c == '\n' || c == '\r')
{
tx[0] = '\r';
tx[1] = '\n';
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
uart_write_bytes (CONFIG_ESP_CONSOLE_UART_NUM, (const char *)tx, 2);
#else
uart_write_bytes (CONFIG_CONSOLE_UART_NUM, (const char *)tx, 2);
#endif
console->buffer[console->total_bytes] = 0;
return true;
}
if (c < 0x20)
{
return false;
}
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
uart_write_bytes (CONFIG_ESP_CONSOLE_UART_NUM, (const char *)&c, 1);
#else
uart_write_bytes (CONFIG_CONSOLE_UART_NUM, (const char *)&c, 1);
#endif
console->buffer[console->total_bytes++] = (char)c;
if (console->total_bytes > max_size)
{
console->total_bytes = 0;
}
return false;
}
static bool
console_exec (esp_periph_handle_t self, char *cmd, int argc, char *argv[])
{
periph_console_handle_t console
= (periph_console_handle_t)esp_periph_get_data (self);
if (cmd == NULL)
{
return false;
}
int i;
for (i = 0; i < console->command_num; i++)
{
if (strcasecmp (cmd, console->commands[i].cmd) == 0)
{
if (console->commands[i].func)
{
console->commands[i].func (self, argc, argv);
return true;
}
int cmd_id = console->commands[i].id;
if (cmd_id == 0)
{
cmd_id = i;
}
esp_periph_send_event (self, cmd_id, argv, argc);
return true;
}
}
printf ("----------------------\r\n");
printf ("Perpheral console HELP\r\n");
printf ("----------------------\r\n");
for (i = 0; i < console->command_num; i++)
{
printf ("%s \t%s\r\n", console->commands[i].cmd,
console->commands[i].help);
}
return false;
}
static esp_err_t
_console_destroy (esp_periph_handle_t self)
{
periph_console_handle_t console
= (periph_console_handle_t)esp_periph_get_data (self);
console->run = false;
xEventGroupWaitBits (console->state_event_bits, STOPPED_BIT, false, true,
portMAX_DELAY);
vEventGroupDelete (console->state_event_bits);
if (console->prompt_string)
{
audio_free (console->prompt_string);
}
audio_free (console->buffer);
audio_free (console);
return ESP_OK;
}
static void
_console_task (void *pv)
{
esp_periph_handle_t self = (esp_periph_handle_t)pv;
char *lp, *cmd, *tokp;
char *args[CONSOLE_MAX_ARGUMENTS + 1];
int n;
periph_console_handle_t console
= (periph_console_handle_t)esp_periph_get_data (self);
if (console->total_bytes >= console->buffer_size)
{
console->total_bytes = 0;
}
console->run = true;
xEventGroupClearBits (console->state_event_bits, STOPPED_BIT);
const char *prompt_string = CONSOLE_DEFAULT_PROMPT_STRING;
if (console->prompt_string)
{
prompt_string = console->prompt_string;
}
printf ("\r\n%s ", prompt_string);
while (console->run)
{
if (console_get_line (console, console->buffer_size,
10 / portTICK_RATE_MS))
{
if (console->total_bytes)
{
ESP_LOGD (TAG, "Read line: %s", console->buffer);
}
lp = conslole_parse_arguments (console->buffer, &tokp);
cmd = lp;
n = 0;
while ((lp = conslole_parse_arguments (NULL, &tokp)) != NULL)
{
if (n >= CONSOLE_MAX_ARGUMENTS)
{
printf ("too many arguments\r\n");
cmd = NULL;
break;
}
args[n++] = lp;
}
args[n] = NULL;
if (console->total_bytes > 0)
{
console_exec (self, cmd, n, args);
console->total_bytes = 0;
}
printf ("%s ", prompt_string);
}
}
xEventGroupSetBits (console->state_event_bits, STOPPED_BIT);
vTaskDelete (NULL);
}
static esp_err_t
_console_init (esp_periph_handle_t self)
{
periph_console_handle_t console
= (periph_console_handle_t)esp_periph_get_data (self);
setvbuf (stdin, NULL, _IONBF, 0);
setvbuf (stdout, NULL, _IONBF, 0);
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
esp_vfs_dev_uart_set_rx_line_endings (ESP_LINE_ENDINGS_CR);
/* Move the caret to the beginning of the next line on '\n' */
esp_vfs_dev_uart_set_tx_line_endings (ESP_LINE_ENDINGS_CRLF);
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
uart_driver_install (CONFIG_ESP_CONSOLE_UART_NUM, console->buffer_size * 2,
0, 0, NULL, 0);
#else
uart_driver_install (CONFIG_CONSOLE_UART_NUM, console->buffer_size * 2, 0, 0,
NULL, 0);
#endif
/* Tell VFS to use UART driver */
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
esp_vfs_dev_uart_use_driver (CONFIG_ESP_CONSOLE_UART_NUM);
#else
esp_vfs_dev_uart_use_driver (CONFIG_CONSOLE_UART_NUM);
#endif
console->buffer = (char *)audio_malloc (console->buffer_size);
AUDIO_MEM_CHECK (TAG, console->buffer, { return ESP_ERR_NO_MEM; });
if (xTaskCreate (_console_task, "console_task", console->task_stack, self,
console->task_prio, NULL)
!= pdTRUE)
{
ESP_LOGE (TAG, "Error create console task, memory exhausted?");
return ESP_FAIL;
}
return ESP_OK;
}
esp_periph_handle_t
periph_console_init (periph_console_cfg_t *config)
{
esp_periph_handle_t periph
= esp_periph_create (PERIPH_ID_CONSOLE, "periph_console");
AUDIO_MEM_CHECK (TAG, periph, return NULL);
periph_console_t *console = audio_calloc (1, sizeof (periph_console_t));
AUDIO_MEM_CHECK (TAG, console, {
audio_free (periph);
return NULL;
});
console->commands = config->commands;
console->command_num = config->command_num;
console->task_stack = CONSOLE_DEFAULT_TASK_STACK;
console->task_prio = CONSOLE_DEFAULT_TASK_PRIO;
console->buffer_size = CONSOLE_DEFAULT_BUFFER_SIZE;
if (config->buffer_size > 0)
{
console->buffer_size = config->buffer_size;
}
if (config->task_stack > 0)
{
console->task_stack = config->task_stack;
}
if (config->task_prio)
{
console->task_prio = config->task_prio;
}
if (config->prompt_string)
{
console->prompt_string = audio_strdup (config->prompt_string);
AUDIO_MEM_CHECK (TAG, console->prompt_string, {
audio_free (periph);
audio_free (console);
return NULL;
});
}
console->state_event_bits = xEventGroupCreate ();
esp_periph_set_data (periph, console);
esp_periph_set_function (periph, _console_init, NULL, _console_destroy);
return periph;
}

View File

@@ -0,0 +1,184 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2019 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "periph_gpio_isr.h"
#include "audio_error.h"
#include "audio_mem.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_peripherals.h"
#include "sys/queue.h"
#include <string.h>
static const char *TAG = "PERIPH_GPIO_ISR";
typedef struct gpio_info_node
{
gpio_isr_info_t gpio_info;
STAILQ_ENTRY (gpio_info_node) entries;
} gpio_isr_node_t;
static esp_periph_handle_t g_handle = NULL;
static STAILQ_HEAD (gpio_isr_list, gpio_info_node) gpio_isr_info_list;
static void IRAM_ATTR
gpio_isr_handler (void *param)
{
int gpio_num = (int)param;
esp_periph_send_cmd_from_isr (g_handle, gpio_num, NULL, 0);
}
static esp_err_t
_gpio_isr_init (esp_periph_handle_t self)
{
esp_err_t ret = ESP_OK;
gpio_isr_node_t *tmp_node = NULL;
gpio_isr_info_t *tmp_info = NULL;
STAILQ_FOREACH (tmp_node, &gpio_isr_info_list, entries)
{
tmp_info = &tmp_node->gpio_info;
ret |= gpio_isr_init (tmp_info->gpio_num, tmp_info->type, gpio_isr_handler,
(void *)tmp_info->gpio_num);
}
return ret;
}
static esp_err_t
_gpio_isr_run (esp_periph_handle_t self, audio_event_iface_msg_t *msg)
{
esp_err_t ret = ESP_OK;
if (msg->cmd >= 0)
{
ret = esp_periph_send_event (self, 0, (void *)msg->cmd, 0);
return ret;
}
return ESP_FAIL;
}
static esp_err_t
_gpio_isr_destory (esp_periph_handle_t self)
{
esp_err_t ret = ESP_OK;
gpio_isr_node_t *tmp, *item;
gpio_isr_info_t *tmp_info = NULL;
STAILQ_FOREACH_SAFE (item, &gpio_isr_info_list, entries, tmp)
{
tmp_info = &item->gpio_info;
ret |= gpio_isr_deinit (tmp_info->gpio_num);
STAILQ_REMOVE (&gpio_isr_info_list, item, gpio_info_node, entries);
audio_free (item);
}
return ret;
}
esp_err_t
periph_gpio_isr_add (gpio_isr_info_t *gpio_info)
{
AUDIO_NULL_CHECK (TAG, gpio_info, return ESP_FAIL);
gpio_isr_node_t *tmp_node = NULL;
gpio_isr_info_t *tmp_info = NULL;
STAILQ_FOREACH (tmp_node, &gpio_isr_info_list, entries)
{
tmp_info = &tmp_node->gpio_info;
if (tmp_info->gpio_num == gpio_info->gpio_num)
{
ESP_LOGW (TAG, "The gpio has already registered isr");
return ESP_FAIL;
}
}
gpio_isr_node_t *gpio_isr_node
= (gpio_isr_node_t *)audio_calloc (1, sizeof (gpio_isr_node_t));
AUDIO_NULL_CHECK (TAG, gpio_isr_node, return ESP_FAIL);
memcpy (gpio_isr_node, gpio_info, sizeof (gpio_isr_info_t));
STAILQ_INSERT_TAIL (&gpio_isr_info_list, gpio_isr_node, entries);
return gpio_isr_init (gpio_info->gpio_num, gpio_info->type, gpio_isr_handler,
(void *)gpio_info->gpio_num);
}
esp_err_t
periph_gpio_isr_delete (int gpio_num)
{
esp_err_t ret = ESP_OK;
if (gpio_num < 0)
{
ESP_LOGW (TAG, "The gpio number should be greater than 0");
}
gpio_isr_node_t *tmp_node = NULL;
gpio_isr_info_t *tmp_info = NULL;
STAILQ_FOREACH (tmp_node, &gpio_isr_info_list, entries)
{
tmp_info = &tmp_node->gpio_info;
if (tmp_info->gpio_num == gpio_num)
{
STAILQ_REMOVE (&gpio_isr_info_list, tmp_node, gpio_info_node, entries);
ret |= gpio_isr_deinit (tmp_info->gpio_num);
audio_free (tmp_node);
return ret;
}
}
ESP_LOGW (TAG, "The gpio %d hasn't been registered", gpio_num);
return ESP_FAIL;
}
esp_periph_handle_t
periph_gpio_isr_init (periph_gpio_isr_cfg_t *isr_config)
{
esp_periph_handle_t periph
= esp_periph_create (PERIPH_ID_GPIO_ISR, "periph_gpio_isr");
AUDIO_NULL_CHECK (TAG, periph, return NULL);
STAILQ_INIT (&gpio_isr_info_list);
if (isr_config)
{
for (int i = 0; i < isr_config->info_size; i++)
{
gpio_isr_node_t *gpio_isr_node
= (gpio_isr_node_t *)audio_calloc (1, sizeof (gpio_isr_node_t));
AUDIO_NULL_CHECK (TAG, gpio_isr_node, {
audio_free (periph);
return NULL;
});
memcpy (gpio_isr_node, &isr_config->gpio_isr_info[i],
sizeof (gpio_isr_info_t));
STAILQ_INSERT_TAIL (&gpio_isr_info_list, gpio_isr_node, entries);
}
}
esp_periph_set_data (periph, &gpio_isr_info_list);
esp_periph_set_function (periph, _gpio_isr_init, _gpio_isr_run,
_gpio_isr_destory);
g_handle = periph;
return periph;
}

View File

@@ -0,0 +1,534 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "periph_is31fl3216.h"
#include "IS31FL3216.h"
#include "audio_mem.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include <string.h>
#define IS31FL3216_TASK_STACK_SIZE (2048 + 1024)
#define IS31FL3216_TASK_PRIORITY 3
#define ONE_FRAME_BYTE_SIZE 18
#define DEFAULT_FLASH_STEP 2
static const char *TAG = "PERIPH_IS31";
static const int DESTROY_BIT = BIT0;
#define VALIDATE_IS31FL3216(periph, ret) \
if (!(periph && esp_periph_get_id (periph) == PERIPH_ID_IS31FL3216)) \
{ \
ESP_LOGE (TAG, "Invalid is31fl3216 periph, at line %d", __LINE__); \
return ret; \
}
static const uint8_t light_audio_frames[8][ONE_FRAME_BYTE_SIZE] = {
{ 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff },
{ 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0xff, 0xff },
{ 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0xff, 0xff, 0xff },
{ 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xff, 0xff, 0xff },
{ 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xff, 0xFF, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
};
typedef enum
{
PERIPH_IS31_CMD_CHG_STATE,
PERIPH_IS31_CMD_QUIT,
} periph_is31_cmd_t;
typedef struct
{
uint16_t max_light_num; // Maximum light number
uint16_t light_num; // Working lights number
uint16_t light_mask; // Light bits mask
int interval_time; // Interval working time
uint16_t act_time; // Action times
uint8_t duty_step; // Duty step
periph_is31_shift_mode_t shift_mode; // Shift mode step
} periph_is31_arg_t;
typedef struct
{
periph_is31_arg_t *arg;
uint8_t duty[IS31FL3216_CH_NUM]; // Duty of lights
is31fl3216_handle_t handle;
periph_is31fl3216_state_t cur_state;
QueueHandle_t evt;
EventGroupHandle_t g_event_bit;
} periph_is31fl3216_t;
typedef struct
{
periph_is31_cmd_t type;
uint32_t data;
} periph_is31_msg_t;
static esp_err_t
is31_leds_ctrl (is31fl3216_handle_t *handle, uint16_t mask)
{
esp_err_t ret = ESP_OK;
for (int i = 0; i < IS31FL3216_CH_NUM; i++)
{
if (mask & (1UL << i))
{
ret |= is31fl3216_ch_enable (handle, 1UL << i);
}
else
{
ret |= is31fl3216_ch_disable (handle, 1UL << i);
}
}
return ret;
}
static esp_err_t
is31_leds_duty (is31fl3216_handle_t *handle, int duty, uint16_t mask)
{
esp_err_t ret = ESP_OK;
for (int i = 0; i < IS31FL3216_CH_NUM; i++)
{
if (mask & (1UL << i))
ret |= is31fl3216_ch_duty_set (handle, 1UL << i, duty);
}
return ret;
}
static void
is31_evt_send (void *que, periph_is31_cmd_t type, uint32_t data, int dir)
{
periph_is31_msg_t evt = { 0 };
evt.type = type;
evt.data = data;
if (dir)
{
xQueueSendToFront (que, &evt, 0);
}
else
{
xQueueSend (que, &evt, 0);
}
}
static esp_err_t
is31_change_state (periph_is31fl3216_t *is31, int state,
periph_is31_arg_t *arg)
{
esp_err_t ret = ESP_OK;
switch (state)
{
case IS31FL3216_STATE_OFF:
ret |= is31fl3216_ch_disable (is31->handle, arg->light_mask);
arg->interval_time = portMAX_DELAY;
is31->cur_state = IS31FL3216_STATE_OFF;
break;
case IS31FL3216_STATE_ON:
if (is31->cur_state == IS31FL3216_STATE_BY_AUDIO)
{
ret |= is31fl3216_work_mode_set (is31->handle, IS31FL3216_MODE_PWM);
is31_leds_duty (is31->handle, IS31FL3216_DUTY_MAX, arg->light_mask);
}
is31_leds_ctrl (is31->handle, arg->light_mask);
arg->interval_time = portMAX_DELAY;
is31->cur_state = IS31FL3216_STATE_ON;
break;
case IS31FL3216_STATE_FLASH:
if (is31->cur_state == IS31FL3216_STATE_BY_AUDIO)
{
ret |= is31fl3216_work_mode_set (is31->handle, IS31FL3216_MODE_PWM);
}
is31->cur_state = IS31FL3216_STATE_FLASH;
break;
case IS31FL3216_STATE_SHIFT:
if (is31->cur_state == IS31FL3216_STATE_BY_AUDIO)
{
ret |= is31fl3216_work_mode_set (is31->handle, IS31FL3216_MODE_PWM);
}
is31->cur_state = IS31FL3216_STATE_SHIFT;
break;
case IS31FL3216_STATE_BY_AUDIO:
is31fl3216_reset (is31->handle);
is31fl3216_work_mode_set (is31->handle, IS31FL3216_MODE_FRAME);
is31fl3216_sample_rate_set (is31->handle, 0xB4); // Set adc sample rate
is31fl3216_frame_value_set (is31->handle, 1,
(uint8_t *)&light_audio_frames,
sizeof (light_audio_frames));
is31fl3216_first_frame_set (is31->handle, 0);
is31->cur_state = IS31FL3216_STATE_BY_AUDIO;
arg->interval_time = portMAX_DELAY;
break;
default:
ESP_LOGE (TAG, "State %d is not supported", state);
break;
}
return ret;
}
static void
is31fl3216_run_task (void *Para)
{
esp_periph_handle_t periph = (esp_periph_handle_t)Para;
periph_is31fl3216_t *is31 = esp_periph_get_data (periph);
periph_is31_arg_t is31_arg = {
.max_light_num = IS31FL3216_CH_NUM,
.light_num = 1,
.light_mask = 1,
.interval_time = 1000,
.act_time = 0,
.duty_step = DEFAULT_FLASH_STEP,
.shift_mode = 0,
};
periph_is31_msg_t msg = { 0 };
int wait_time_ms = portMAX_DELAY;
bool task_run = true;
xEventGroupClearBits (is31->g_event_bit, DESTROY_BIT);
int cur_duty = 0;
int sig = 2;
int cur_bits_mask = 0;
int i = 0;
uint16_t act_times = 0;
while (task_run)
{
if (xQueueReceive (is31->evt, &msg, (wait_time_ms / portTICK_PERIOD_MS)))
{
ESP_LOGD (TAG, "cmd:%d, data:%d", msg.type, msg.data);
switch (msg.type)
{
case PERIPH_IS31_CMD_CHG_STATE:
memcpy (&is31_arg, is31->arg, sizeof (periph_is31_arg_t));
wait_time_ms = is31->arg->interval_time;
memset (is31->arg, 0, sizeof (periph_is31_arg_t));
is31->arg->interval_time = portMAX_DELAY;
is31->arg->max_light_num = IS31FL3216_CH_NUM;
is31->arg->duty_step = DEFAULT_FLASH_STEP;
is31_change_state (is31, msg.data, &is31_arg);
if (IS31FL3216_STATE_FLASH == msg.data)
{
sig = is31_arg.duty_step;
}
if (is31_arg.act_time && wait_time_ms)
{
act_times = is31_arg.act_time / wait_time_ms;
}
else
{
act_times = 0;
}
break;
case PERIPH_IS31_CMD_QUIT:
task_run = false;
if (is31->g_event_bit)
{
xEventGroupSetBits (is31->g_event_bit, DESTROY_BIT);
}
break;
default:
break;
}
if (task_run == false)
{
ESP_LOGW (TAG, "Quit is31fl3216 task ...");
break;
}
}
switch (is31->cur_state)
{
case IS31FL3216_STATE_FLASH:
{
is31_leds_duty (is31->handle, cur_duty, is31_arg.light_mask);
is31_leds_ctrl (is31->handle, is31_arg.light_mask);
cur_duty += sig;
if (cur_duty > IS31FL3216_DUTY_MAX)
{
cur_duty = IS31FL3216_DUTY_MAX;
sig = -(is31_arg.duty_step);
}
if (cur_duty < 0)
{
cur_duty = 0;
sig = (is31_arg.duty_step);
}
}
if (is31_arg.act_time == 0)
{
act_times = 0;
break;
}
act_times--;
if (act_times == 0)
{
wait_time_ms = portMAX_DELAY;
is31->cur_state = IS31FL3216_STATE_UNKNOWN;
is31_leds_ctrl (is31->handle, 0);
}
break;
case IS31FL3216_STATE_SHIFT:
if (is31_arg.shift_mode == PERIPH_IS31_SHIFT_MODE_SINGLE)
{
cur_bits_mask = ((1UL << is31_arg.light_num) - 1) << (i++);
if (i == (is31_arg.max_light_num - is31_arg.light_num + 1))
{
i = 0;
}
}
else if (is31_arg.shift_mode == PERIPH_IS31_SHIFT_MODE_ACC)
{
cur_bits_mask = (1UL << (is31_arg.light_num * ((i++) + 1))) - 1;
if ((cur_bits_mask >> is31_arg.max_light_num) & 0x01)
{
cur_bits_mask = 0;
i = 0;
}
}
is31_leds_duty (is31->handle, IS31FL3216_DUTY_MAX, cur_bits_mask);
is31_leds_ctrl (is31->handle, cur_bits_mask);
ESP_LOGD (TAG, "Mask:%08x, %d", cur_bits_mask, wait_time_ms);
if (is31_arg.act_time == 0)
{
act_times = 0;
break;
}
act_times--;
if (act_times == 0)
{
wait_time_ms = portMAX_DELAY;
is31->cur_state = IS31FL3216_STATE_UNKNOWN;
is31_leds_ctrl (is31->handle, 0);
}
break;
default:
break;
}
}
vTaskDelete (NULL);
}
esp_err_t
periph_is31fl3216_set_state (esp_periph_handle_t periph,
periph_is31fl3216_state_t state)
{
periph_is31fl3216_t *is31fl3216 = esp_periph_get_data (periph);
is31_evt_send (is31fl3216->evt, PERIPH_IS31_CMD_CHG_STATE, state, 0);
return ESP_OK;
}
esp_err_t
periph_is31fl3216_set_blink_pattern (esp_periph_handle_t periph,
uint16_t blink_pattern)
{
periph_is31fl3216_t *is31fl3216 = esp_periph_get_data (periph);
is31fl3216->arg->light_mask = blink_pattern;
return ESP_OK;
}
esp_err_t
periph_is31fl3216_set_duty (esp_periph_handle_t periph, uint8_t index,
uint8_t value)
{
periph_is31fl3216_t *is31fl3216 = esp_periph_get_data (periph);
is31fl3216->duty[index] = value;
is31fl3216_ch_duty_set (is31fl3216->handle, 1UL << index,
is31fl3216->duty[index]);
return ESP_OK;
}
esp_err_t
periph_is31fl3216_set_duty_step (esp_periph_handle_t periph, uint8_t step)
{
periph_is31fl3216_t *is31fl3216 = esp_periph_get_data (periph);
is31fl3216->arg->duty_step = step;
return ESP_OK;
}
esp_err_t
periph_is31fl3216_set_interval (esp_periph_handle_t periph,
uint16_t interval_ms)
{
periph_is31fl3216_t *is31fl3216 = esp_periph_get_data (periph);
is31fl3216->arg->interval_time = interval_ms;
return ESP_OK;
}
esp_err_t
periph_is31fl3216_set_shift_mode (esp_periph_handle_t periph,
periph_is31_shift_mode_t mode)
{
periph_is31fl3216_t *is31fl3216 = esp_periph_get_data (periph);
is31fl3216->arg->shift_mode = mode;
return ESP_OK;
}
esp_err_t
periph_is31fl3216_set_light_on_num (esp_periph_handle_t periph,
uint16_t light_on_num,
uint16_t max_light_num)
{
periph_is31fl3216_t *is31fl3216 = esp_periph_get_data (periph);
is31fl3216->arg->max_light_num = max_light_num;
is31fl3216->arg->light_num = light_on_num;
return ESP_OK;
}
esp_err_t
periph_is31fl3216_set_act_time (esp_periph_handle_t periph, uint16_t act_ms)
{
periph_is31fl3216_t *is31fl3216 = esp_periph_get_data (periph);
is31fl3216->arg->act_time = act_ms;
return ESP_OK;
}
static esp_err_t
_is31fl3216_init (esp_periph_handle_t self)
{
periph_is31fl3216_t *is31fl3216 = esp_periph_get_data (self);
esp_err_t ret = ESP_OK;
is31fl3216_ch_disable (is31fl3216->handle, IS31FL3216_CH_ALL);
is31_leds_duty (is31fl3216->handle, 0, IS31FL3216_CH_ALL);
xTaskCreate (is31fl3216_run_task, "is31fl3216_run_task",
IS31FL3216_TASK_STACK_SIZE, (void *)self,
IS31FL3216_TASK_PRIORITY, NULL);
if (ret)
{
ESP_LOGE (TAG, "Failed to initialize is31fl3216");
return ESP_FAIL;
}
return ESP_OK;
}
static esp_err_t
_is31fl3216_destroy (esp_periph_handle_t self)
{
VALIDATE_IS31FL3216 (self, ESP_FAIL);
periph_is31fl3216_t *is31fl3216 = esp_periph_get_data (self);
is31_evt_send (is31fl3216->evt, PERIPH_IS31_CMD_QUIT, 0, 0);
if (is31fl3216->g_event_bit)
{
xEventGroupWaitBits (is31fl3216->g_event_bit, DESTROY_BIT, pdTRUE,
pdFALSE, portMAX_DELAY);
vEventGroupDelete (is31fl3216->g_event_bit);
is31fl3216->g_event_bit = NULL;
}
esp_err_t ret = ESP_OK;
ret |= is31fl3216_ch_disable (is31fl3216->handle, IS31FL3216_CH_ALL);
ret |= is31fl3216_deinit (is31fl3216->handle);
audio_free (is31fl3216->arg);
vQueueDelete (is31fl3216->evt);
audio_free (is31fl3216);
if (ret)
{
ESP_LOGE (TAG, "Error occurred when stopping the is31fl3216");
return ESP_FAIL;
}
return ESP_OK;
}
esp_periph_handle_t
periph_is31fl3216_init (periph_is31fl3216_cfg_t *is31fl3216_config)
{
esp_periph_handle_t periph
= esp_periph_create (PERIPH_ID_IS31FL3216, "periph_is31fl3216");
AUDIO_MEM_CHECK (TAG, periph, return NULL);
periph_is31fl3216_t *is31fl3216
= audio_calloc (1, sizeof (periph_is31fl3216_t));
AUDIO_MEM_CHECK (TAG, is31fl3216, {
audio_free (periph);
return NULL;
});
is31fl3216->g_event_bit = xEventGroupCreate ();
AUDIO_NULL_CHECK (TAG, is31fl3216->g_event_bit, {
audio_free (periph);
audio_free (is31fl3216);
});
is31fl3216->evt = xQueueCreate (2, sizeof (periph_is31_msg_t));
AUDIO_MEM_CHECK (TAG, is31fl3216->evt, {
audio_free (periph);
vEventGroupDelete (is31fl3216->g_event_bit);
audio_free (is31fl3216);
return NULL;
});
is31fl3216->arg = audio_calloc (1, sizeof (periph_is31_arg_t));
AUDIO_MEM_CHECK (TAG, is31fl3216->arg, {
vQueueDelete (is31fl3216->evt);
vEventGroupDelete (is31fl3216->g_event_bit);
audio_free (periph);
audio_free (is31fl3216);
return NULL;
});
is31fl3216->arg->max_light_num = IS31FL3216_CH_NUM;
is31fl3216->arg->light_num = 0;
is31fl3216->arg->light_mask = 0;
is31fl3216->arg->interval_time = 1000;
is31fl3216->arg->act_time = 0;
is31fl3216->arg->duty_step = DEFAULT_FLASH_STEP;
is31fl3216->arg->shift_mode = PERIPH_IS31_SHIFT_MODE_ACC;
if (is31fl3216_config->duty == NULL)
{
ESP_LOGW (TAG, "The duty array is NULL");
}
else
{
for (int i = 0; i < IS31FL3216_CH_NUM; i++)
{
is31fl3216->duty[i] = is31fl3216_config->duty[i];
}
}
is31fl3216->handle = is31fl3216_init ();
AUDIO_MEM_CHECK (TAG, is31fl3216, {
audio_free (is31fl3216->arg);
vQueueDelete (is31fl3216->evt);
audio_free (periph);
vEventGroupDelete (is31fl3216->g_event_bit);
audio_free (is31fl3216);
return NULL;
});
esp_periph_set_data (periph, is31fl3216);
esp_periph_set_function (periph, _is31fl3216_init, NULL,
_is31fl3216_destroy);
return periph;
}

View File

@@ -0,0 +1,298 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "periph_led.h"
#include "audio_mem.h"
#include "audio_mutex.h"
#include "audio_sys.h"
#include "esp_log.h"
#include "esp_peripherals.h"
#include <math.h>
#include <string.h>
#define MAX_LED_CHANNEL (8)
static const char *TAG = "PERIPH_LED";
#define VALIDATE_LED(periph, ret) \
if (!(periph && esp_periph_get_id (periph) == PERIPH_ID_LED)) \
{ \
ESP_LOGE (TAG, "Invalid LED periph, at line %d", __LINE__); \
return ret; \
}
typedef struct
{
int index;
int pin;
int high_level_ms;
int low_level_ms;
long long tick;
int loop;
bool is_high_level;
bool fade;
bool stop;
int level;
} periph_led_channel_t;
typedef struct periph_led
{
ledc_mode_t led_speed_mode;
ledc_timer_bit_t led_duty_resolution;
ledc_timer_t led_timer_num;
uint32_t led_freq_hz;
QueueHandle_t led_mutex;
periph_led_channel_t channels[MAX_LED_CHANNEL];
} periph_led_t;
static esp_err_t
_led_run (esp_periph_handle_t self, audio_event_iface_msg_t *msg)
{
return ESP_OK;
}
static esp_err_t
_led_init (esp_periph_handle_t self)
{
VALIDATE_LED (self, ESP_FAIL);
periph_led_t *periph_led = esp_periph_get_data (self);
ledc_timer_config_t ledc_timer = {
.duty_resolution
= periph_led->led_duty_resolution, // resolution of PWM duty
.freq_hz = periph_led->led_freq_hz, // frequency of PWM signal
.speed_mode = periph_led->led_speed_mode, // timer mode
.timer_num = periph_led->led_timer_num // timer index
};
// Set configuration of timer0 for high speed channels
ledc_timer_config (&ledc_timer);
ledc_fade_func_install (0);
return ESP_OK;
}
static esp_err_t
_led_destroy (esp_periph_handle_t self)
{
periph_led_t *periph_led = esp_periph_get_data (self);
for (int i = 0; i < MAX_LED_CHANNEL; i++)
{
periph_led_channel_t *ch = &periph_led->channels[i];
if (ch->index > 0 && ch->pin > 0)
{
ledc_stop (periph_led->led_speed_mode, ch->index, ch->level);
}
}
esp_periph_stop_timer (self);
ledc_fade_func_uninstall ();
mutex_destroy (periph_led->led_mutex);
audio_free (periph_led);
return ESP_OK;
}
esp_periph_handle_t
periph_led_init (periph_led_cfg_t *config)
{
esp_periph_handle_t periph = esp_periph_create (PERIPH_ID_LED, "periph_led");
// check periph
periph_led_t *periph_led = audio_calloc (1, sizeof (periph_led_t));
// check periph_led
periph_led->led_speed_mode = config->led_speed_mode;
periph_led->led_duty_resolution = config->led_duty_resolution;
periph_led->led_timer_num = config->led_timer_num;
periph_led->led_freq_hz = config->led_freq_hz;
periph_led->led_mutex = mutex_create ();
if (periph_led->led_freq_hz == 0)
{
periph_led->led_freq_hz = 5000;
}
memset (&periph_led->channels, -1, sizeof (periph_led->channels));
esp_periph_set_data (periph, periph_led);
esp_periph_set_function (periph, _led_init, _led_run, _led_destroy);
return periph;
}
static periph_led_channel_t *
_find_led_channel (periph_led_t *periph_led, int gpio_num)
{
periph_led_channel_t *ch = NULL;
for (int i = 0; i < MAX_LED_CHANNEL; i++)
{
if (periph_led->channels[i].pin == gpio_num)
{
ch = &periph_led->channels[i];
ch->index = i;
break;
}
else if (periph_led->channels[i].pin == -1)
{
ch = &periph_led->channels[i];
ch->index = i;
}
}
return ch;
}
static void
led_timer_handler (xTimerHandle tmr)
{
esp_periph_handle_t periph = (esp_periph_handle_t)pvTimerGetTimerID (tmr);
periph_led_t *periph_led = esp_periph_get_data (periph);
mutex_lock (periph_led->led_mutex);
for (int i = 0; i < MAX_LED_CHANNEL; i++)
{
periph_led_channel_t *ch = &periph_led->channels[i];
if (ch->pin < 0 || ch->stop == true)
{
continue;
}
if (ch->loop == 0)
{
ledc_stop (periph_led->led_speed_mode, ch->index, ch->level);
esp_periph_send_event (periph, PERIPH_LED_BLINK_FINISH,
(void *)ch->pin, 0);
ch->stop = true;
continue;
}
if (!ch->is_high_level
&& audio_sys_get_time_ms () - ch->tick > ch->low_level_ms)
{
if (ch->loop > 0)
{
ch->loop--;
}
// now, switch on
if (ch->fade)
{
ledc_set_fade_with_time (periph_led->led_speed_mode, ch->index,
pow (2, periph_led->led_duty_resolution)
- 1,
ch->high_level_ms);
ledc_fade_start (periph_led->led_speed_mode, ch->index,
LEDC_FADE_NO_WAIT);
}
else
{
ledc_set_duty (periph_led->led_speed_mode, ch->index,
pow (2, periph_led->led_duty_resolution) - 1);
ledc_update_duty (periph_led->led_speed_mode, ch->index);
}
if (ch->low_level_ms > 0)
{
ch->is_high_level = true;
}
ch->tick = audio_sys_get_time_ms ();
}
else if (ch->is_high_level
&& audio_sys_get_time_ms () - ch->tick > ch->high_level_ms)
{
if (ch->loop > 0)
{
ch->loop--;
}
// switch off
if (ch->fade)
{
ledc_set_fade_with_time (periph_led->led_speed_mode, ch->index,
0, ch->low_level_ms);
ledc_fade_start (periph_led->led_speed_mode, ch->index,
LEDC_FADE_NO_WAIT);
}
else
{
ledc_set_duty (periph_led->led_speed_mode, ch->index, 0);
ledc_update_duty (periph_led->led_speed_mode, ch->index);
}
if (ch->high_level_ms > 0)
{
ch->is_high_level = false;
}
ch->tick = audio_sys_get_time_ms ();
}
}
mutex_unlock (periph_led->led_mutex);
}
esp_err_t
periph_led_blink (esp_periph_handle_t periph, int gpio_num, int time_on_ms,
int time_off_ms, bool fade, int loop,
periph_led_idle_level_t level)
{
periph_led_t *periph_led = esp_periph_get_data (periph);
periph_led_channel_t *ch = _find_led_channel (periph_led, gpio_num);
if (ch == NULL)
{
return ESP_FAIL;
}
ledc_channel_config_t ledc_channel_cfg = {
.channel = ch->index,
.duty = 0,
.gpio_num = gpio_num,
.speed_mode = periph_led->led_speed_mode,
.timer_sel = periph_led->led_timer_num,
};
ledc_channel_config (&ledc_channel_cfg);
ch->pin = gpio_num;
ch->tick = audio_sys_get_time_ms ();
ch->loop = loop;
ch->fade = fade;
if (level == PERIPH_LED_IDLE_LEVEL_LOW)
{
ch->is_high_level = false;
ch->high_level_ms = time_on_ms;
ch->low_level_ms = time_off_ms;
}
else
{
ch->is_high_level = true;
ch->high_level_ms = time_off_ms;
ch->low_level_ms = time_on_ms;
}
ch->stop = false;
ch->level = level;
esp_periph_start_timer (periph, portTICK_RATE_MS, led_timer_handler);
return ESP_OK;
}
esp_err_t
periph_led_stop (esp_periph_handle_t periph, int gpio_num)
{
periph_led_t *periph_led = esp_periph_get_data (periph);
periph_led_channel_t *ch = _find_led_channel (periph_led, gpio_num);
if (ch && (ch->pin < 0 || ch->index < 0))
{
return ESP_OK;
}
mutex_lock (periph_led->led_mutex);
ch->stop = true;
ledc_stop (periph_led->led_speed_mode, ch->index, ch->level);
mutex_unlock (periph_led->led_mutex);
return ESP_OK;
}

View File

@@ -0,0 +1,230 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "periph_sdcard.h"
#include "audio_mem.h"
#include "driver/gpio.h"
#include "driver/sdmmc_defs.h"
#include "driver/sdmmc_host.h"
#include "esp_log.h"
#include "sdcard.h"
static const char *TAG = "PERIPH_SDCARD";
#define SDCARD_CHECK_TIMEOUT_MS (20)
#define VALIDATE_SDCARD(periph, ret) \
if (!(periph && esp_periph_get_id (periph) == PERIPH_ID_SDCARD)) \
{ \
ESP_LOGE (TAG, "Invalid SDCARD periph, at line %d", __LINE__); \
return ret; \
}
#define tick_get periph_tick_get
static esp_err_t periph_sdcard_mount (esp_periph_handle_t periph);
static esp_err_t periph_sdcard_unmount (esp_periph_handle_t periph);
typedef struct
{
char *root;
int card_detect_pin;
bool is_mounted;
long long last_detect_time;
periph_sdcard_mode_t sd_mode;
} periph_sdcard_t;
static void IRAM_ATTR
sdcard_gpio_intr_handler (void *param)
{
esp_periph_handle_t periph = (esp_periph_handle_t)param;
periph_sdcard_t *sdcard = esp_periph_get_data (periph);
if (sdcard_is_exist () && !sdcard->is_mounted)
{
esp_periph_send_cmd_from_isr (periph, SDCARD_STATUS_CARD_DETECT_CHANGE,
NULL, 0);
}
else if (!sdcard_is_exist () && sdcard->is_mounted)
{
esp_periph_send_cmd_from_isr (periph, SDCARD_STATUS_CARD_DETECT_CHANGE,
NULL, 0);
}
}
static esp_err_t
_sdcard_run (esp_periph_handle_t self, audio_event_iface_msg_t *msg)
{
if (msg->cmd != SDCARD_STATUS_CARD_DETECT_CHANGE)
{
return ESP_OK;
}
periph_sdcard_t *sdcard = esp_periph_get_data (self);
if (sdcard_is_exist () && !sdcard->is_mounted)
{
periph_sdcard_mount (self);
}
else if (!sdcard_is_exist () && sdcard->is_mounted)
{
periph_sdcard_unmount (self);
}
return ESP_OK;
}
static void
sdcard_timer_handler (xTimerHandle tmr)
{
esp_periph_handle_t periph = (esp_periph_handle_t)pvTimerGetTimerID (tmr);
esp_periph_send_cmd (periph, SDCARD_STATUS_CARD_DETECT_CHANGE, NULL, 0);
}
static esp_err_t
_sdcard_init (esp_periph_handle_t self)
{
periph_sdcard_t *sdcard = esp_periph_get_data (self);
esp_err_t ret
= sdcard_init (sdcard->card_detect_pin, sdcard_gpio_intr_handler, self);
if (sdcard_is_exist ())
{
ret |= periph_sdcard_mount (self);
}
else
{
ESP_LOGE (TAG, "no sdcard detect");
}
esp_periph_start_timer (self, 1000 / portTICK_RATE_MS, sdcard_timer_handler);
return ESP_OK;
}
static esp_err_t
_sdcard_destroy (esp_periph_handle_t self)
{
VALIDATE_SDCARD (self, ESP_FAIL);
esp_err_t ret = ESP_OK;
ret |= sdcard_unmount ();
ret |= sdcard_destroy ();
if (ret != ESP_OK)
{
ESP_LOGE (TAG, "stop sdcard error!");
}
periph_sdcard_t *sdcard = esp_periph_get_data (self);
audio_free (sdcard->root);
audio_free (sdcard);
return ret;
}
esp_err_t
periph_sdcard_mount (esp_periph_handle_t periph)
{
VALIDATE_SDCARD (periph, ESP_FAIL);
periph_sdcard_t *sdcard = esp_periph_get_data (periph);
int ret = sdcard_mount (sdcard->root, sdcard->sd_mode);
if (ret == ESP_OK)
{
ESP_LOGD (TAG, "Mount SDCARD success");
sdcard->is_mounted = true;
return esp_periph_send_event (periph, SDCARD_STATUS_MOUNTED, NULL, 0);
}
else if (ret == ESP_ERR_INVALID_STATE)
{
ESP_LOGD (TAG, "periph sdcard handle already mounted!");
return ESP_OK;
}
else
{
esp_periph_send_event (periph, SDCARD_STATUS_MOUNT_ERROR, NULL, 0);
sdcard->is_mounted = false;
ESP_LOGE (TAG, "mount sdcard error!");
return ESP_FAIL;
}
}
esp_err_t
periph_sdcard_unmount (esp_periph_handle_t periph)
{
VALIDATE_SDCARD (periph, ESP_FAIL);
periph_sdcard_t *sdcard = esp_periph_get_data (periph);
int ret = sdcard_unmount ();
if (ret == ESP_OK)
{
ESP_LOGD (TAG, "UnMount SDCARD success");
sdcard->is_mounted = false;
return esp_periph_send_event (periph, SDCARD_STATUS_UNMOUNTED, NULL, 0);
}
else
{
esp_periph_send_event (periph, SDCARD_STATUS_UNMOUNT_ERROR, NULL, 0);
ESP_LOGE (TAG, "unmount sdcard error!");
sdcard->is_mounted = false;
return ESP_FAIL;
}
return ESP_OK;
}
esp_periph_handle_t
periph_sdcard_init (periph_sdcard_cfg_t *sdcard_cfg)
{
esp_periph_handle_t periph
= esp_periph_create (PERIPH_ID_SDCARD, "periph_sdcard");
AUDIO_MEM_CHECK (TAG, periph, return NULL);
periph_sdcard_t *sdcard = audio_calloc (1, sizeof (periph_sdcard_t));
AUDIO_MEM_CHECK (TAG, sdcard, {
audio_free (periph);
return NULL;
});
if (sdcard_cfg->root)
{
sdcard->root = audio_strdup (sdcard_cfg->root);
}
else
{
sdcard->root = audio_strdup ("/sdcard");
}
AUDIO_MEM_CHECK (TAG, sdcard->root, {
audio_free (sdcard);
audio_free (periph);
return NULL;
});
sdcard->card_detect_pin = sdcard_cfg->card_detect_pin;
sdcard->sd_mode = sdcard_cfg->mode;
esp_periph_set_data (periph, sdcard);
esp_periph_set_function (periph, _sdcard_init, _sdcard_run, _sdcard_destroy);
return periph;
}
bool
periph_sdcard_is_mounted (esp_periph_handle_t periph)
{
VALIDATE_SDCARD (periph, ESP_FAIL);
periph_sdcard_t *sdcard = esp_periph_get_data (periph);
return sdcard->is_mounted;
}

View File

@@ -0,0 +1,236 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "periph_spiffs.h"
#include "audio_mem.h"
#include "esp_log.h"
#include "esp_spiffs.h"
static const char *TAG = "PERIPH_SPIFFS";
#define VALIDATE_SPIFFS(periph, ret) \
if (!(periph && esp_periph_get_id (periph) == PERIPH_ID_SPIFFS)) \
{ \
ESP_LOGE (TAG, "Invalid SPIFFS periph, at line %d", __LINE__); \
return ret; \
}
#define SPIFFS_DEFAULT_MAX_FILES 5
static esp_err_t periph_spiffs_mount (esp_periph_handle_t periph);
static esp_err_t periph_spiffs_unmount (esp_periph_handle_t periph);
typedef struct
{
char *root;
char *partition_label;
size_t max_files;
bool format_if_mount_failed;
bool is_mounted;
} periph_spiffs_t;
static esp_err_t
_spiffs_run (esp_periph_handle_t self, audio_event_iface_msg_t *msg)
{
return ESP_OK;
}
static esp_err_t
_spiffs_init (esp_periph_handle_t self)
{
return periph_spiffs_mount (self);
;
}
static esp_err_t
_spiffs_destroy (esp_periph_handle_t self)
{
VALIDATE_SPIFFS (self, ESP_FAIL);
esp_err_t ret = ESP_OK;
ret |= periph_spiffs_unmount (self);
if (ret != ESP_OK)
{
ESP_LOGE (TAG, "Failed to unmount SPIFFS");
}
periph_spiffs_t *spiffs = esp_periph_get_data (self);
audio_free (spiffs->root);
if (spiffs->partition_label != NULL)
{
audio_free (spiffs->partition_label);
}
audio_free (spiffs);
return ret;
}
esp_err_t
periph_spiffs_mount (esp_periph_handle_t periph)
{
VALIDATE_SPIFFS (periph, ESP_FAIL);
periph_spiffs_t *spiffs = esp_periph_get_data (periph);
esp_vfs_spiffs_conf_t conf
= { .base_path = spiffs->root,
.partition_label = spiffs->partition_label,
.max_files = spiffs->max_files,
.format_if_mount_failed = spiffs->format_if_mount_failed };
// Use settings defined above to initialize and mount SPIFFS filesystem.
// Note: esp_vfs_spiffs_register is an all-in-one convenience function.
esp_err_t ret = esp_vfs_spiffs_register (&conf);
if (ret != ESP_OK)
{
if (ret == ESP_FAIL)
{
ESP_LOGE (TAG, "Failed to mount or format filesystem");
}
else if (ret == ESP_ERR_NOT_FOUND)
{
printf ("root %s ", spiffs->root);
ESP_LOGE (TAG, "Failed to find SPIFFS partition");
}
else
{
ESP_LOGE (TAG, "Failed to initialize SPIFFS (%d)", ret);
}
return ESP_FAIL;
}
if (ret == ESP_OK)
{
ESP_LOGD (TAG, "Mount SPIFFS success");
spiffs->is_mounted = true;
size_t total = 0, used = 0;
ret = esp_spiffs_info (NULL, &total, &used);
if (ret != ESP_OK)
{
ESP_LOGE (TAG, "Failed to get SPIFFS partition information (%d)",
ret);
}
else
{
ESP_LOGI (TAG, "Partition size: total: %d, used: %d", total, used);
}
return esp_periph_send_event (periph, SPIFFS_STATUS_MOUNTED, NULL, 0);
}
else if (ret == ESP_ERR_INVALID_STATE)
{
ESP_LOGD (TAG, "Periph SPIFFS handle already mounted!");
return ESP_OK;
}
else
{
esp_periph_send_event (periph, SPIFFS_STATUS_MOUNT_ERROR, NULL, 0);
spiffs->is_mounted = false;
ESP_LOGE (TAG, "Mount SPIFFS error!");
return ESP_FAIL;
}
}
esp_err_t
periph_spiffs_unmount (esp_periph_handle_t periph)
{
VALIDATE_SPIFFS (periph, ESP_FAIL);
periph_spiffs_t *spiffs = esp_periph_get_data (periph);
int ret = esp_vfs_spiffs_unregister (spiffs->partition_label);
if (ret == ESP_OK)
{
ESP_LOGD (TAG, "Unmount SPIFFS success");
spiffs->is_mounted = false;
return esp_periph_send_event (periph, SPIFFS_STATUS_UNMOUNTED, NULL, 0);
}
else
{
esp_periph_send_event (periph, SPIFFS_STATUS_UNMOUNT_ERROR, NULL, 0);
ESP_LOGE (TAG, "Unmount SPIFFS error!");
spiffs->is_mounted = false;
return ESP_FAIL;
}
return ESP_OK;
}
esp_periph_handle_t
periph_spiffs_init (periph_spiffs_cfg_t *spiffs_cfg)
{
esp_periph_handle_t periph
= esp_periph_create (PERIPH_ID_SPIFFS, "periph_spiffs");
AUDIO_MEM_CHECK (TAG, periph, return NULL);
periph_spiffs_t *spiffs = audio_calloc (1, sizeof (periph_spiffs_t));
AUDIO_MEM_CHECK (TAG, spiffs, {
audio_free (periph);
return NULL;
});
if (spiffs_cfg->root)
{
spiffs->root = audio_strdup (spiffs_cfg->root);
}
else
{
spiffs->root = audio_strdup ("/spiffs");
}
if (spiffs_cfg->partition_label)
{
spiffs->partition_label = audio_strdup (spiffs_cfg->partition_label);
}
else
{
spiffs->partition_label = NULL;
}
if (spiffs_cfg->max_files < SPIFFS_DEFAULT_MAX_FILES)
{
spiffs->max_files = SPIFFS_DEFAULT_MAX_FILES;
}
else
{
spiffs->max_files = spiffs_cfg->max_files;
}
spiffs->format_if_mount_failed = spiffs_cfg->format_if_mount_failed;
AUDIO_MEM_CHECK (TAG, spiffs->root, {
audio_free (spiffs);
audio_free (periph);
return NULL;
});
esp_periph_set_data (periph, spiffs);
esp_periph_set_function (periph, _spiffs_init, _spiffs_run, _spiffs_destroy);
return periph;
}
bool
periph_spiffs_is_mounted (esp_periph_handle_t periph)
{
VALIDATE_SPIFFS (periph, ESP_FAIL);
periph_spiffs_t *spiffs = esp_periph_get_data (periph);
return spiffs->is_mounted;
}

View File

@@ -0,0 +1,145 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "periph_touch.h"
#include "audio_mem.h"
#include "esp_log.h"
#include "esp_peripherals.h"
#include "touch.h"
static const char *TAG = "PERIPH_TOUCH";
#define VALIDATE_TOUCH(periph, ret) \
if (!(periph && esp_periph_get_id (periph) == PERIPH_ID_TOUCH)) \
{ \
ESP_LOGE (TAG, "Invalid TOUCH periph, at line %d", __LINE__); \
return ret; \
}
typedef struct periph_touch
{
esp_touch_handle_t touch;
int touch_mask;
int long_tap_time_ms;
int tap_threshold_percent;
touch_result_t result;
} periph_touch_t;
static void
touch_send_event (esp_periph_handle_t self, int event_id, int mask)
{
int touch_num = 0;
while (mask)
{
if (mask & 0x01)
{
esp_periph_send_event (self, event_id, (void *)touch_num, 0);
}
mask >>= 1;
touch_num++;
}
}
static esp_err_t
_touch_run (esp_periph_handle_t self, audio_event_iface_msg_t *msg)
{
periph_touch_t *periph_touch = esp_periph_get_data (self);
touch_send_event (self, PERIPH_TOUCH_TAP, periph_touch->result.tap_mask);
touch_send_event (self, PERIPH_TOUCH_RELEASE,
periph_touch->result.release_mask);
touch_send_event (self, PERIPH_TOUCH_LONG_TAP,
periph_touch->result.long_tap_mask);
touch_send_event (self, PERIPH_TOUCH_LONG_RELEASE,
periph_touch->result.long_release_mask);
return ESP_OK;
}
static void
touch_timer_handler (xTimerHandle tmr)
{
esp_periph_handle_t periph = (esp_periph_handle_t)pvTimerGetTimerID (tmr);
periph_touch_t *periph_touch = esp_periph_get_data (periph);
if (esp_touch_read (periph_touch->touch, &periph_touch->result))
{
ESP_LOGD (TAG,
"Touch event, tap %x, release_mask: %x, long_tap_mask: %x, "
"long_tap_mask: %x",
periph_touch->result.tap_mask,
periph_touch->result.release_mask,
periph_touch->result.long_tap_mask,
periph_touch->result.long_release_mask);
esp_periph_send_cmd (periph, 0, NULL, 0);
}
}
static esp_err_t
_touch_init (esp_periph_handle_t self)
{
VALIDATE_TOUCH (self, ESP_FAIL);
periph_touch_t *periph_touch = esp_periph_get_data (self);
touch_config_t touch_config = {
.touch_mask = periph_touch->touch_mask,
.long_tap_time_ms = periph_touch->long_tap_time_ms,
.tap_threshold_percent = periph_touch->tap_threshold_percent,
};
periph_touch->touch = esp_touch_init (&touch_config);
esp_periph_start_timer (self, 150 / portTICK_PERIOD_MS, touch_timer_handler);
ESP_LOGW (TAG, "_touch_init");
return ESP_OK;
}
static esp_err_t
_touch_destroy (esp_periph_handle_t self)
{
periph_touch_t *periph_touch = esp_periph_get_data (self);
esp_touch_destroy (periph_touch->touch);
audio_free (periph_touch);
return ESP_OK;
}
esp_periph_handle_t
periph_touch_init (periph_touch_cfg_t *config)
{
esp_periph_handle_t periph
= esp_periph_create (PERIPH_ID_TOUCH, "periph_touch");
AUDIO_MEM_CHECK (TAG, periph, return NULL);
periph_touch_t *periph_touch = audio_calloc (1, sizeof (periph_touch_t));
AUDIO_MEM_CHECK (TAG, periph_touch, {
audio_free (periph);
return NULL;
});
periph_touch->touch_mask = config->touch_mask;
periph_touch->long_tap_time_ms = config->long_tap_time_ms;
periph_touch->tap_threshold_percent = config->tap_threshold_percent;
esp_periph_set_data (periph, periph_touch);
esp_periph_set_function (periph, _touch_init, _touch_run, _touch_destroy);
return periph;
}

View File

@@ -0,0 +1,632 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in
* which case, it is free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "esp_event.h"
#include "esp_log.h"
#include "esp_smartconfig.h"
#include "esp_wifi.h"
#include "esp_wpa2.h"
#include <string.h>
#include "audio_mem.h"
#include "esp_peripherals.h"
#include "periph_wifi.h"
#include "wifibleconfig.h"
#if __has_include("esp_idf_version.h")
#include "esp_idf_version.h"
#else
#define ESP_IDF_VERSION_VAL(major, minor, patch) 1
#endif
static const char *TAG = "PERIPH_WIFI";
#define VALIDATE_WIFI(periph, ret) \
if (!(periph && esp_periph_get_id (periph) == PERIPH_ID_WIFI)) \
{ \
ESP_LOGE (TAG, "Invalid WIFI periph, at line %d", __LINE__); \
return ret; \
}
#define DEFAULT_RECONNECT_TIMEOUT_MS (1000)
/* Constants that aren't configurable in menuconfig */
#define EAP_PEAP 1
#define EAP_TTLS 2
typedef struct periph_wifi *periph_wifi_handle_t;
struct periph_wifi
{
periph_wifi_state_t wifi_state;
bool disable_auto_reconnect;
bool is_open;
uint8_t max_recon_time;
char *ssid;
char *password;
EventGroupHandle_t state_event;
int reconnect_timeout_ms;
periph_wifi_config_mode_t config_mode;
periph_wpa2_enterprise_cfg_t *wpa2_e_cfg;
};
static const int CONNECTED_BIT = BIT0;
static const int DISCONNECTED_BIT = BIT1;
static const int SMARTCONFIG_DONE_BIT = BIT2;
static const int SMARTCONFIG_ERROR_BIT = BIT3;
static esp_periph_handle_t g_periph = NULL;
esp_err_t
periph_wifi_wait_for_connected (esp_periph_handle_t periph,
TickType_t tick_to_wait)
{
VALIDATE_WIFI (periph, ESP_FAIL);
periph_wifi_handle_t periph_wifi
= (periph_wifi_handle_t)esp_periph_get_data (periph);
EventBits_t connected_bit = xEventGroupWaitBits (
periph_wifi->state_event, CONNECTED_BIT, false, true, tick_to_wait);
if (connected_bit & CONNECTED_BIT)
{
return ESP_OK;
}
#ifdef CONFIG_BLUEDROID_ENABLED
if (periph_wifi->config_mode == WIFI_CONFIG_BLUEFI)
{
ble_config_stop ();
}
#endif
return ESP_FAIL;
}
periph_wifi_state_t
periph_wifi_is_connected (esp_periph_handle_t periph)
{
VALIDATE_WIFI (periph, false);
periph_wifi_handle_t wifi
= (periph_wifi_handle_t)esp_periph_get_data (periph);
return wifi->wifi_state;
}
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
static void
_wifi_smartconfig_event_callback (void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
wifi_config_t sta_conf;
periph_wifi_handle_t periph_wifi
= (periph_wifi_handle_t)esp_periph_get_data (g_periph);
switch (event_id)
{
case SC_EVENT_SCAN_DONE:
ESP_LOGD (TAG, "SC_EVENT_SCAN_DONE");
break;
case SC_EVENT_FOUND_CHANNEL:
ESP_LOGD (TAG, "SC_EVENT_FOUND_CHANNEL");
break;
case SC_EVENT_GOT_SSID_PSWD:
ESP_LOGE (TAG, "SC_EVENT_GOT_SSID_PSWD");
smartconfig_event_got_ssid_pswd_t *evt
= (smartconfig_event_got_ssid_pswd_t *)event_data;
memset (&sta_conf, 0x00, sizeof (sta_conf));
memcpy (sta_conf.sta.ssid, evt->ssid, sizeof (sta_conf.sta.ssid));
memcpy (sta_conf.sta.password, evt->password,
sizeof (sta_conf.sta.password));
sta_conf.sta.bssid_set = evt->bssid_set;
if (sta_conf.sta.bssid_set == true)
{
memcpy (sta_conf.sta.bssid, evt->bssid, sizeof (sta_conf.sta.bssid));
}
ESP_LOGE (TAG, "SSID=%s, PASS=%s", sta_conf.sta.ssid,
sta_conf.sta.password);
esp_wifi_disconnect ();
if (esp_wifi_set_config (WIFI_IF_STA, &sta_conf) != ESP_OK)
{
periph_wifi->wifi_state = PERIPH_WIFI_CONFIG_ERROR;
xEventGroupSetBits (periph_wifi->state_event, SMARTCONFIG_ERROR_BIT);
}
if (esp_wifi_connect () != ESP_OK)
{
periph_wifi->wifi_state = PERIPH_WIFI_CONFIG_ERROR;
xEventGroupSetBits (periph_wifi->state_event, SMARTCONFIG_ERROR_BIT);
esp_periph_send_event (g_periph, PERIPH_WIFI_CONFIG_ERROR, NULL, 0);
break;
}
break;
case SC_EVENT_SEND_ACK_DONE:
ESP_LOGE (TAG, "SC_EVENT_SEND_ACK_DONE");
periph_wifi->wifi_state = PERIPH_WIFI_CONFIG_DONE;
esp_periph_send_event (g_periph, PERIPH_WIFI_CONFIG_DONE, NULL, 0);
xEventGroupSetBits (periph_wifi->state_event, SMARTCONFIG_DONE_BIT);
esp_smartconfig_stop ();
break;
}
}
#else
static void
_wifi_smartconfig_event_callback (smartconfig_status_t status, void *pdata)
{
wifi_config_t sta_conf;
smartconfig_type_t *type;
periph_wifi_handle_t periph_wifi
= (periph_wifi_handle_t)esp_periph_get_data (g_periph);
switch (status)
{
case SC_STATUS_WAIT:
ESP_LOGD (TAG, "SC_STATUS_WAIT");
break;
case SC_STATUS_FIND_CHANNEL:
ESP_LOGD (TAG, "SC_STATUS_FIND_CHANNEL");
break;
case SC_STATUS_GETTING_SSID_PSWD:
type = pdata;
ESP_LOGD (TAG, "SC_STATUS_GETTING_SSID_PSWD, SC_TYPE=%d", (int)*type);
break;
case SC_STATUS_LINK:
ESP_LOGE (TAG, "SC_STATUS_LINK");
memset (&sta_conf, 0x00, sizeof (sta_conf));
memcpy (&sta_conf.sta, pdata, sizeof (wifi_sta_config_t));
ESP_LOGE (TAG, "SSID=%s, PASS=%s", sta_conf.sta.ssid,
sta_conf.sta.password);
esp_wifi_disconnect ();
if (esp_wifi_set_config (WIFI_IF_STA, &sta_conf) != ESP_OK)
{
periph_wifi->wifi_state = PERIPH_WIFI_CONFIG_ERROR;
xEventGroupSetBits (periph_wifi->state_event, SMARTCONFIG_ERROR_BIT);
}
if (esp_wifi_connect () != ESP_OK)
{
periph_wifi->wifi_state = PERIPH_WIFI_CONFIG_ERROR;
xEventGroupSetBits (periph_wifi->state_event, SMARTCONFIG_ERROR_BIT);
esp_periph_send_event (g_periph, PERIPH_WIFI_CONFIG_ERROR, NULL, 0);
break;
}
break;
case SC_STATUS_LINK_OVER:
ESP_LOGE (TAG, "SC_STATUS_LINK_OVER");
if (pdata != NULL)
{
char phone_ip[4] = { 0 };
memcpy (phone_ip, (const void *)pdata, 4);
ESP_LOGD (TAG, "Phone ip: %d.%d.%d.%d", phone_ip[0], phone_ip[1],
phone_ip[2], phone_ip[3]);
periph_wifi->wifi_state = PERIPH_WIFI_CONFIG_DONE;
esp_periph_send_event (g_periph, PERIPH_WIFI_CONFIG_DONE, NULL, 0);
xEventGroupSetBits (periph_wifi->state_event, SMARTCONFIG_DONE_BIT);
}
else
{
periph_wifi->wifi_state = PERIPH_WIFI_CONFIG_ERROR;
esp_periph_send_event (g_periph, PERIPH_WIFI_CONFIG_ERROR, NULL, 0);
xEventGroupSetBits (periph_wifi->state_event, SMARTCONFIG_ERROR_BIT);
}
esp_smartconfig_stop ();
break;
}
}
#endif
esp_err_t
periph_wifi_wait_for_disconnected (esp_periph_handle_t periph,
TickType_t tick_to_wait)
{
VALIDATE_WIFI (periph, ESP_FAIL);
periph_wifi_handle_t periph_wifi
= (periph_wifi_handle_t)esp_periph_get_data (periph);
EventBits_t disconnected_bit = xEventGroupWaitBits (
periph_wifi->state_event, DISCONNECTED_BIT, false, true, tick_to_wait);
if (disconnected_bit & DISCONNECTED_BIT)
{
return ESP_OK;
}
return ESP_FAIL;
}
esp_err_t
periph_wifi_config_start (esp_periph_handle_t periph,
periph_wifi_config_mode_t mode)
{
VALIDATE_WIFI (periph, ESP_FAIL);
periph_wifi_handle_t periph_wifi
= (periph_wifi_handle_t)esp_periph_get_data (periph);
esp_err_t err = ESP_OK;
periph_wifi->disable_auto_reconnect = true;
periph_wifi->config_mode = mode;
esp_wifi_disconnect ();
if (periph_wifi_wait_for_disconnected (periph, portMAX_DELAY) != ESP_OK)
{
return ESP_FAIL;
}
periph_wifi->wifi_state = PERIPH_WIFI_SETTING;
if (mode >= WIFI_CONFIG_ESPTOUCH && mode <= WIFI_CONFIG_ESPTOUCH_AIRKISS)
{
err = ESP_OK; // 0;
// esp_wifi_start();
err |= esp_smartconfig_set_type (mode);
err |= esp_smartconfig_fast_mode (true);
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT ();
err |= esp_smartconfig_start (&cfg);
esp_event_handler_register (SC_EVENT, ESP_EVENT_ANY_ID,
&_wifi_smartconfig_event_callback, NULL);
#else
err |= esp_smartconfig_start (_wifi_smartconfig_event_callback, 0);
#endif
xEventGroupClearBits (periph_wifi->state_event, SMARTCONFIG_DONE_BIT);
xEventGroupClearBits (periph_wifi->state_event, SMARTCONFIG_ERROR_BIT);
}
else if (mode == WIFI_CONFIG_WPS)
{
// todo : add wps
return ESP_OK;
}
else if (mode == WIFI_CONFIG_BLUEFI)
{
#ifdef CONFIG_BLUEDROID_ENABLED
ble_config_start (periph);
#endif
return ESP_OK;
}
return err;
}
esp_err_t
periph_wifi_config_wait_done (esp_periph_handle_t periph,
TickType_t tick_to_wait)
{
VALIDATE_WIFI (periph, ESP_FAIL);
periph_wifi_handle_t periph_wifi
= (periph_wifi_handle_t)esp_periph_get_data (periph);
EventBits_t wificonfig_bit = xEventGroupWaitBits (
periph_wifi->state_event, SMARTCONFIG_DONE_BIT | SMARTCONFIG_ERROR_BIT,
false, false, tick_to_wait);
if (wificonfig_bit & SMARTCONFIG_DONE_BIT)
{
return ESP_OK;
}
if (wificonfig_bit & SMARTCONFIG_ERROR_BIT)
{
return ESP_FAIL;
}
esp_smartconfig_stop ();
return ESP_FAIL;
}
static void
wifi_reconnect_timer (xTimerHandle tmr)
{
esp_periph_handle_t periph = (esp_periph_handle_t)pvTimerGetTimerID (tmr);
periph_wifi_handle_t periph_wifi
= (periph_wifi_handle_t)esp_periph_get_data (periph);
esp_periph_stop_timer (periph);
if (periph_wifi->disable_auto_reconnect != true)
{
esp_wifi_connect ();
}
}
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
static void
_wifi_event_callback (void *arg, esp_event_base_t event_base, int32_t event_id,
void *event_data)
{
esp_periph_handle_t self = (esp_periph_handle_t)arg;
periph_wifi_handle_t periph_wifi
= (periph_wifi_handle_t)esp_periph_get_data (self);
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
{
esp_wifi_connect ();
}
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
{
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
ESP_LOGI (TAG, "Got ip:" IPSTR, IP2STR (&event->ip_info.ip));
periph_wifi->wifi_state = PERIPH_WIFI_CONNECTED;
xEventGroupClearBits (periph_wifi->state_event, DISCONNECTED_BIT);
esp_periph_send_event (self, PERIPH_WIFI_CONNECTED, NULL, 0);
xEventGroupSetBits (periph_wifi->state_event, CONNECTED_BIT);
wifi_config_t w_config;
memset (&w_config, 0x00, sizeof (wifi_config_t));
esp_wifi_get_config (WIFI_IF_STA, &w_config);
strcpy (periph_wifi->ssid, (char *)w_config.sta.ssid);
}
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
{
periph_wifi->wifi_state = PERIPH_WIFI_DISCONNECTED;
xEventGroupClearBits (periph_wifi->state_event, CONNECTED_BIT);
xEventGroupSetBits (periph_wifi->state_event, DISCONNECTED_BIT);
esp_periph_send_event (self, PERIPH_WIFI_DISCONNECTED, NULL, 0);
ESP_LOGW (TAG,
"Wi-Fi disconnected from SSID %s, auto-reconnect %s, "
"reconnect after %d ms",
periph_wifi->ssid,
periph_wifi->disable_auto_reconnect == 0 ? "enabled"
: "disabled",
periph_wifi->reconnect_timeout_ms);
if (periph_wifi->disable_auto_reconnect)
{
return;
}
esp_periph_start_timer (
self, periph_wifi->reconnect_timeout_ms / portTICK_RATE_MS,
wifi_reconnect_timer);
}
else
{
ESP_LOGW (TAG, "WiFi Event cb, Unhandle event_base:%s, event_id:%d",
event_base, event_id);
}
}
#else
static esp_err_t
_wifi_event_callback (void *ctx, system_event_t *event)
{
esp_periph_handle_t self = (esp_periph_handle_t)ctx;
periph_wifi_handle_t periph_wifi
= (periph_wifi_handle_t)esp_periph_get_data (self);
switch (event->event_id)
{
case SYSTEM_EVENT_STA_START:
periph_wifi->wifi_state = PERIPH_WIFI_CONNECTING;
esp_wifi_connect ();
break;
case SYSTEM_EVENT_STA_CONNECTED:
break;
case SYSTEM_EVENT_STA_GOT_IP:
periph_wifi->wifi_state = PERIPH_WIFI_CONNECTED;
xEventGroupClearBits (periph_wifi->state_event, DISCONNECTED_BIT);
esp_periph_send_event (self, PERIPH_WIFI_CONNECTED, NULL, 0);
xEventGroupSetBits (periph_wifi->state_event, CONNECTED_BIT);
wifi_config_t w_config;
memset (&w_config, 0x00, sizeof (wifi_config_t));
esp_wifi_get_config (WIFI_IF_STA, &w_config);
strcpy (periph_wifi->ssid, (char *)w_config.sta.ssid);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
periph_wifi->wifi_state = PERIPH_WIFI_DISCONNECTED;
xEventGroupClearBits (periph_wifi->state_event, CONNECTED_BIT);
xEventGroupSetBits (periph_wifi->state_event, DISCONNECTED_BIT);
esp_periph_send_event (self, PERIPH_WIFI_DISCONNECTED, NULL, 0);
ESP_LOGW (TAG,
"Wi-Fi disconnected from SSID %s, auto-reconnect %s, "
"reconnect after %d ms",
periph_wifi->ssid,
periph_wifi->disable_auto_reconnect == 0 ? "enabled"
: "disabled",
periph_wifi->reconnect_timeout_ms);
if (periph_wifi->disable_auto_reconnect)
{
break;
}
esp_periph_start_timer (
self, periph_wifi->reconnect_timeout_ms / portTICK_RATE_MS,
wifi_reconnect_timer);
break;
default:
break;
}
return ESP_OK;
}
#endif
static esp_err_t
_wifi_run (esp_periph_handle_t self, audio_event_iface_msg_t *msg)
{
esp_periph_send_event (self, msg->cmd, NULL, 0);
return ESP_OK;
}
static esp_err_t
_wifi_init (esp_periph_handle_t self)
{
periph_wifi_handle_t periph_wifi
= (periph_wifi_handle_t)esp_periph_get_data (self);
wifi_config_t wifi_config;
if (periph_wifi->is_open)
{
ESP_LOGE (TAG, "Wifi has initialized");
return ESP_FAIL;
}
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
ESP_ERROR_CHECK (esp_event_loop_create_default ());
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 1, 0))
esp_netif_create_default_wifi_sta ();
#endif
ESP_ERROR_CHECK (esp_event_handler_register (WIFI_EVENT, ESP_EVENT_ANY_ID,
&_wifi_event_callback, self));
ESP_ERROR_CHECK (esp_event_handler_register (IP_EVENT, IP_EVENT_STA_GOT_IP,
&_wifi_event_callback, self));
#else
#include "esp_event_loop.h"
if (esp_event_loop_get_queue () == NULL)
{
ESP_ERROR_CHECK (esp_event_loop_init (_wifi_event_callback, self));
}
else
{
esp_event_loop_set_cb (_wifi_event_callback, self);
}
#endif
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT ();
ESP_ERROR_CHECK (esp_wifi_init (&cfg));
memset (&wifi_config, 0x00, sizeof (wifi_config_t));
if (periph_wifi->ssid)
{
strcpy ((char *)wifi_config.sta.ssid, periph_wifi->ssid);
ESP_LOGD (TAG, "WIFI_SSID=%s", wifi_config.sta.ssid);
if (periph_wifi->password)
{
strcpy ((char *)wifi_config.sta.password, periph_wifi->password);
ESP_LOGD (TAG, "WIFI_PASS=%s", wifi_config.sta.password);
}
ESP_ERROR_CHECK (esp_wifi_set_storage (WIFI_STORAGE_RAM));
ESP_ERROR_CHECK (esp_wifi_set_mode (WIFI_MODE_STA));
ESP_ERROR_CHECK (esp_wifi_set_config (WIFI_IF_STA, &wifi_config));
}
if (periph_wifi->wpa2_e_cfg->diasble_wpa2_e)
{
unsigned int ca_pem_bytes = periph_wifi->wpa2_e_cfg->ca_pem_end
- periph_wifi->wpa2_e_cfg->ca_pem_start;
unsigned int client_crt_bytes
= periph_wifi->wpa2_e_cfg->wpa2_e_cert_end
- periph_wifi->wpa2_e_cfg->wpa2_e_cert_start;
unsigned int client_key_bytes
= periph_wifi->wpa2_e_cfg->wpa2_e_key_end
- periph_wifi->wpa2_e_cfg->wpa2_e_key_start;
ESP_ERROR_CHECK (esp_wifi_sta_wpa2_ent_set_ca_cert (
(const unsigned char *)periph_wifi->wpa2_e_cfg->ca_pem_start,
ca_pem_bytes));
ESP_ERROR_CHECK (esp_wifi_sta_wpa2_ent_set_cert_key (
(const unsigned char *)periph_wifi->wpa2_e_cfg->wpa2_e_cert_start,
client_crt_bytes,
(const unsigned char *)periph_wifi->wpa2_e_cfg->wpa2_e_key_start,
client_key_bytes, NULL, 0));
ESP_ERROR_CHECK (esp_wifi_sta_wpa2_ent_set_identity (
(uint8_t *)periph_wifi->wpa2_e_cfg->eap_id,
strlen (periph_wifi->wpa2_e_cfg->eap_id)));
if (periph_wifi->wpa2_e_cfg->eap_method == EAP_PEAP
|| periph_wifi->wpa2_e_cfg->eap_method == EAP_TTLS)
{
ESP_ERROR_CHECK (esp_wifi_sta_wpa2_ent_set_username (
(uint8_t *)periph_wifi->wpa2_e_cfg->eap_username,
strlen (periph_wifi->wpa2_e_cfg->eap_username)));
ESP_ERROR_CHECK (esp_wifi_sta_wpa2_ent_set_password (
(uint8_t *)periph_wifi->wpa2_e_cfg->eap_password,
strlen (periph_wifi->wpa2_e_cfg->eap_password)));
}
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0))
ESP_ERROR_CHECK (esp_wifi_sta_wpa2_ent_enable ());
#else
esp_wpa2_config_t wpa2_config = WPA2_CONFIG_INIT_DEFAULT ();
ESP_ERROR_CHECK (esp_wifi_sta_wpa2_ent_enable (&wpa2_config));
#endif
}
ESP_ERROR_CHECK (esp_wifi_start ());
periph_wifi->is_open = true;
periph_wifi->wifi_state = PERIPH_WIFI_DISCONNECTED;
xEventGroupClearBits (periph_wifi->state_event, CONNECTED_BIT);
xEventGroupSetBits (periph_wifi->state_event, DISCONNECTED_BIT);
return ESP_OK;
}
static esp_err_t
_wifi_destroy (esp_periph_handle_t self)
{
periph_wifi_handle_t periph_wifi
= (periph_wifi_handle_t)esp_periph_get_data (self);
esp_periph_stop_timer (self);
periph_wifi->disable_auto_reconnect = true;
esp_wifi_disconnect ();
periph_wifi_wait_for_disconnected (self, portMAX_DELAY);
esp_wifi_stop ();
esp_wifi_deinit ();
audio_free (periph_wifi->ssid);
audio_free (periph_wifi->password);
vEventGroupDelete (periph_wifi->state_event);
if (periph_wifi->wpa2_e_cfg != NULL)
{
audio_free (periph_wifi->wpa2_e_cfg);
periph_wifi->wpa2_e_cfg = NULL;
}
audio_free (periph_wifi);
g_periph = NULL;
return ESP_OK;
}
esp_periph_handle_t
periph_wifi_init (periph_wifi_cfg_t *config)
{
esp_periph_handle_t periph = NULL;
periph_wifi_handle_t periph_wifi = NULL;
bool _success
= ((periph = esp_periph_create (PERIPH_ID_WIFI, "periph_wifi"))
&& (periph_wifi = audio_calloc (1, sizeof (struct periph_wifi)))
&& (periph_wifi->state_event = xEventGroupCreate ())
&& (config->ssid
? (bool)(periph_wifi->ssid = audio_strdup (config->ssid))
: true)
&& (config->password ? (bool)(periph_wifi->password
= audio_strdup (config->password))
: true));
AUDIO_MEM_CHECK (TAG, _success, goto _periph_wifi_init_failed);
periph_wifi->reconnect_timeout_ms = config->reconnect_timeout_ms;
if (periph_wifi->reconnect_timeout_ms == 0)
{
periph_wifi->reconnect_timeout_ms = DEFAULT_RECONNECT_TIMEOUT_MS;
}
periph_wifi->disable_auto_reconnect = config->disable_auto_reconnect;
periph_wifi->wpa2_e_cfg
= audio_malloc (sizeof (periph_wpa2_enterprise_cfg_t));
AUDIO_NULL_CHECK (TAG, periph_wifi->wpa2_e_cfg, {
audio_free (periph);
goto _periph_wifi_init_failed;
});
memcpy (periph_wifi->wpa2_e_cfg, &config->wpa2_e_cfg,
sizeof (periph_wpa2_enterprise_cfg_t));
esp_periph_set_data (periph, periph_wifi);
esp_periph_set_function (periph, _wifi_init, _wifi_run, _wifi_destroy);
g_periph = periph;
return periph;
_periph_wifi_init_failed:
if (periph_wifi)
{
vEventGroupDelete (periph_wifi->state_event);
audio_free (periph_wifi->ssid);
audio_free (periph_wifi->password);
audio_free (periph_wifi);
}
return NULL;
}

Some files were not shown because too many files have changed in this diff Show More