Merge branch 'master' into fix_20ms_chunk_size_bug

# Conflicts:
#	.project
#	components/audio_board/CMakeLists.txt
#	components/audio_board/Kconfig.projbuild
#	components/audio_board/component.mk
#	components/audio_board/esp32_s2_kaluga_1_v1_2/board.c
#	components/audio_board/esp32_s2_kaluga_1_v1_2/board.h
#	components/audio_hal/driver/es8388/es8388.c
#	components/audio_hal/driver/es8388/headphone_detect.c
#	components/audio_hal/driver/tas5805m/tas5805m.c
#	components/custom_board/Kconfig.projbuild
#	components/esp_peripherals/driver/i2c_bus/i2c_bus.c
#	components/esp_peripherals/esp_peripherals.c
#	components/esp_peripherals/periph_button.c
#	components/esp_peripherals/periph_console.c
#	components/esp_peripherals/periph_led.c
#	components/esp_peripherals/periph_sdcard.c
#	components/esp_peripherals/periph_wifi.c
#	components/esp_peripherals/periph_ws2812.c
#	components/esp_peripherals/test/esp_peripherals_test.c
#	components/eth_interface/CMakeLists.txt
#	components/eth_interface/eth_interface.c
#	components/lightsnapcast/include/snapcast.h
#	components/lightsnapcast/player.c
#	components/wifi_interface/CMakeLists.txt
#	components/wifi_interface/wifi_interface.c
#	dependencies.lock
#	main/CMakeLists.txt
#	main/main.c
#	sdkconfig_PCM5102A
#	sdkconfig_TAS5805M

Signed-off-by: Karl Osterseher <karli_o@gmx.at>
This commit is contained in:
Karl Osterseher
2025-01-19 00:05:24 +01:00
Unverified
66 changed files with 14621 additions and 2271 deletions

View File

@@ -9,10 +9,9 @@
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.pathentry">
<pathentry kind="src" path=""/>
<pathentry excluding="**/CMakeFiles/**" kind="out" path="build"/>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
<storageModule moduleId="org.eclipse.cdt.core.pathentry">
<pathentry excluding="**/CMakeFiles/**" kind="out" path="build"/>
</storageModule>
</cproject>

3
.gitmodules vendored
View File

@@ -7,3 +7,6 @@
[submodule "components/opus/opus"]
path = components/opus/opus
url = https://github.com/xiph/opus
[submodule "components/improv_wifi/Improv-WiFi-Library"]
path = components/improv_wifi/Improv-WiFi-Library
url = https://github.com/jnthas/Improv-WiFi-Library.git

4007
.project

File diff suppressed because it is too large Load Diff

View File

@@ -21,24 +21,21 @@ Please check out the task list and feel free to fill in.
I dropped the usage of ADF completely but copied stripped down, needed components to this project (using <b>ESP-ADF v2.6</b>).
This was necessary because ADF was using flac in closed source precompiled library
which made it impossible to get good results for multiroom syncing. IDF's I2S driver was also copied
to project's components and adapted. Originally it wasn't possible to pre load DMA buffers with audio
samples and therefore no precise sync could be achieved.
which made it impossible to get good results for multiroom syncing.
### Codebase
The codebase is split into components and build on <b>ESP-IDF v4.3.5</b>. I still
The codebase is split into components and build on <b>ESP-IDF v5.1.1</b>. I still
have some refactoring on the todo list as the concept has started to settle and
allow for new features can be added in a structured manner. In the code you
will find parts that are only partly related features and still not on the task
list. Also there is a lot of code clean up needed.
Components
- audio-board : taken from ADF, stripped down to strictly necessary parts for usage with Lyrat v4.3
- audio-hal : taken from ADF, stripped down to strictly necessary parts for usage with Lyrat v4.3
- audio-sal : taken from ADF, stripped down to strictly necessary parts for usage with Lyrat v4.3
- custom_board :
- custom-driver : modified I2S driver from IDF v4.3.1 which supports preloading DMA buffers with valid data
- audio-board : taken from ADF, stripped down to strictly necessary parts for playback
- audio-hal : taken from ADF, stripped down to strictly necessary parts for playback
- audio-sal : taken from ADF, stripped down to strictly necessary parts for playback
- custom_board : generic board component to support easy integration of DACs
- dsp_processor : Audio Processor, low pass filters, effects, etc.
- esp-dsp : Submodule to the ESP-ADF done by David Douard
- esp-peripherals : taken from ADF, stripped down to strictly necessary parts for usage with Lyrat v4.3
@@ -121,12 +118,30 @@ git submodule update --init
```
### ESP-IDF environnement configuration
- <b>If you're on Windows :</b> Install ESP-IDF v4.3.5 locally [https://github.com/espressif/esp-idf/releases/tag/v4.3.5](https://github.com/espressif/esp-idf/releases/tag/v4.3.5). More info: [https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup-update.html](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup-update.html)
- <b>If you're on Linux :</b> Use the docker image for ESP-IDF by following [docker build](doc/docker_build.md) doc.
- <b>If you're on Windows :</b> Install [ESP-IDF v5.1.1](https://github.com/espressif/esp-idf/releases/tag/v5.1.1) locally ([More info](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/windows-setup-update.html)).
- <b>If you're on Linux (docker) :</b> Use the image for ESP-IDF by following [docker build](doc/docker_build.md) doc
- <b>If you're on Linux :</b> follow [official Espressif](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/get-started/linux-macos-setup.html) instructions
For debian based systems you'll need to do the following:
```
sudo apt-get install git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0
mkdir -p ~/esp
cd ~/esp
git clone -b v5.1.1 --recursive https://github.com/espressif/esp-idf.git
cd ~/esp/esp-idf
./install.sh esp32
. ./export.sh
```
<a name="config"></a>
### Snapcast ESP Configuration
Configure your platform:
Frist copy one of the template sdkconfig files and rename it to sdkconfig
```
cp sdkconfig_lyrat_v4.3 sdkconfig
```
then configure your platform:
```
idf.py menuconfig
```
@@ -169,6 +184,13 @@ Configure to match your setup
```
idf.py build flash monitor
```
### Merge bin to flash at 0x0 with web.esphome.io
```
esptool.py --chip esp32 merge_bin -o merged.bin --flash_size 4MB --flash_freq 80m 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0xd000 build/ota_data_initial.bin 0x10000 build/snapclient.bin 0x370000 build/storage.bin
```
## Test
Setup a snapcast server on your network
@@ -209,29 +231,13 @@ Then on every `git commit`, a few sanity/formatting checks will be performed.
## Task list
- [ok] Fix to alinge with above
- [ok] put kconfig to better locations in tree
* add codec description
- [ok] Integrate ESP wifi provision
- [ok] Find and connect to Avahi broadcasted Snapcast server name
- [ ] Add a client command interface layer like volume/mute control
- [ ] put kconfig to better locations in tree
- [ ] add missing codec's (ogg)
- [ok] test esp-dsp functionality after ADF drop
- [ok] Check compatibility with different HW than Lyrat v4.3
- [ok] rework dsp_processor and test. At the moment only dspfStereo and dspfBassBoost will work. Also ensure/test we got enough RAM on WROVER modules
- [ ] reduce dsp_processor memory footprint
- [ ] dsp_processor: add equalizer
* Control interface for equalizer
- [ ] Control interface for equalizer (component: ui_http_server)
- [ ] clean and polish code (remove all unused variables etc.)
- [ok] Improve Documentation, e.g. Hardware guide (supported codecs)
- [ ] upgrade to IDF v5
- [ ] in IDF v5 use native i2s driver, as it supports preloading DMA buffer with valid data now
- [ ] Improve Documentation
- [ ] Throw out ADF copied components from project tree and use CmakeLists.txt to pull in necessary files from ADF
## Minor task
- [ok] soft mute - play sample in buffer with decreasing volume
- [ok] hard mute - using ADF's HAL
- [ok] Startup: do not start parsing on samples to codec before sample ring buffer hits requested buffer size.
- [ok] Start from empty buffer
- [ ] fill in missing component descriptions in Readme.md
- [ok] DAC latency setting from android app
- [ ] fill in missing component descriptions in Readme.md

View File

@@ -22,6 +22,15 @@ set(COMPONENT_SRCS
)
endif()
if (CONFIG_ESP_AI_THINKER_ES8388_BOARD)
message(STATUS "Current board name is " CONFIG_ESP_AI_THINKER_ES8388_BOARD)
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./ai_thinker_es8388)
set(COMPONENT_SRCS
./ai_thinker_es8388/board.c
./ai_thinker_es8388/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)
@@ -60,7 +69,6 @@ set(COMPONENT_SRCS
)
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)
@@ -70,6 +78,7 @@ set(COMPONENT_SRCS
)
endif()
#[[
if (CONFIG_ESP32_S3_KORVO2_V3_BOARD)
message(STATUS "Current board name is " CONFIG_ESP32_S3_KORVO2_V3_BOARD)
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./esp32_s3_korvo2_v3)

View File

@@ -1,64 +1,330 @@
menu "Audio HAL"
menu "Audio Board"
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"
#config ESP32_S3_KORVO2_V3_BOARD
# bool "ESP32-S3-Korvo-2 v3"
#config ESP32_S3_KORVO2L_V1_BOARD
# bool "ESP32-S3-Korvo-2L v1"
#config ESP32_S3_BOX_LITE_BOARD
# bool "ESP32-S3-BOX-Lite"
#config ESP32_S3_BOX_BOARD
# bool "ESP32-S3-BOX"
#config ESP32_C3_LYRA_V2_BOARD
# bool "ESP32-C3-Lyra-v2.0"
#config ESP32_C6_DEVKIT_BOARD
# bool "ESP32-C6-DEVKIT"
config I2S_USE_MSB_FORMAT
bool
default n
help
Specifies if the I2S should use MSB format instead. Some DACs (such as PT8211) need this enabled to ensure
compatibility with their LSBJ timing under their native bit-depth. This option is only adjusted by the DAC
choice and is not exposed to menuconfig.
See https://github.com/schreibfaul1/ESP32-audioI2S/blob/1d9b299d0197f99fc70335295adcd226dc220f88/src/Audio.cpp#L4929
endchoice
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"
config ESP_AI_THINKER_ES8388_BOARD
bool "ESP-AI-Thinker-ES8388 v2.2"
#config ESP32_S3_KORVO2_V3_BOARD
# bool "ESP32-S3-Korvo-2 v3"
#config ESP32_S3_KORVO2L_V1_BOARD
# bool "ESP32-S3-Korvo-2L v1"
#config ESP32_S3_BOX_LITE_BOARD
# bool "ESP32-S3-BOX-Lite"
#config ESP32_S3_BOX_BOARD
# bool "ESP32-S3-BOX"
#config ESP32_C3_LYRA_V2_BOARD
# bool "ESP32-C3-Lyra-v2.0"
#config ESP32_C6_DEVKIT_BOARD
# bool "ESP32-C6-DEVKIT"
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
endchoice
config ESP32_KORVO_DU1906_DAC_TAS5805M
bool "ESP32_KORVO_DU1906_DAC_TAS5805M"
config ESP32_KORVO_DU1906_DAC_ES7148
bool "ESP32_KORVO_DU1906_DAC_ES7148"
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
endchoice
config ESP32_KORVO_DU1906_DAC_TAS5805M
bool "ESP32_KORVO_DU1906_DAC_TAS5805M"
config ESP32_KORVO_DU1906_DAC_ES7148
bool "ESP32_KORVO_DU1906_DAC_ES7148"
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
endchoice
config ESP32_KORVO_DU1906_ADC_ES7243
bool "ESP32_KORVO_DU1906_ADC_ES7243"
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
menu "Custom Audio Board"
depends on AUDIO_BOARD_CUSTOM
choice GENERIC_BOARD_DAC
prompt "DAC chip"
default DAC_MA120
help
Select a DAC connected to the generic ESP32 board
config DAC_PCM51XX
bool "TI PCM51XX/TAS57XX based DAC"
config DAC_PCM5102A
bool "TI PCM5102A based DAC"
config DAC_MA120
bool "Infineon MA120 ClassD AMP"
config DAC_MA120X0
bool "Infineon MA120X0 ClassD AMP"
config DAC_ADAU1961
bool "Analog Devices ADAU1961 DAC"
config DAC_MAX98357
bool "Analog Devices MAX98357 DAC"
config DAC_TAS5805M
bool "Texas Instruments TAS5805M"
config DAC_PT8211
bool "Princeton Technology PT8211"
select I2S_USE_MSB_FORMAT
endchoice
menu "DAC I2C control interface"
config DAC_I2C_SDA
int "SDA pin"
default 12 if DAC_ADAU1961
default 21 if DAC_MA120 || DAC_PCM51XX || DAC_MA120 || DAC_MA120X0 || DAC_MAX98357 || DAC_PCM5102A || DAC_TAS5805M
default -1 if DAC_PT8211
help
I2C SDA pin of the DAC control interface
config DAC_I2C_SCL
int "SCL pin"
default 14 if DAC_ADAU1961
default 22 if DAC_MA120 || DAC_PCM51XX || DAC_MA120 || DAC_MA120X0 || DAC_MAX98357 || DAC_PCM5102A
default 27 if DAC_TAS5805M
default -1 if DAC_PT8211
help
I2C SCL pin of the DAC control interface
config DAC_I2C_ADDR
hex "I2C address"
default 0x70 if DAC_ADAU1961
default 0x20 if DAC_MA120 || DAC_PCM51XX || DAC_MA120 || DAC_MA120X0 || DAC_MAX98357 || DAC_PCM5102A
default 0x2D if DAC_TAS5805M
default 0x00 if DAC_PT8211
help
I2C Address of the DAC control interface
endmenu
menu "I2S master interface"
config MASTER_I2S_MCLK_PIN
int "Master i2s mclk"
default 3 if DAC_ADAU1961
default 0
help
Master audio interface master clock.
config MASTER_I2S_BCK_PIN
int "Master i2s bck"
default 15 if DAC_ADAU1961
default 23 if DAC_MAX98357
default 26 if DAC_TAS5805M
default 23
help
Master audio interface bit clock.
config MASTER_I2S_LRCK_PIN
int "Master i2s lrck"
default 13 if DAC_ADAU1961
default 24 if DAC_MAX98357
default 25 if DAC_TAS5805M
default 2
help
Master audio interface left/right sync clock.
config MASTER_I2S_DATAOUT_PIN
int "Master i2s data out"
default 4 if DAC_ADAU1961
default 25 if DAC_MAX98357
default 22 if DAC_TAS5805M
default 14
help
Master audio interface data out.
endmenu
menu "DAC-Operation-Mode"
depends on DAC_TAS5805M
config DAC_BRIDGE_MODE
bool "Enable Bridge-Mode"
default false if DAC_TAS5805M
help
If enabled left channel will be played with more power. To use the right channel please change Word-Select-Setting in Logic-Level-Settings.
endmenu
menu "I2S slave interface"
config SLAVE_I2S_BCK_PIN
int "Slave i2s bck"
default 26
help
Slave audio interface bit clock.
config SLAVE_I2S_MCLK_PIN
int "Slave i2s mclk"
default 0
help
Slave audio interface bit clock.
config SLAVE_I2S_LRCK_PIN
int "Slave i2s lrck"
default 12
help
Slave audio interface left/right sync clock.
config SLAVE_I2S_DATAOUT_PIN
int "Slave i2s data out"
default 5
help
Slave audio interface data out.
endmenu
menu "Merus MA120x0 interface Configuration"
depends on DAC_MA120X0
config MA120X0_NENABLE_PIN
int "Master enable/disable for ma120x0"
default 16
help
GPIO number to control enable/disable.
config MA120X0_NMUTE_PIN
int "Master mute/unmute for ma120x0"
default 2
help
GPIO number to controm mute/unmute.
config MERUS_NERR_PIN
int "NERR monitor pin"
default 21
help
GPIO number to monitor NERROR.
config MERUS_NCLIP_PIN
int "Clip indication pin"
default 22
help
GPIO number low if clip observed
endmenu
menu "Merus MA120 interface Configuration"
depends on DAC_MA120
config MA120_ENABLE_PIN
int "Master enable/disable for ma120x0"
default 16
help
GPIO number to control enable/disable.
config MA120_NMUTE_PIN
int "Master mute/unmute for ma120x0"
default 2
help
GPIO number to controm mute/unmute.
config MERUS_NERR_PIN
int "NERR monitor pin"
default 21
help
GPIO number to monitor NERROR.
config MERUS_NCLIP_PIN
int "Clip indication pin"
default 22
help
GPIO number low if clip observed
endmenu
menu "TI PCM5102A interface Configuration"
depends on DAC_PCM5102A
config PCM5102A_MUTE_PIN
int "Master mute/unmute for PCM5102A"
default 18
help
GPIO number to control mute/unmute.
This is labeled "X(S)MT" on chip/boards
endmenu
menu "MAX98357 interface Configuration"
depends on DAC_MAX98357
config MAX98357_MUTE_PIN
int "Master mute/mode for MAX98357"
default 18
help
GPIO number to control mute/mode. This require a special resistor to select the correct mode.
You need to put a serie resistor to select the mode (GPIO --> Resistor --> SD):
LEFT only : 0ohm (direct connection)
RIGHT only : 220Kohm
(L+R)/2 : 1Mohm
Refer to Analog Devices' doc for more infos.
This is labeled "SD" on chip/boards.
endmenu
menu "PT8211 interface Configuration"
depends on DAC_PT8211
config PT8211_MUTE_PIN
int "Master mute/unmute"
default -1
help
GPIO number to control mute/unmute.
Note that PT8211 does not have a mute control pin. This output is intended to control external circuit (e.g., amplifier).
config PT8211_MUTE_ACTIVE_LOW
bool "Mute active LOW"
default false
help
Output LOW instead of HIGH on mute/unmute pin when in mute state.
endmenu
menu "Logic-Level-Settings"
config INVERT_MCLK_LEVEL
bool "Invert Logic Level MCLK"
default false
help
Invert the Logic-Level of MCLK.
config INVERT_WORD_SELECT_LEVEL
bool "Invert Logic Level WordSelect"
default false
help
Some Dacs can bridge their outputs. Word-Select is used for selecting the played audio channel. This will switch L/R.
config INVERT_BCLK_LEVEL
bool "Invert Logic Level BCLK"
default false
help
Invert the Logic-Level of BCLK.
endmenu
endmenu
endmenu

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,103 @@
/*
* 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 BOARD_PA_GAIN (10) /* Power amplifier gain defined by board (dB) */
#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, \
}, \
};
/**
* @brief Button Function Definition
*/
#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,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.
*
*/
#include <string.h>
#include "audio_error.h"
#include "audio_mem.h"
#include "board.h"
#include "driver/gpio.h"
#include "esp_log.h"
static const char *TAG = "AI_THINKER_ES8388";
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_33;
i2c_config->scl_io_num = GPIO_NUM_32;
} 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, board_i2s_pin_t *i2s_config) {
AUDIO_NULL_CHECK(TAG, i2s_config, return ESP_FAIL);
if (port == I2S_NUM_0 || port == I2S_NUM_1) {
i2s_config->mck_io_num = GPIO_NUM_0;
i2s_config->bck_io_num = GPIO_NUM_27;
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(board_i2s_pin_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;
}
// 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

@@ -51,3 +51,8 @@ ifdef CONFIG_ESP32_C3_LYRA_V2_BOARD
COMPONENT_ADD_INCLUDEDIRS += ./esp32_c3_lyra
COMPONENT_SRCDIRS += ./esp32_c3_lyra
endif
ifdef CONFIG_ESP_AI_THINKER_ES8388_BOARD
COMPONENT_ADD_INCLUDEDIRS += ./ai_thinker_es8388
COMPONENT_SRCDIRS += ./ai_thinker_es8388
endif

View File

@@ -28,7 +28,7 @@
#include "audio_mem.h"
#include "esp_log.h"
#include "periph_adc_button.h"
// #include "periph_adc_button.h"
static const char *TAG = "AUDIO_BOARD";
@@ -61,80 +61,81 @@ esp_err_t audio_board_sdcard_init(esp_periph_set_handle_t set,
return ret;
}
display_service_handle_t audio_board_led_init(void) {
// TODO
return NULL;
}
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0))
esp_err_t _get_lcd_io_bus(void *bus, esp_lcd_panel_io_spi_config_t *io_config,
esp_lcd_panel_io_handle_t *out_panel_io) {
return esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)bus, io_config,
out_panel_io);
}
void *audio_board_lcd_init(esp_periph_set_handle_t set, void *cb) {
gpio_config_t bk_gpio_config = {.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << LCD_CTRL_GPIO};
// Initialize the GPIO of backlight
ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
spi_bus_config_t buscfg = {.sclk_io_num = LCD_CLK_GPIO,
.mosi_io_num = LCD_MOSI_GPIO,
.miso_io_num = -1,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 16 * LCD_H_RES * 2 + 8};
ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
esp_lcd_panel_io_spi_config_t io_config = {
.dc_gpio_num = LCD_DC_GPIO,
.cs_gpio_num = LCD_CS_GPIO,
.pclk_hz = 60 * 1000 * 1000,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
.spi_mode = 0,
.trans_queue_depth = 10,
.on_color_trans_done = cb,
.user_ctx = NULL,
};
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = LCD_RST_GPIO,
.color_space = ESP_LCD_COLOR_SPACE_BGR,
.bits_per_pixel = 16,
};
periph_lcd_cfg_t cfg = {
.io_bus = (void *)SPI2_HOST,
.new_panel_io = _get_lcd_io_bus,
.lcd_io_cfg = &io_config,
.new_lcd_panel = esp_lcd_new_panel_st7789,
.lcd_dev_cfg = &panel_config,
.rest_cb = NULL,
.rest_cb_ctx = NULL,
.lcd_swap_xy = LCD_SWAP_XY,
.lcd_mirror_x = LCD_MIRROR_X,
.lcd_mirror_y = LCD_MIRROR_Y,
.lcd_color_invert = LCD_COLOR_INV,
};
esp_periph_handle_t periph_lcd = periph_lcd_init(&cfg);
AUDIO_NULL_CHECK(TAG, periph_lcd, return NULL);
esp_periph_start(set, periph_lcd);
return (void *)periph_lcd_get_panel_handle(periph_lcd);
}
#endif
esp_err_t audio_board_key_init(esp_periph_set_handle_t set) {
periph_adc_button_cfg_t adc_btn_cfg = PERIPH_ADC_BUTTON_DEFAULT_CONFIG();
adc_arr_t adc_btn_tag = ADC_DEFAULT_ARR();
adc_btn_tag.adc_ch = ADC1_CHANNEL_5;
adc_btn_tag.total_steps = 6;
int btn_array[7] = {190, 600, 1000, 1375, 1775, 2195, 2610};
adc_btn_tag.adc_level_step = btn_array;
adc_btn_cfg.arr = &adc_btn_tag;
adc_btn_cfg.arr_size = 1;
esp_periph_handle_t adc_btn_handle = periph_adc_button_init(&adc_btn_cfg);
AUDIO_NULL_CHECK(TAG, adc_btn_handle, return ESP_ERR_ADF_MEMORY_LACK);
return esp_periph_start(set, adc_btn_handle);
}
// display_service_handle_t audio_board_led_init(void) {
// // TODO
// return NULL;
// }
// #if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0))
// esp_err_t _get_lcd_io_bus(void *bus, esp_lcd_panel_io_spi_config_t
// *io_config,
// esp_lcd_panel_io_handle_t *out_panel_io) {
// return esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)bus, io_config,
// out_panel_io);
// }
//
// void *audio_board_lcd_init(esp_periph_set_handle_t set, void *cb) {
// gpio_config_t bk_gpio_config = {.mode = GPIO_MODE_OUTPUT,
// .pin_bit_mask = 1ULL << LCD_CTRL_GPIO};
// // Initialize the GPIO of backlight
// ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
//
// spi_bus_config_t buscfg = {.sclk_io_num = LCD_CLK_GPIO,
// .mosi_io_num = LCD_MOSI_GPIO,
// .miso_io_num = -1,
// .quadwp_io_num = -1,
// .quadhd_io_num = -1,
// .max_transfer_sz = 16 * LCD_H_RES * 2 + 8};
// ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
//
// esp_lcd_panel_io_spi_config_t io_config = {
// .dc_gpio_num = LCD_DC_GPIO,
// .cs_gpio_num = LCD_CS_GPIO,
// .pclk_hz = 60 * 1000 * 1000,
// .lcd_cmd_bits = 8,
// .lcd_param_bits = 8,
// .spi_mode = 0,
// .trans_queue_depth = 10,
// .on_color_trans_done = cb,
// .user_ctx = NULL,
// };
// esp_lcd_panel_dev_config_t panel_config = {
// .reset_gpio_num = LCD_RST_GPIO,
// .color_space = ESP_LCD_COLOR_SPACE_BGR,
// .bits_per_pixel = 16,
// };
// periph_lcd_cfg_t cfg = {
// .io_bus = (void *)SPI2_HOST,
// .new_panel_io = _get_lcd_io_bus,
// .lcd_io_cfg = &io_config,
// .new_lcd_panel = esp_lcd_new_panel_st7789,
// .lcd_dev_cfg = &panel_config,
// .rest_cb = NULL,
// .rest_cb_ctx = NULL,
// .lcd_swap_xy = LCD_SWAP_XY,
// .lcd_mirror_x = LCD_MIRROR_X,
// .lcd_mirror_y = LCD_MIRROR_Y,
// .lcd_color_invert = LCD_COLOR_INV,
// };
// esp_periph_handle_t periph_lcd = periph_lcd_init(&cfg);
// AUDIO_NULL_CHECK(TAG, periph_lcd, return NULL);
// esp_periph_start(set, periph_lcd);
// return (void *)periph_lcd_get_panel_handle(periph_lcd);
// }
// #endif
//
// esp_err_t audio_board_key_init(esp_periph_set_handle_t set) {
// periph_adc_button_cfg_t adc_btn_cfg = PERIPH_ADC_BUTTON_DEFAULT_CONFIG();
// adc_arr_t adc_btn_tag = ADC_DEFAULT_ARR();
// adc_btn_tag.adc_ch = ADC1_CHANNEL_5;
// adc_btn_tag.total_steps = 6;
// int btn_array[7] = {190, 600, 1000, 1375, 1775, 2195, 2610};
// adc_btn_tag.adc_level_step = btn_array;
// adc_btn_cfg.arr = &adc_btn_tag;
// adc_btn_cfg.arr_size = 1;
// esp_periph_handle_t adc_btn_handle = periph_adc_button_init(&adc_btn_cfg);
// AUDIO_NULL_CHECK(TAG, adc_btn_handle, return ESP_ERR_ADF_MEMORY_LACK);
// return esp_periph_start(set, adc_btn_handle);
// }
audio_board_handle_t audio_board_get_handle(void) { return board_handle; }

View File

@@ -30,10 +30,10 @@
#include "audio_hal.h"
#include "board_def.h"
#include "board_pins_config.h"
#include "display_service.h"
#include "esp_peripherals.h"
#include "periph_lcd.h"
#include "periph_sdcard.h"
// #include "display_service.h"
// #include "esp_peripherals.h"
// #include "periph_lcd.h"
// #include "periph_sdcard.h"
#ifdef __cplusplus
extern "C" {
@@ -67,7 +67,7 @@ audio_hal_handle_t audio_board_codec_init(void);
*
* @return The audio display service handle
*/
display_service_handle_t audio_board_led_init(void);
// display_service_handle_t audio_board_led_init(void);
/**
* @brief Initialize lcd peripheral
@@ -78,7 +78,7 @@ display_service_handle_t audio_board_led_init(void);
*
* @return The `esp_lcd_panel_handle_t` handle
*/
void *audio_board_lcd_init(esp_periph_set_handle_t set, void *cb);
// void *audio_board_lcd_init(esp_periph_set_handle_t set, void *cb);
/**
* @brief Initialize sdcard peripheral
@@ -89,8 +89,8 @@ void *audio_board_lcd_init(esp_periph_set_handle_t set, void *cb);
* - ESP_OK, success
* - Others, fail
*/
esp_err_t audio_board_sdcard_init(esp_periph_set_handle_t set,
periph_sdcard_mode_t mode);
// esp_err_t audio_board_sdcard_init(esp_periph_set_handle_t set,
// periph_sdcard_mode_t mode);
/**
* @brief Initialize key peripheral
@@ -101,7 +101,7 @@ esp_err_t audio_board_sdcard_init(esp_periph_set_handle_t set,
* - ESP_OK, success
* - Others, fail
*/
esp_err_t audio_board_key_init(esp_periph_set_handle_t set);
// esp_err_t audio_board_key_init(esp_periph_set_handle_t set);
/**
* @brief Query audio_board_handle

View File

@@ -33,7 +33,8 @@
#include "esp_log.h"
#include "i2c_bus.h"
#ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
#if defined(CONFIG_ESP_LYRAT_V4_3_BOARD) || \
defined(CONFIG_ESP_AI_THINKER_ES8388_BOARD)
#include "headphone_detect.h"
#endif
@@ -266,11 +267,16 @@ esp_err_t es8388_i2s_config_clock(es_i2s_clock_t cfg) {
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
#if defined(CONFIG_ESP_LYRAT_V4_3_BOARD) || \
defined(CONFIG_ESP_AI_THINKER_ES8388_BOARD)
headphone_detect_deinit();
res = es_write_reg(ES8388_ADDR, ES8388_CHIPPOWER,
0xFF); // reset and stop es8388
i2c_bus_delete(i2c_handle);
#endif
audio_codec_volume_deinit(dac_vol_handle);
@@ -284,7 +290,9 @@ esp_err_t es8388_deinit(void) {
*/
esp_err_t es8388_init(audio_hal_codec_config_t *cfg) {
int res = 0;
#ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
#if defined(CONFIG_ESP_LYRAT_V4_3_BOARD) || \
defined(CONFIG_ESP_AI_THINKER_ES8388_BOARD)
headphone_detect_init(get_headphone_detect_gpio());
#endif
@@ -326,15 +334,15 @@ esp_err_t es8388_init(audio_hal_codec_config_t *cfg) {
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 |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL23, 0x00); // vroi=0
res |= es_write_reg(
ES8388_ADDR, ES8388_DACCONTROL24,
0x1E); // Set L1 R1 L2 R2 volume. 0x00: -30dB, 0x1E: 0dB, 0x21: 3dB
res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL25, 0x1E);
res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL26, 0);
res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL27, 0);
// res |= es8388_set_adc_dac_volume(ES_MODULE_DAC, 0, 0); // 0db
res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL26, 0x1E);
res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL27, 0x1E);
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;
@@ -430,18 +438,41 @@ esp_err_t es8388_config_fmt(es_module_t mode, es_i2s_fmt_t fmt) {
esp_err_t es8388_set_voice_volume(int volume) {
esp_err_t res = ESP_OK;
uint8_t reg = 0;
reg = audio_codec_get_dac_reg_value(dac_vol_handle, volume);
res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL5, reg);
res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL4, reg);
ESP_LOGD(ES_TAG, "Set volume:%.2d reg_value:0x%.2x dB:%.1f",
(int)dac_vol_handle->user_volume, reg,
audio_codec_cal_dac_volume(dac_vol_handle));
/* Audio Settings can be checked here:
* https://dl.radxa.com/rock2/docs/hw/ds/ES8388%20user%20Guide.pdf
*
* ES8388_DACCONTROL4 & ES8388_DACCONTROL5
* 0 = 0dB
* 192 = -96dB
*
* ES8388_DACCONTROL24 - ES8388_DACCONTROL27
* 0 = -45dB
* 33 = 4.5dB
*/
// restrict range from 0-46 instead of 0-192
// int inv_volume = -0.46 * volume + 46;
// if (volume == 0) {
// // if volume is 0, set to -96dB
// inv_volume = 192;
// }
// res = es_write_reg (ES8388_ADDR, ES8388_DACCONTROL5, inv_volume);
// res |= es_write_reg (ES8388_ADDR, ES8388_DACCONTROL4, inv_volume);
return res;
}
esp_err_t es8388_get_voice_volume(int *volume) {
esp_err_t res = ESP_OK;
uint8_t reg = 0;
res = es_read_reg(ES8388_DACCONTROL4, &reg);
if (res == ESP_FAIL) {
*volume = 0;
@@ -454,6 +485,20 @@ esp_err_t es8388_get_voice_volume(int *volume) {
}
}
ESP_LOGD(ES_TAG, "Get volume:%.2d reg_value:0x%.2x", *volume, reg);
// else
// {
// // 0 = 0dB, 192 = -96dB
// // max is 0, min is 46
// // interpolate to 0-100
// if (reg == 192) {
// *volume = 0;
// }
// else {
// *volume = -(50/23) * reg + 100;
// }
// }
return res;
}

View File

@@ -36,12 +36,13 @@
#include "freertos/task.h"
#include "freertos/timers.h"
#ifdef CONFIG_ESP_LYRAT_V4_3_BOARD
#if defined(CONFIG_ESP_LYRAT_V4_3_BOARD) || \
defined(CONFIG_ESP_AI_THINKER_ES8388_BOARD)
#define HP_DELAY_TIME_MS 1000
static const char *TAG = "HEADPHONE";
static xTimerHandle timer_headphone;
static TimerHandle_t timer_headphone;
static void hp_timer_cb(TimerHandle_t xTimer) {
int num = (int)pvTimerGetTimerID(xTimer);
@@ -51,7 +52,7 @@ static void hp_timer_cb(TimerHandle_t xTimer) {
static int hp_timer_init(int num) {
timer_headphone =
xTimerCreate("hp_timer0", HP_DELAY_TIME_MS / portTICK_RATE_MS, pdFALSE,
xTimerCreate("hp_timer0", HP_DELAY_TIME_MS / portTICK_PERIOD_MS, pdFALSE,
(void *)num, hp_timer_cb);
if (timer_headphone == NULL) {
ESP_LOGE(TAG, "hp_timer create err");
@@ -69,7 +70,7 @@ static void IRAM_ATTR headphone_gpio_intr_handler(void *arg) {
}
void headphone_detect_deinit() {
xTimerDelete(timer_headphone, HP_DELAY_TIME_MS / portTICK_RATE_MS);
xTimerDelete(timer_headphone, HP_DELAY_TIME_MS / portTICK_PERIOD_MS);
gpio_uninstall_isr_service();
timer_headphone = NULL;
}
@@ -92,4 +93,5 @@ void headphone_detect_init(int num) {
gpio_install_isr_service(0);
gpio_isr_handler_add(num, headphone_gpio_intr_handler, (void *)num);
}
#endif /* CONFIG_ESP_LYRAT_V4_3_BOARD */
#endif /* defined(CONFIG_ESP_LYRAT_V4_3_BOARD) || \
defined(CONFIG_ESP_AI_THINKER_ES8388_BOARD) */

View File

@@ -29,7 +29,6 @@
#include "audio_volume.h"
#include "board.h"
#include "esp_log.h"
#include "freertos/projdefs.h"
#include "i2c_bus.h"
#include "tas5805m_reg_cfg.h"
@@ -96,7 +95,7 @@ static esp_err_t tas5805m_transmit_registers(const tas5805m_cfg_reg_t *conf_buf,
// Used in legacy applications. Ignored here.
break;
case CFG_META_DELAY:
vTaskDelay(pdMS_TO_TICKS(conf_buf[i].value));
vTaskDelay(conf_buf[i].value / portTICK_PERIOD_MS);
break;
case CFG_META_BURST:
ret = i2c_bus_write_bytes(i2c_handler, TAS5805M_ADDR,
@@ -136,9 +135,9 @@ esp_err_t tas5805m_init(audio_hal_codec_config_t *codec_cfg) {
io_conf.intr_type = GPIO_INTR_DISABLE;
gpio_config(&io_conf);
gpio_set_level(TAS5805M_RST_GPIO, 0);
vTaskDelay(pdMS_TO_TICKS(20));
vTaskDelay(20 / portTICK_PERIOD_MS);
gpio_set_level(TAS5805M_RST_GPIO, 1);
vTaskDelay(pdMS_TO_TICKS(200));
vTaskDelay(200 / portTICK_PERIOD_MS);
ret = get_i2c_pins(I2C_NUM_0, &i2c_cfg);
i2c_handler = i2c_bus_create(I2C_NUM_0, &i2c_cfg);

View File

@@ -17,7 +17,7 @@ if(CONFIG_AUDIO_BOARD_CUSTOM)
endif()
if(CONFIG_DAC_PCM51XX)
message(STATUS "Selected DAC is " CONFIG_DAC_PCM15XX)
message(STATUS "Selected DAC is " CONFIG_DAC_PCM51XX)
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./pcm51xx/include)
list(APPEND COMPONENT_SRCS ./pcm51xx/pcm51xx.c)
endif()
@@ -45,6 +45,18 @@ if(CONFIG_AUDIO_BOARD_CUSTOM)
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./max98357/include)
list(APPEND COMPONENT_SRCS ./max98357/max98357.c)
endif()
if(CONFIG_DAC_TAS5805M)
message(STATUS "Selected DAC is " CONFIG_DAC_TAS5805M)
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./tas5805m/include)
list(APPEND COMPONENT_SRCS ./tas5805m/tas5805m.c)
endif()
if(CONFIG_DAC_PT8211)
message(STATUS "Selected DAC is " CONFIG_DAC_PT8211)
list(APPEND COMPONENT_ADD_INCLUDEDIRS ./pt8211/include)
list(APPEND COMPONENT_SRCS ./pt8211/pt8211.c)
endif()
endif()
register_component()

View File

@@ -1,193 +1 @@
menu "Custom Audio Board"
depends on AUDIO_BOARD_CUSTOM
choice GENERIC_BOARD_DAC
prompt "DAC chip"
default DAC_MA120
help
Select a DAC connected to the generic ESP32 board
config DAC_PCM51XX
bool "TI PCM51XX/TAS57XX based DAC"
config DAC_PCM5102A
bool "TI PCM5102A based DAC"
config DAC_MA120
bool "Infineon MA120 ClassD AMP"
config DAC_MA120X0
bool "Infineon MA120X0 ClassD AMP"
config DAC_ADAU1961
bool "Analog Devices ADAU1961 DAC"
config DAC_MAX98357
bool "Analog Devices MAX98357 DAC"
endchoice
menu "DAC I2C control interface"
config DAC_I2C_SDA
int "SDA pin"
default 12 if DAC_ADAU1961
default 21 if DAC_MA120 || DAC_PCM51XX || DAC_MA120 || DAC_MA120X0 || DAC_MAX98357 || DAC_PCM5102A
help
I2C SDA pin of the DAC control interface
config DAC_I2C_SCL
int "SCL pin"
default 14 if DAC_ADAU1961
default 22 if DAC_MA120 || DAC_PCM51XX || DAC_MA120 || DAC_MA120X0 || DAC_MAX98357 || DAC_PCM5102A
help
I2C SCL pin of the DAC control interface
config DAC_I2C_ADDR
hex "I2C address"
default 0x70 if DAC_ADAU1961
default 0x20 if DAC_MA120 || DAC_PCM51XX || DAC_MA120 || DAC_MA120X0 || DAC_MAX98357 || DAC_PCM5102A
help
I2C Address of the DAC control interface
endmenu
menu "I2S master interface"
config MASTER_I2S_MCLK_PIN
int "Master i2s mclk"
default 3 if DAC_ADAU1961
default 0
help
Master audio interface master clock.
config MASTER_I2S_BCK_PIN
int "Master i2s bck"
default 15 if DAC_ADAU1961
default 23 if DAC_MAX98357
default 23
help
Master audio interface bit clock.
config MASTER_I2S_LRCK_PIN
int "Master i2s lrck"
default 13 if DAC_ADAU1961
default 24 if DAC_MAX98357
default 13
help
Master audio interface left/right sync clock.
config MASTER_I2S_DATAOUT_PIN
int "Master i2s data out"
default 4 if DAC_ADAU1961
default 25 if DAC_MAX98357
default 14
help
Master audio interface data out.
endmenu
menu "I2S slave interface"
config SLAVE_I2S_MCLK_PIN
int "Slave i2s mclk"
default 0
help
Slave audio interface master clock.
config SLAVE_I2S_BCK_PIN
int "Slave i2s bck"
default 26
help
Slave audio interface bit clock.
config SLAVE_I2S_LRCK_PIN
int "Slave i2s lrck"
default 12
help
Slave audio interface left/right sync clock.
config SLAVE_I2S_DATAOUT_PIN
int "Slave i2s data out"
default 5
help
Slave audio interface data out.
endmenu
menu "Merus MA120x0 interface Configuration"
depends on DAC_MA120X0
config MA120X0_NENABLE_PIN
int "Master enable/disable for ma120x0"
default 16
help
GPIO number to control enable/disable.
config MA120X0_NMUTE_PIN
int "Master mute/unmute for ma120x0"
default 2
help
GPIO number to controm mute/unmute.
config MA120X0_NERR_PIN
int "NERR monitor pin"
default 21
help
GPIO number to monitor NERROR.
config MA120X0_NCLIP_PIN
int "Clip indication pin"
default 22
help
GPIO number low if clip observed
endmenu
menu "Merus MA120 interface Configuration"
depends on DAC_MA120
config MA120_ENABLE_PIN
int "Master enable/disable for ma120x0"
default 16
help
GPIO number to control enable/disable.
config MA120_NMUTE_PIN
int "Master mute/unmute for ma120x0"
default 2
help
GPIO number to controm mute/unmute.
config MERUS_NERR_PIN
int "NERR monitor pin"
default 21
help
GPIO number to monitor NERROR.
config MERUS_NCLIP_PIN
int "Clip indication pin"
default 22
help
GPIO number low if clip observed
endmenu
menu "TI PCM5102A interface Configuration"
depends on DAC_PCM5102A
config PCM5102A_MUTE_PIN
int "Master mute/unmute for PCM5102A"
default 18
help
GPIO number to control mute/unmute.
This is labeled "X(S)MT" on chip/boards
endmenu
menu "MAX98357 interface Configuration"
depends on DAC_MAX98357
config MAX98357_MUTE_PIN
int "Master mute/mode for MAX98357"
default 18
help
GPIO number to control mute/mode. This require a special resistor to select the correct mode.
You need to put a serie resistor to select the mode (GPIO --> Resistor --> SD):
LEFT only : 0ohm (direct connection)
RIGHT only : 220Kohm
(L+R)/2 : 1Mohm
Refer to Analog Devices' doc for more infos.
This is labeled "SD" on chip/boards.
endmenu
endmenu
# this was moved to audio_board

View File

@@ -27,4 +27,14 @@ COMPONENT_ADD_INCLUDEDIRS += ./max98357/include
COMPONENT_SRCDIRS += ./max98357
endif
ifdef CONFIG_DAC_TAS5805M
COMPONENT_ADD_INCLUDEDIRS += ./tas5805m/include
COMPONENT_SRCDIRS += ./tas5805m
endif
ifdef CONFIG_DAC_PT8211
COMPONENT_ADD_INCLUDEDIRS += ./pt8211/include
COMPONENT_SRCDIRS += ./pt8211
endif
endif

View File

@@ -49,6 +49,12 @@ extern audio_hal_func_t AUDIO_CODEC_ADAU1961_DEFAULT_HANDLE;
#elif CONFIG_DAC_MAX98357
extern audio_hal_func_t AUDIO_CODEC_MAX98357_DEFAULT_HANDLE;
#define AUDIO_CODEC_DEFAULT_HANDLE AUDIO_CODEC_MAX98357_DEFAULT_HANDLE
#elif CONFIG_DAC_TAS5805M
extern audio_hal_func_t AUDIO_CODEC_TAS5805M_DEFAULT_HANDLE;
#define AUDIO_CODEC_DEFAULT_HANDLE AUDIO_CODEC_TAS5805M_DEFAULT_HANDLE
#elif CONFIG_DAC_PT8211
extern audio_hal_func_t AUDIO_CODEC_PT8211_DEFAULT_HANDLE;
#define AUDIO_CODEC_DEFAULT_HANDLE AUDIO_CODEC_PT8211_DEFAULT_HANDLE
#endif
static const char *TAG = "AUDIO_BOARD";

View File

@@ -271,7 +271,8 @@ esp_err_t ma_write(uint8_t i2c_addr, uint8_t prot, uint16_t address,
i2c_master_write_byte(cmd, wbuf[i], ack);
}
i2c_master_stop(cmd);
int ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
int ret =
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_FAIL) {
return ret;
@@ -294,7 +295,7 @@ esp_err_t ma_write_byte(uint8_t i2c_addr, uint8_t prot, uint16_t address,
}
i2c_master_write_byte(cmd, value, ACK_VAL);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_FAIL) {
printf("ESP_I2C_WRITE ERROR : %d\n", ret);
@@ -326,7 +327,7 @@ esp_err_t ma_read(uint8_t i2c_addr, uint8_t prot, uint16_t address,
// { i2c_master_read_byte(cmd, rbuf++, ACK_VAL); }
i2c_master_read_byte(cmd, rbuf + n - 1, NACK_VAL);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 100 / portTICK_RATE_MS);
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 100 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_FAIL) {
printf("i2c Error read - readback\n");
@@ -353,7 +354,7 @@ uint8_t ma_read_byte(uint8_t i2c_addr, uint8_t prot, uint16_t address) {
i2c_master_read_byte(cmd, &value, NACK_VAL);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_FAIL) {
printf("i2c Error read - readback\n");

View File

@@ -283,7 +283,8 @@ esp_err_t ma_write(uint8_t i2c_addr, uint8_t prot, uint16_t address,
i2c_master_write_byte(cmd, wbuf[i], ack);
}
i2c_master_stop(cmd);
int ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
int ret =
i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_FAIL) {
return ret;
@@ -306,7 +307,7 @@ esp_err_t ma_write_byte(uint8_t i2c_addr, uint8_t prot, uint16_t address,
}
i2c_master_write_byte(cmd, value, ACK_VAL);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_FAIL) {
printf("ESP_I2C_WRITE ERROR : %d\n", ret);
@@ -338,7 +339,7 @@ esp_err_t ma_read(uint8_t i2c_addr, uint8_t prot, uint16_t address,
// { i2c_master_read_byte(cmd, rbuf++, ACK_VAL); }
i2c_master_read_byte(cmd, rbuf + n - 1, NACK_VAL);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 100 / portTICK_RATE_MS);
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 100 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_FAIL) {
printf("i2c Error read - readback\n");
@@ -365,7 +366,7 @@ uint8_t ma_read_byte(uint8_t i2c_addr, uint8_t prot, uint16_t address) {
i2c_master_read_byte(cmd, &value, NACK_VAL);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (ret == ESP_FAIL) {
printf("i2c Error read - readback\n");

View File

@@ -106,9 +106,9 @@ io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.intr_type = GPIO_INTR_DISABLE;
gpio_config(&io_conf);
gpio_set_level(PCM51XX_RST_GPIO, 0);
vTaskDelay(20 / portTICK_RATE_MS);
vTaskDelay(20 / portTICK_PERIOD_MS);
gpio_set_level(PCM51XX_RST_GPIO, 1);
vTaskDelay(200 / portTICK_RATE_MS);
vTaskDelay(200 / portTICK_PERIOD_MS);
*/
ret = get_i2c_pins(I2C_NUM_0, &i2c_cfg);

View File

@@ -0,0 +1,49 @@
/*
* Princeton Technology PT8211 audio hal
*/
#ifndef _PT8211_H_
#define _PT8211_H_
#include "audio_hal.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Initialize PT8211 codec chip
*/
esp_err_t pt8211_init(audio_hal_codec_config_t *codec_cfg);
/**
* Deinitialize PT8211 codec chip
*/
esp_err_t pt8211_deinit(void);
/**
* Set volume - NOT AVAILABLE
*/
esp_err_t pt8211_set_volume(int vol);
/**
* Get volume - NOT AVAILABLE
*/
esp_err_t pt8211_get_volume(int *value);
/**
* Set PT8211 mute or not
*/
esp_err_t pt8211_set_mute(bool enable);
/**
* Get PT8211 mute status - NOT IMPLEMENTED
*/
esp_err_t pt8211_get_mute(bool *enabled);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,90 @@
/*
* Princeton Technology PT8211 audio hal
*
* Mostly stubs (no I2C or volume control)
* Configuration of mute/unmute gpio in init (for external amplifier)
*/
#include "pt8211.h"
#include <driver/gpio.h>
#include "board.h"
#include "esp_log.h"
#ifndef CONFIG_PT8211_MUTE_ACTIVE_LOW
#define CONFIG_PT8211_MUTE_ACTIVE_LOW 0
#endif
static const char *TAG = "PT8211";
esp_err_t pt8211_ctrl(audio_hal_codec_mode_t mode, audio_hal_ctrl_t ctrl_state);
esp_err_t pt8211_config_iface(audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface);
audio_hal_func_t AUDIO_CODEC_PT8211_DEFAULT_HANDLE = {
.audio_codec_initialize = pt8211_init,
.audio_codec_deinitialize = pt8211_deinit,
.audio_codec_ctrl = pt8211_ctrl,
.audio_codec_config_iface = pt8211_config_iface,
.audio_codec_set_mute = pt8211_set_mute,
.audio_codec_set_volume = pt8211_set_volume,
.audio_codec_get_volume = pt8211_get_volume,
.audio_hal_lock = NULL,
.handle = NULL,
};
esp_err_t pt8211_init(audio_hal_codec_config_t *codec_cfg) {
esp_err_t ret = ESP_OK;
#if CONFIG_PT8211_MUTE_PIN != -1
gpio_config_t io_conf;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = (1ULL << CONFIG_PT8211_MUTE_PIN);
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
ret = gpio_config(&io_conf);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Mute gpio config failed for pin %d", CONFIG_PT8211_MUTE_PIN);
} else {
gpio_set_level(CONFIG_PT8211_MUTE_PIN, 0);
ESP_LOGD(TAG, "Setup mute output %d\n", CONFIG_PT8211_MUTE_PIN);
}
#else
ESP_LOGD(TAG, "Mute gpio not specified\n");
#endif
return ret;
}
esp_err_t pt8211_set_volume(int vol) { return ESP_OK; }
esp_err_t pt8211_get_volume(int *value) { return ESP_OK; }
esp_err_t pt8211_set_mute(bool enable) {
esp_err_t ret = ESP_OK;
#if CONFIG_PT8211_MUTE_PIN != -1
ret = gpio_set_level(CONFIG_PT8211_MUTE_PIN,
enable ^ CONFIG_PT8211_MUTE_ACTIVE_LOW);
#endif
return ret;
}
esp_err_t pt8211_get_mute(bool *enabled) { return ESP_OK; }
esp_err_t pt8211_deinit(void) { return gpio_reset_pin(CONFIG_PT8211_MUTE_PIN); }
esp_err_t pt8211_ctrl(audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state) {
return ESP_OK;
}
esp_err_t pt8211_config_iface(audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface) {
return ESP_OK;
}

View File

@@ -0,0 +1,146 @@
/*
* 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"
#include "esp_log.h"
#include "board.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define I2C_MASTER_FREQ_HZ 400000 /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_TIMEOUT_MS 1000
/* Represented in % */
#define TAS5805M_VOLUME_MIN 0
#define TAS5805M_VOLUME_MAX 100
#define TAS5805M_VOLUME_MUTE 255
/* See here for the original Implementation : audio_hal/driver/tas5805m */
/* Its not from me it was developed by Espressif */
/* Volume steps tas5805m_volume[0] => 255 which means mute */
static const uint8_t tas5805m_volume[]
= { 0xff, 0x9f, 0x8f, 0x7f, 0x6f, 0x5f, 0x5c, 0x5a, 0x58, 0x54, 0x50,
0x4c, 0x4a, 0x48, 0x44, 0x40, 0x3d, 0x3b, 0x39, 0x37, 0x35 };
int8_t currentVolume = 0; // Last Volume gets updated after a change or before a mute
/**
* @brief Initialize TAS5805 codec chip
*
* @param cfg configuration of TAS5805
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t tas5805m_init ();
/**
* @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 *vol);
/**
* @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 TAS5805M
*
* @param value Time for mute with millisecond.
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*
*/
/**
* @brief Get TAS5805 mute status
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t tas5805m_get_mute (bool *enabled);
esp_err_t tas5805m_ctrl(audio_hal_codec_mode_t mode,
audio_hal_ctrl_t ctrl_state);
esp_err_t tas5805m_config_iface(audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,100 @@
/*
* 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_REG_CFG_
#define _TAS5805M_REG_CFG_
#ifdef __cplusplus
extern "C"
{
#endif
/* Register Naming*/
#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
#define ACK_VAL I2C_MASTER_ACK /*!< I2C ack value */
#define NACK_VAL I2C_MASTER_NACK /*!< I2C nack value */
#define I2C_TAS5805M_MASTER_NUM I2C_MASTER_NUM /*!< I2C port number for master dev */
#define TAS5805M_ADDRESS 0x2D /*!< 7-bit address with a 15k pull up resistor */
#ifdef PIN_DAC_PWDN
#define TAS5805M_GPIO_PDN PIN_DAC_PWDN
#else
#define TAS5805M_GPIO_PDN GPIO_NUM_33 /*!< GPIO used for !PDN pin */
#endif
#define TAS5805M_GPIO_PDN_MASK ((1ULL << TAS5805M_GPIO_PDN))
#define TAS5805M_RESET_CTRL_REGISTER 0x01
#define TAS5805M_DEVICE_CTRL_1_REGISTER 0x02
#define TAS5805M_DEVICE_CTRL_2_REGISTER 0x03
#define TAS5805M_I2C_PAGE_AUTO_INC_REGISTER 0x0f
#define TAS5805M_SIG_CH_CTRL_REGISTER 0x28
#define TAS5805M_CLOCK_DET_CTRL_REGISTER 0x29
#define TAS5805M_SDOUT_SEL_REGISTER 0x30
#define TAS5805M_I2S_CTRL_REGISTER 0x31
#define TAS5805M_SAP_CTRL1_REGISTER 0x33
#define TAS5805M_SAP_CTRL2_REGISTER 0x34
#define TAS5805M_SAP_CTRL3_REGISTER 0x35
#define TAS5805M_FS_MON_REGISTER 0x37
#define TAS5805M_BCK_MON_REGISTER 0x38
#define TAS5805M_CLKDET_STATUS_REGISTER 0x39
#define TAS5805M_CHANNEL_FORCE_HIZ_REGISTER 0x40
#define TAS5805M_DIG_VOL_CTRL_REGISTER 0x4c
#define TAS5805M_DIG_VOL_CTRL2_REGISTER 0x4e
#define TAS5805M_DIG_VOL_CTRL3_REGISTER 0x4f
#define TAS5805M_AUTO_MUTE_CTRL_REGISTER 0x50
#define TAS5805M_AUTO_MUTE_TIME_REGISTER 0x51
#define TAS5805M_ANA_CTRL_REGISTER 0x53
#define TAS5805M_AGAIN_REGISTER 0x54
#define TAS5805M_BQ_WR_CTRL1_REGISTER 0x5c
#define TAS5805M_DAC_CTRL_REGISTER 0x5d
#define TAS5805M_ADR_PIN_CTRL_REGISTER 0x60
#define TAS5805M_ADR_PIN_CONFIG_REGISTER 0x61
#define TAS5805M_DSP_MISC_REGISTER 0x66
#define TAS5805M_DIE_ID_REGISTER 0x67
#define TAS5805M_POWER_STATE_REGISTER 0x68
#define TAS5805M_AUTOMUTE_STATE_REGISTER 0x69
#define TAS5805M_PHASE_CTRL_REGISTER 0x6a
#define TAS5805M_SS_CTRL0_REGISTER 0x6b
#define TAS5805M_SS_CTRL1_REGISTER 0x6c
#define TAS5805M_SS_CTRL2_REGISTER 0x6d
#define TAS5805M_SS_CTRL3_REGISTER 0x6e
#define TAS5805M_SS_CTRL4_REGISTER 0x6f
#define TAS5805M_CHAN_FAULT_REGISTER 0x70
#define TAS5805M_GLOBAL_FAULT1_REGISTER 0x71
#define TAS5805M_GLOBAL_FAULT2_REGISTER 0x72
#define TAS5805M_OT_WARNING_REGISTER 0x73
#define TAS5805M_PIN_CONTROL1_REGISTER 0x74
#define TAS5805M_PIN_CONTROL2_REGISTER 0x75
#define TAS5805M_MISC_CONTROL_REGISTER 0x76
#define TAS5805M_FAULT_CLEAR_REGISTER 0x78
#endif

View File

@@ -0,0 +1,260 @@
/*
* 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 "esp_log.h"
#include "i2c_bus.h"
#include "tas5805m_reg_cfg.h"
static const char *TAG = "TAS5805M";
/* Default I2C config */
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 = I2C_MASTER_FREQ_HZ,
};
/*
* 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_config_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,
};
/* Init the I2C Driver */
void i2c_master_init() {
int i2c_master_port = I2C_MASTER_NUM;
ESP_ERROR_CHECK(get_i2c_pins(I2C_NUM_0, &i2c_cfg));
ESP_ERROR_CHECK(i2c_param_config(i2c_master_port, &i2c_cfg));
ESP_ERROR_CHECK(i2c_driver_install(i2c_master_port, i2c_cfg.mode,
I2C_MASTER_RX_BUF_DISABLE,
I2C_MASTER_TX_BUF_DISABLE, 0));
}
/* Helper Functions */
// Reading of TAS5805M-Register
esp_err_t tas5805m_read_byte(uint8_t register_name, uint8_t *data) {
int ret;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, TAS5805M_ADDRESS << 1 | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write_byte(cmd, register_name, ACK_CHECK_EN);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(I2C_TAS5805M_MASTER_NUM, cmd,
1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "I2C ERROR");
}
vTaskDelay(1 / portTICK_PERIOD_MS);
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, TAS5805M_ADDRESS << 1 | READ_BIT, ACK_CHECK_EN);
i2c_master_read_byte(cmd, data, NACK_VAL);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(I2C_TAS5805M_MASTER_NUM, cmd,
1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
// Writing of TAS5805M-Register
esp_err_t tas5805m_write_byte(uint8_t register_name, uint8_t value) {
int ret = 0;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, TAS5805M_ADDRESS << 1 | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write_byte(cmd, register_name, ACK_CHECK_EN);
i2c_master_write_byte(cmd, value, ACK_CHECK_EN);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(I2C_TAS5805M_MASTER_NUM, cmd,
1000 / portTICK_PERIOD_MS);
// Check if ret is OK
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Fehler bei der I2C-Übertragung: %s", esp_err_to_name(ret));
}
i2c_cmd_link_delete(cmd);
return ret;
}
// Inits the TAS5805M change Settings in Menuconfig to enable Bridge-Mode
esp_err_t tas5805m_init() {
int ret = 0;
// Init the I2C-Driver
i2c_master_init();
/* Register the PDN pin as output and write 1 to enable the TAS chip */
/* TAS5805M.INIT() */
gpio_config_t io_conf;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = TAS5805M_GPIO_PDN_MASK;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
ESP_LOGW(TAG, "Power down pin: %d", TAS5805M_GPIO_PDN);
gpio_config(&io_conf);
gpio_set_level(TAS5805M_GPIO_PDN, 0);
vTaskDelay(10 / portTICK_PERIOD_MS);
gpio_set_level(TAS5805M_GPIO_PDN, 1);
vTaskDelay(10 / portTICK_PERIOD_MS);
/* TAS5805M.Begin()*/
ESP_LOGW(TAG, "Setting to HI Z");
ESP_ERROR_CHECK(tas5805m_write_byte(TAS5805M_DEVICE_CTRL_2_REGISTER, 0x02));
vTaskDelay(10 / portTICK_PERIOD_MS);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "TAS5805M_DEVICE_CTRL_2_REGISTER, 0x02 FAILED!!!");
return ret;
}
ESP_LOGW(TAG, "Setting to PLAY");
ret = tas5805m_write_byte(TAS5805M_DEVICE_CTRL_2_REGISTER, 0x03);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "TAS5805M_DEVICE_CTRL_2_REGISTER, 0x03 FAILED!!");
return ret;
}
// Check if Bridge-Mode is enabled
#ifdef CONFIG_DAC_BRIDGE_MODE
uint8_t value = 0;
ret = tas5805m_read_byte(TAS5805M_DEVICE_CTRL_1_REGISTER, &value);
if (ret != ESP_OK) return ret;
value = 0b100;
ret = tas5805m_write_byte(TAS5805M_DEVICE_CTRL_1_REGISTER, value);
if (ret != ESP_OK) return ret;
#endif
return ret;
}
// Setting the Volume
esp_err_t tas5805m_set_volume(int vol) {
int vol_idx = 0; // Temp-Variable
/* Checking if Volume is bigger or smaller than the max values */
if (vol < TAS5805M_VOLUME_MIN) {
vol = TAS5805M_VOLUME_MIN;
}
if (vol > TAS5805M_VOLUME_MAX) {
vol = TAS5805M_VOLUME_MAX;
}
/* Mapping the Values from 0-100 to 254-0 */
vol_idx = vol / 5;
/* Updating the global volume Variable */
currentVolume = vol_idx;
/* Writing the Volume to the Register*/
return tas5805m_write_byte(TAS5805M_DIG_VOL_CTRL_REGISTER,
tas5805m_volume[vol_idx]);
}
esp_err_t tas5805m_get_volume(int *vol) {
esp_err_t ret = ESP_OK;
uint8_t rxbuf = 0;
ret = tas5805m_read_byte(TAS5805M_DIG_VOL_CTRL_REGISTER, &rxbuf);
int i;
for (i = 0; i < sizeof(tas5805m_volume); i++) {
if (rxbuf >= tas5805m_volume[i]) break;
}
/* Updating the global volume Variable */
currentVolume = i;
ESP_LOGI(TAG, "Volume is %d", i * 5);
*vol = 5 * i; // Converting it to percent
return ret;
}
esp_err_t tas5805m_deinit(void) {
// TODO
return ESP_OK;
}
esp_err_t tas5805m_set_mute(bool enable) {
if (enable == true) {
// Set the Volume to 255 to enable the MUTE
return tas5805m_write_byte(TAS5805M_DIG_VOL_CTRL_REGISTER,
TAS5805M_VOLUME_MUTE);
} else {
return tas5805m_write_byte(
TAS5805M_DIG_VOL_CTRL_REGISTER,
tas5805m_volume[currentVolume]); // Restore Volume to its old value
}
return ESP_OK;
}
esp_err_t tas5805m_get_mute(bool *enabled) {
int currentVolume;
if (tas5805m_get_volume(&currentVolume) != ESP_OK) {
ESP_LOGW(TAG, "Cant get volume in get-Mute-Function");
}
if (currentVolume == TAS5805M_VOLUME_MUTE) {
*enabled = true;
} else {
*enabled = false;
}
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_config_iface(audio_hal_codec_mode_t mode,
audio_hal_codec_i2s_iface_t *iface) {
// TODO
return ESP_OK;
}

View File

@@ -1,6 +1,10 @@
#ifndef _DSP_PROCESSOR_H_
#define _DSP_PROCESSOR_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_err.h"
typedef enum dspFlows {
@@ -64,4 +68,8 @@ int dsp_processor_worker(char *audio, size_t chunk_size, uint32_t samplerate);
esp_err_t dsp_processor_update_filter_params(filterParams_t *params);
void dsp_processor_set_volome(double volume);
#ifdef __cplusplus
}
#endif
#endif /* _DSP_PROCESSOR_H_ */

View File

@@ -33,7 +33,6 @@
#include "audio_mutex.h"
#include "driver/i2c.h"
#include "esp_log.h"
#include "freertos/projdefs.h"
#define ESP_INTR_FLG_DEFAULT (0)
#define ESP_I2C_MASTER_BUF_LEN (0)
@@ -117,7 +116,7 @@ esp_err_t i2c_bus_write_bytes(i2c_bus_handle_t bus, int addr, uint8_t *reg,
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, pdMS_TO_TICKS(1000));
ret |= i2c_master_cmd_begin(p_bus->i2c_port, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
mutex_unlock(p_bus->bus_lock);
I2C_BUS_CHECK(ret == 0, "I2C Bus WriteReg Error", ESP_FAIL);
@@ -137,7 +136,7 @@ esp_err_t i2c_bus_write_data(i2c_bus_handle_t bus, int addr, uint8_t *data,
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, pdMS_TO_TICKS(1000));
ret |= i2c_master_cmd_begin(p_bus->i2c_port, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
mutex_unlock(p_bus->bus_lock);
I2C_BUS_CHECK(ret == 0, "I2C Bus WriteReg Error", ESP_FAIL);
@@ -159,7 +158,7 @@ esp_err_t i2c_bus_read_bytes(i2c_bus_handle_t bus, int addr, uint8_t *reg,
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, pdMS_TO_TICKS(1000));
ret |= i2c_master_cmd_begin(p_bus->i2c_port, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
cmd = i2c_cmd_link_create();
@@ -172,7 +171,7 @@ esp_err_t i2c_bus_read_bytes(i2c_bus_handle_t bus, int addr, uint8_t *reg,
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, pdMS_TO_TICKS(1000));
ret |= i2c_master_cmd_begin(p_bus->i2c_port, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
mutex_unlock(p_bus->bus_lock);

View File

@@ -38,7 +38,7 @@
static const char *TAG = "ESP_PERIPH";
#define DEFAULT_ESP_PERIPH_WAIT_TICK (10 / portTICK_RATE_MS)
#define DEFAULT_ESP_PERIPH_WAIT_TICK (10 / portTICK_PERIOD_MS)
struct esp_periph {
char *tag;
@@ -57,7 +57,7 @@ struct esp_periph {
typedef struct esp_periph_sets {
EventGroupHandle_t state_event_bits;
xSemaphoreHandle lock;
SemaphoreHandle_t lock;
int task_stack;
int task_prio;
int task_core;
@@ -93,7 +93,7 @@ esp_err_t esp_periph_set_change_waiting_time(
esp_periph_set_handle_t periph_set_handle, int time_ms) {
audio_event_iface_set_cmd_waiting_timeout(
esp_periph_set_get_event_iface(periph_set_handle),
time_ms / portTICK_RATE_MS);
time_ms / portTICK_PERIOD_MS);
return ESP_OK;
}

View File

@@ -106,7 +106,7 @@ static esp_err_t _button_init(esp_periph_handle_t self) {
};
periph_btn->btn = button_init(&btn_config);
esp_periph_start_timer(self, 50 / portTICK_RATE_MS, button_timer_handler);
esp_periph_start_timer(self, 50 / portTICK_PERIOD_MS, button_timer_handler);
return ret;
}

View File

@@ -218,7 +218,7 @@ static void _console_task(void *pv) {
printf("\r\n%s ", prompt_string);
while (console->run) {
if (console_get_line(console, console->buffer_size,
10 / portTICK_RATE_MS)) {
10 / portTICK_PERIOD_MS)) {
if (console->total_bytes) {
ESP_LOGD(TAG, "Read line: %s", console->buffer);
}

View File

@@ -234,7 +234,7 @@ esp_err_t periph_led_blink(esp_periph_handle_t periph, int gpio_num,
}
ch->stop = false;
ch->level = level;
esp_periph_start_timer(periph, portTICK_RATE_MS, led_timer_handler);
esp_periph_start_timer(periph, portTICK_PERIOD_MS, led_timer_handler);
return ESP_OK;
}

View File

@@ -98,7 +98,7 @@ static esp_err_t _sdcard_init(esp_periph_handle_t self) {
} else {
ESP_LOGE(TAG, "no sdcard detect");
}
esp_periph_start_timer(self, 1000 / portTICK_RATE_MS, sdcard_timer_handler);
esp_periph_start_timer(self, 1000 / portTICK_PERIOD_MS, sdcard_timer_handler);
return ESP_OK;
}

View File

@@ -346,9 +346,9 @@ static void _wifi_event_callback(void *arg, esp_event_base_t event_base,
if (periph_wifi->disable_auto_reconnect) {
return;
}
esp_periph_start_timer(self,
periph_wifi->reconnect_timeout_ms / portTICK_RATE_MS,
wifi_reconnect_timer);
esp_periph_start_timer(
self, periph_wifi->reconnect_timeout_ms / portTICK_PERIOD_MS,
wifi_reconnect_timer);
} else {
ESP_LOGW(TAG, "WiFi Event cb, Unhandle event_base:%s, event_id:%d",
@@ -395,10 +395,12 @@ static esp_err_t _wifi_event_callback(void *ctx, system_event_t *event) {
break;
}
esp_periph_start_timer(
self, periph_wifi->reconnect_timeout_ms / portTICK_RATE_MS,
self, periph_wifi->reconnect_timeout_ms / portTICK_PERIOD_MS,
wifi_reconnect_timer);
break;
default:
ESP_LOGW(TAG, "WiFi Event cb, Unhandled event_id: 0x%08X",
event->event_id);
break;
}
return ESP_OK;

View File

@@ -90,7 +90,7 @@ typedef struct periph_ws2812 {
periph_rgb_value *color;
uint32_t led_num;
TimerHandle_t timer;
xSemaphoreHandle sem;
SemaphoreHandle_t sem;
intr_handle_t rmt_intr_handle;
periph_ws2812_state_t *state;
periph_ws2812_process_t process;
@@ -404,7 +404,7 @@ esp_err_t periph_ws2812_control(esp_periph_handle_t periph,
periph_ws2812->state[i].mode = control_cfg[i].mode;
}
esp_periph_start_timer(periph, INTERVAL_TIME_MS / portTICK_RATE_MS,
esp_periph_start_timer(periph, INTERVAL_TIME_MS / portTICK_PERIOD_MS,
ws2812_timer_handler);
return ESP_OK;

View File

@@ -214,7 +214,7 @@ static void periph_console_test(void) {
TEST_ASSERT_FALSE(esp_periph_start(set, console_handle));
while (task_flag) {
vTaskDelay(10 / portTICK_RATE_MS);
vTaskDelay(10 / portTICK_PERIOD_MS);
}
ESP_LOGI(TAG, "Quit test, release all resources");
@@ -295,7 +295,7 @@ static void periph_is31fl3216_test(void) {
periph_is31fl3216_set_state(is31fl3216_handle, IS31FL3216_STATE_SHIFT));
ESP_LOGI(TAG, "Start testing for 5 seconds...");
vTaskDelay(5000 / portTICK_RATE_MS);
vTaskDelay(5000 / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "Quit test, release all resources");
TEST_ASSERT_FALSE(esp_periph_set_stop_all(set));
@@ -326,11 +326,11 @@ static void periph_led_test(void) {
false, 4, 0));
ESP_LOGI(TAG, "running...");
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "STOP BLUE LED");
TEST_ASSERT_FALSE(periph_led_stop(led_handle, get_blue_led_gpio()));
vTaskDelay(1000 / portTICK_RATE_MS);
vTaskDelay(1000 / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "Changing blink preset...");
TEST_ASSERT_FALSE(periph_led_blink(led_handle, get_blue_led_gpio(), 500, 200,
false, -1, 0));

View File

@@ -1,8 +1,3 @@
#if(CONFIG_SNAPCLIENT_ENABLE_ETHERNET)
idf_component_register(SRCS "eth_interface.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES driver esp_eth esp_netif)
#else()
# idf_component_register()
#endif()
idf_component_register(SRCS "eth_interface.c"
INCLUDE_DIRS "include"
REQUIRES driver esp_eth esp_netif)

View File

@@ -1,51 +1,19 @@
menu "Snapclient Ethernet Configuration"
config SNAPCLIENT_ENABLE_ETHERNET
bool "enable Ethernet"
default n
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
config SNAPCLIENT_USE_INTERNAL_ETHERNET
depends on SOC_EMAC_SUPPORTED
select ETH_USE_ESP32_EMAC
default y
bool "Internal EMAC"
help
Enable Ethernet interface
config SNAPCLIENT_USE_SPI_ETHERNET
bool
depends on SNAPCLIENT_ENABLE_ETHERNET
choice SNAPCLIENT_ETHERNET_TYPE
prompt "Ethernet Type"
default SNAPCLIENT_USE_INTERNAL_ETHERNET if IDF_TARGET_ESP32
default SNAPCLIENT_USE_W5500
depends on SNAPCLIENT_ENABLE_ETHERNET
help
Select which kind of Ethernet will be used in the example.
config SNAPCLIENT_USE_INTERNAL_ETHERNET
depends on IDF_TARGET_ESP32
select ETH_USE_ESP32_EMAC
bool "Internal EMAC"
help
Select internal Ethernet MAC controller.
config SNAPCLIENT_USE_DM9051
bool "DM9051 Module"
select SNAPCLIENT_USE_SPI_ETHERNET
select ETH_USE_SPI_ETHERNET
select ETH_SPI_ETHERNET_DM9051
help
Select external SPI-Ethernet module (DM9051).
config SNAPCLIENT_USE_W5500
bool "W5500 Module"
select SNAPCLIENT_USE_SPI_ETHERNET
select ETH_USE_SPI_ETHERNET
select ETH_SPI_ETHERNET_W5500
help
Select external SPI-Ethernet module (W5500).
endchoice # SNAPCLIENT_ETHERNET_TYPE
Use internal Ethernet MAC controller.
if SNAPCLIENT_USE_INTERNAL_ETHERNET
choice SNAPCLIENT_ETH_PHY_MODEL
prompt "Ethernet PHY Device"
default SNAPCLIENT_ETH_PHY_IP101
depends on SNAPCLIENT_ENABLE_ETHERNET
help
Select the Ethernet PHY device to use in the example.
@@ -61,11 +29,18 @@ menu "Snapclient Ethernet Configuration"
RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
config SNAPCLIENT_ETH_PHY_LAN8720
bool "LAN8720"
config SNAPCLIENT_ETH_PHY_LAN87XX
bool "LAN87xx"
help
Below chips are supported:
LAN8710A is a small footprint MII/RMII 10/100 Ethernet Transceiver with HP Auto-MDIX and
flexPWR® Technology.
LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
Goto https://www.microchip.com/LAN8720A for more information about it.
LAN8740A/LAN8741A is a small footprint MII/RMII 10/100 Energy Efficient Ethernet Transceiver
with HP Auto-MDIX and flexPWR® Technology.
LAN8742A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX and
flexPWR® Technology.
Goto https://www.microchip.com for more information about them.
config SNAPCLIENT_ETH_PHY_DP83848
bool "DP83848"
@@ -73,98 +48,202 @@ menu "Snapclient Ethernet Configuration"
DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
Goto http://www.ti.com/product/DP83848J for more information about it.
config SNAPCLIENT_ETH_PHY_KSZ8041
bool "KSZ8041"
config SNAPCLIENT_ETH_PHY_KSZ80XX
bool "KSZ80xx"
help
The KSZ8041 is a single supply 10Base-T/100Base-TX Physical Layer Transceiver.
Goto https://www.microchip.com/wwwproducts/en/KSZ8041 for more information about it.
With the KSZ80xx series, Microchip offers single-chip 10BASE-T/100BASE-TX
Ethernet Physical Layer Tranceivers (PHY).
The following chips are supported: KSZ8001, KSZ8021, KSZ8031, KSZ8041,
KSZ8051, KSZ8061, KSZ8081, KSZ8091
Goto https://www.microchip.com for more information about them.
endchoice # SNAPCLIENT_ETH_PHY_MODEL
config SNAPCLIENT_ETH_MDC_GPIO
int "SMI MDC GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 23
depends on SNAPCLIENT_ENABLE_ETHERNET
help
Set the GPIO number used by SMI MDC.
config SNAPCLIENT_ETH_MDIO_GPIO
int "SMI MDIO GPIO number"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 18
depends on SNAPCLIENT_ENABLE_ETHERNET
help
Set the GPIO number used by SMI MDIO.
config SNAPCLIENT_ETH_PHY_RST_GPIO
int "PHY Reset GPIO number"
range -1 ENV_GPIO_OUT_RANGE_MAX
default 17
help
Set the GPIO number used to reset PHY chip.
Set to -1 to disable PHY chip hardware reset.
config SNAPCLIENT_ETH_PHY_ADDR
int "PHY Address"
range 0 31
default 0
help
Set PHY address according your board schematic.
endif # SNAPCLIENT_USE_INTERNAL_ETHERNET
config SNAPCLIENT_USE_SPI_ETHERNET
bool "SPI Ethernet"
default n
select ETH_USE_SPI_ETHERNET
help
Use external SPI-Ethernet module(s).
if SNAPCLIENT_USE_SPI_ETHERNET
config SNAPCLIENT_SPI_ETHERNETS_NUM
int "Number of SPI Ethernet modules to use at a time"
range 1 2
default 1
help
Set the number of SPI Ethernet modules you want to use at a time. Multiple SPI modules can be connected
to one SPI interface and can be separately accessed based on state of associated Chip Select (CS).
choice SNAPCLIENT_ETHERNET_TYPE_SPI
prompt "Ethernet SPI"
default SNAPCLIENT_USE_W5500
help
Select which kind of Ethernet will be used in the example.
config SNAPCLIENT_USE_DM9051
bool "DM9051 Module"
select ETH_SPI_ETHERNET_DM9051
help
Select external SPI-Ethernet module (DM9051).
config SNAPCLIENT_USE_KSZ8851SNL
bool "KSZ8851SNL Module"
select ETH_SPI_ETHERNET_KSZ8851SNL
help
Select external SPI-Ethernet module (KSZ8851SNL).
config SNAPCLIENT_USE_W5500
bool "W5500 Module"
select ETH_SPI_ETHERNET_W5500
help
Select external SPI-Ethernet module (W5500).
endchoice
config SNAPCLIENT_ETH_SPI_HOST
int "SPI Host Number"
range 0 2
default 1
depends on SNAPCLIENT_ENABLE_ETHERNET
help
Set the SPI host used to communicate with the SPI Ethernet Controller.
config SNAPCLIENT_ETH_SPI_SCLK_GPIO
int "SPI SCLK GPIO number"
range 0 33
default 20
depends on SNAPCLIENT_ENABLE_ETHERNET
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 14 if IDF_TARGET_ESP32
default 12 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 6 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2
default 4 if IDF_TARGET_ESP32H2
help
Set the GPIO number used by SPI SCLK.
config SNAPCLIENT_ETH_SPI_MOSI_GPIO
int "SPI MOSI GPIO number"
range 0 33
default 19
depends on SNAPCLIENT_ENABLE_ETHERNET
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 13 if IDF_TARGET_ESP32
default 11 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 7 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2
default 5 if IDF_TARGET_ESP32H2
help
Set the GPIO number used by SPI MOSI.
config SNAPCLIENT_ETH_SPI_MISO_GPIO
int "SPI MISO GPIO number"
range 0 33
default 18
depends on SNAPCLIENT_ENABLE_ETHERNET
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
default 12 if IDF_TARGET_ESP32
default 13 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 2 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2
default 0 if IDF_TARGET_ESP32H2
help
Set the GPIO number used by SPI MISO.
config SNAPCLIENT_ETH_SPI_CS_GPIO
int "SPI CS GPIO number"
range 0 33
default 21
depends on SNAPCLIENT_ENABLE_ETHERNET
help
Set the GPIO number used by SPI CS.
config SNAPCLIENT_ETH_SPI_CLOCK_MHZ
int "SPI clock speed (MHz)"
range 5 80
default 36
depends on SNAPCLIENT_ENABLE_ETHERNET
default 12 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32H2
default 36 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
help
Set the clock speed (MHz) of SPI interface.
config SNAPCLIENT_ETH_SPI_INT_GPIO
int "Interrupt GPIO number"
default 4
depends on SNAPCLIENT_ENABLE_ETHERNET
config SNAPCLIENT_ETH_SPI_CS0_GPIO
int "SPI CS0 GPIO number for SPI Ethernet module #1"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 15 if IDF_TARGET_ESP32
default 10 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C2
default 1 if IDF_TARGET_ESP32H2
help
Set the GPIO number used by the SPI Ethernet module interrupt line.
Set the GPIO number used by SPI CS0, i.e. Chip Select associated with the first SPI Eth module).
config SNAPCLIENT_ETH_SPI_CS1_GPIO
depends on SNAPCLIENT_SPI_ETHERNETS_NUM > 1
int "SPI CS1 GPIO number for SPI Ethernet module #2"
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
default 32 if IDF_TARGET_ESP32
default 7 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 8 if IDF_TARGET_ESP32C3
default 3 if IDF_TARGET_ESP32C2
default 11 if IDF_TARGET_ESP32H2
help
Set the GPIO number used by SPI CS1, i.e. Chip Select associated with the second SPI Eth module.
config SNAPCLIENT_ETH_SPI_INT0_GPIO
int "Interrupt GPIO number SPI Ethernet module #1"
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
default 4 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3
default 4 if IDF_TARGET_ESP32C2
default 9 if IDF_TARGET_ESP32H2
help
Set the GPIO number used by the first SPI Ethernet module interrupt line.
config SNAPCLIENT_ETH_SPI_INT1_GPIO
depends on SNAPCLIENT_SPI_ETHERNETS_NUM > 1
int "Interrupt GPIO number SPI Ethernet module #2"
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
default 33 if IDF_TARGET_ESP32
default 5 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C2
default 10 if IDF_TARGET_ESP32H2
help
Set the GPIO number used by the second SPI Ethernet module interrupt line.
config SNAPCLIENT_ETH_SPI_PHY_RST0_GPIO
int "PHY Reset GPIO number of SPI Ethernet Module #1"
range -1 ENV_GPIO_OUT_RANGE_MAX
default -1
help
Set the GPIO number used to reset PHY chip on the first SPI Ethernet module.
Set to -1 to disable PHY chip hardware reset.
config SNAPCLIENT_ETH_SPI_PHY_RST1_GPIO
depends on SNAPCLIENT_SPI_ETHERNETS_NUM > 1
int "PHY Reset GPIO number of SPI Ethernet Module #2"
range -1 ENV_GPIO_OUT_RANGE_MAX
default -1
help
Set the GPIO number used to reset PHY chip on the second SPI Ethernet module.
Set to -1 to disable PHY chip hardware reset.
config SNAPCLIENT_ETH_SPI_PHY_ADDR0
int "PHY Address of SPI Ethernet Module #1"
range 0 31
default 1
help
Set the first SPI Ethernet module PHY address according your board schematic.
config SNAPCLIENT_ETH_SPI_PHY_ADDR1
depends on SNAPCLIENT_SPI_ETHERNETS_NUM > 1
int "PHY Address of SPI Ethernet Module #2"
range 0 31
default 1
help
Set the second SPI Ethernet module PHY address according your board schematic.
endif # SNAPCLIENT_USE_SPI_ETHERNET
config SNAPCLIENT_ETH_PHY_RST_GPIO
int "PHY Reset GPIO number"
default 17
depends on SNAPCLIENT_ENABLE_ETHERNET
help
Set the GPIO number used to reset PHY chip.
Set to -1 to disable PHY chip hardware reset.
config SNAPCLIENT_ETH_PHY_ADDR
int "PHY Address"
range 0 31
default 0
depends on SNAPCLIENT_ENABLE_ETHERNET
help
Set PHY address according your board schematic.
endmenu

View File

@@ -1,15 +1,15 @@
/* Ethernet Basic Example
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "eth_interface.h"
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include "driver/gpio.h"
#include "esp_check.h"
#include "esp_eth.h"
#include "esp_event.h"
#include "esp_log.h"
@@ -19,16 +19,11 @@
#include "freertos/event_groups.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#if CONFIG_ETH_USE_SPI_ETHERNET
#if CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
#include "driver/spi_master.h"
#endif // CONFIG_ETH_USE_SPI_ETHERNET
#endif
static const char *TAG = "ETH";
static esp_eth_handle_t s_eth_handle = NULL;
static esp_eth_mac_t *s_mac = NULL;
static esp_eth_phy_t *s_phy = NULL;
static esp_eth_netif_glue_handle_t s_eth_glue = NULL;
static const char *TAG = "snapclient_eth_init";
/* The event group allows multiple bits for each event, but we only care about
* two events:
@@ -39,11 +34,324 @@ static esp_eth_netif_glue_handle_t s_eth_glue = NULL;
static EventGroupHandle_t s_eth_event_group;
#if CONFIG_SNAPCLIENT_SPI_ETHERNETS_NUM
#define SPI_ETHERNETS_NUM CONFIG_SNAPCLIENT_SPI_ETHERNETS_NUM
#else
#define SPI_ETHERNETS_NUM 0
#endif
#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET
#define INTERNAL_ETHERNETS_NUM 1
#else
#define INTERNAL_ETHERNETS_NUM 0
#endif
#define INIT_SPI_ETH_MODULE_CONFIG(eth_module_config, num) \
do { \
eth_module_config[num].spi_cs_gpio = \
CONFIG_SNAPCLIENT_ETH_SPI_CS##num##_GPIO; \
eth_module_config[num].int_gpio = \
CONFIG_SNAPCLIENT_ETH_SPI_INT##num##_GPIO; \
eth_module_config[num].phy_reset_gpio = \
CONFIG_SNAPCLIENT_ETH_SPI_PHY_RST##num##_GPIO; \
eth_module_config[num].phy_addr = CONFIG_SNAPCLIENT_ETH_SPI_PHY_ADDR##num; \
} while (0)
typedef struct {
uint8_t spi_cs_gpio;
uint8_t int_gpio;
int8_t phy_reset_gpio;
uint8_t phy_addr;
uint8_t *mac_addr;
} spi_eth_module_config_t;
#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET
/**
* @brief Internal ESP32 Ethernet initialization
*
* @param[out] mac_out optionally returns Ethernet MAC object
* @param[out] phy_out optionally returns Ethernet PHY object
* @return
* - esp_eth_handle_t if init succeeded
* - NULL if init failed
*/
static esp_eth_handle_t eth_init_internal(esp_eth_mac_t **mac_out,
esp_eth_phy_t **phy_out) {
esp_eth_handle_t ret = NULL;
// Init common MAC and PHY configs to default
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
// Update PHY config based on board specific configuration
phy_config.phy_addr = CONFIG_SNAPCLIENT_ETH_PHY_ADDR;
phy_config.reset_gpio_num = CONFIG_SNAPCLIENT_ETH_PHY_RST_GPIO;
// Init vendor specific MAC config to default
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
// Update vendor specific MAC config based on board configuration
esp32_emac_config.smi_mdc_gpio_num = CONFIG_SNAPCLIENT_ETH_MDC_GPIO;
esp32_emac_config.smi_mdio_gpio_num = CONFIG_SNAPCLIENT_ETH_MDIO_GPIO;
// Set clock mode and GPIO
#if CONFIG_ETH_RMII_CLK_INPUT
esp32_emac_config.clock_config.rmii.clock_mode = EMAC_CLK_EXT_IN;
#elif CONFIG_ETH_RMII_CLK_OUTPUT
esp32_emac_config.clock_config.rmii.clock_mode = EMAC_CLK_EXT_OUT;
#else
esp32_emac_config.clock_config.rmii.clock_mode = EMAC_CLK_DEFAULT;
#endif
esp32_emac_config.clock_config.rmii.clock_gpio = CONFIG_ETH_RMII_CLK_IN_GPIO;
// Create new ESP32 Ethernet MAC instance
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
// Create new PHY instance based on board configuration
#if CONFIG_SNAPCLIENT_ETH_PHY_IP101
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
#elif CONFIG_SNAPCLIENT_ETH_PHY_RTL8201
esp_eth_phy_t *phy = esp_eth_phy_new_rtl8201(&phy_config);
#elif CONFIG_SNAPCLIENT_ETH_PHY_LAN87XX
esp_eth_phy_t *phy = esp_eth_phy_new_lan87xx(&phy_config);
#elif CONFIG_SNAPCLIENT_ETH_PHY_DP83848
esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config);
#elif CONFIG_SNAPCLIENT_ETH_PHY_KSZ80XX
esp_eth_phy_t *phy = esp_eth_phy_new_ksz80xx(&phy_config);
#endif
// Init Ethernet driver to default and install it
esp_eth_handle_t eth_handle = NULL;
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
ESP_GOTO_ON_FALSE(esp_eth_driver_install(&config, &eth_handle) == ESP_OK,
NULL, err, TAG, "Ethernet driver install failed");
if (mac_out != NULL) {
*mac_out = mac;
}
if (phy_out != NULL) {
*phy_out = phy;
}
return eth_handle;
err:
if (eth_handle != NULL) {
esp_eth_driver_uninstall(eth_handle);
}
if (mac != NULL) {
mac->del(mac);
}
if (phy != NULL) {
phy->del(phy);
}
return ret;
}
#endif // CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET
#if CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
/**
* @brief SPI bus initialization (to be used by Ethernet SPI modules)
*
* @return
* - ESP_OK on success
*/
static esp_err_t spi_bus_init(void) {
esp_err_t ret = ESP_OK;
// Install GPIO ISR handler to be able to service SPI Eth modules interrupts
ret = gpio_install_isr_service(0);
if (ret != ESP_OK) {
if (ret == ESP_ERR_INVALID_STATE) {
ESP_LOGW(TAG, "GPIO ISR handler has been already installed");
ret = ESP_OK; // ISR handler has been already installed so no issues
} else {
ESP_LOGE(TAG, "GPIO ISR handler install failed");
goto err;
}
}
// Init SPI bus
spi_bus_config_t buscfg = {
.miso_io_num = CONFIG_SNAPCLIENT_ETH_SPI_MISO_GPIO,
.mosi_io_num = CONFIG_SNAPCLIENT_ETH_SPI_MOSI_GPIO,
.sclk_io_num = CONFIG_SNAPCLIENT_ETH_SPI_SCLK_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
};
ESP_GOTO_ON_ERROR(spi_bus_initialize(CONFIG_SNAPCLIENT_ETH_SPI_HOST, &buscfg,
SPI_DMA_CH_AUTO),
err, TAG, "SPI host #%d init failed",
CONFIG_SNAPCLIENT_ETH_SPI_HOST);
err:
return ret;
}
/**
* @brief Ethernet SPI modules initialization
*
* @param[in] spi_eth_module_config specific SPI Ethernet module configuration
* @param[out] mac_out optionally returns Ethernet MAC object
* @param[out] phy_out optionally returns Ethernet PHY object
* @return
* - esp_eth_handle_t if init succeeded
* - NULL if init failed
*/
static esp_eth_handle_t eth_init_spi(
spi_eth_module_config_t *spi_eth_module_config, esp_eth_mac_t **mac_out,
esp_eth_phy_t **phy_out) {
esp_eth_handle_t ret = NULL;
// Init common MAC and PHY configs to default
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
// Update PHY config based on board specific configuration
phy_config.phy_addr = spi_eth_module_config->phy_addr;
phy_config.reset_gpio_num = spi_eth_module_config->phy_reset_gpio;
// Configure SPI interface for specific SPI module
spi_device_interface_config_t spi_devcfg = {
.mode = 0,
.clock_speed_hz = CONFIG_SNAPCLIENT_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
.queue_size = 20,
.spics_io_num = spi_eth_module_config->spi_cs_gpio};
// Init vendor specific MAC config to default, and create new SPI Ethernet MAC
// instance and new PHY instance based on board configuration
#if CONFIG_SNAPCLIENT_USE_KSZ8851SNL
eth_ksz8851snl_config_t ksz8851snl_config = ETH_KSZ8851SNL_DEFAULT_CONFIG(
CONFIG_SNAPCLIENT_ETH_SPI_HOST, &spi_devcfg);
ksz8851snl_config.int_gpio_num = spi_eth_module_config->int_gpio;
esp_eth_mac_t *mac =
esp_eth_mac_new_ksz8851snl(&ksz8851snl_config, &mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_ksz8851snl(&phy_config);
#elif CONFIG_SNAPCLIENT_USE_DM9051
eth_dm9051_config_t dm9051_config =
ETH_DM9051_DEFAULT_CONFIG(CONFIG_SNAPCLIENT_ETH_SPI_HOST, &spi_devcfg);
dm9051_config.int_gpio_num = spi_eth_module_config->int_gpio;
esp_eth_mac_t *mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_dm9051(&phy_config);
#elif CONFIG_SNAPCLIENT_USE_W5500
eth_w5500_config_t w5500_config =
ETH_W5500_DEFAULT_CONFIG(CONFIG_SNAPCLIENT_ETH_SPI_HOST, &spi_devcfg);
w5500_config.int_gpio_num = spi_eth_module_config->int_gpio;
esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);
#endif // CONFIG_SNAPCLIENT_USE_W5500
// Init Ethernet driver to default and install it
esp_eth_handle_t eth_handle = NULL;
esp_eth_config_t eth_config_spi = ETH_DEFAULT_CONFIG(mac, phy);
ESP_GOTO_ON_FALSE(
esp_eth_driver_install(&eth_config_spi, &eth_handle) == ESP_OK, NULL, err,
TAG, "SPI Ethernet driver install failed");
// The SPI Ethernet module might not have a burned factory MAC address, we can
// set it manually.
if (spi_eth_module_config->mac_addr != NULL) {
ESP_GOTO_ON_FALSE(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR,
spi_eth_module_config->mac_addr) == ESP_OK,
NULL, err, TAG, "SPI Ethernet MAC address config failed");
}
if (mac_out != NULL) {
*mac_out = mac;
}
if (phy_out != NULL) {
*phy_out = phy;
}
return eth_handle;
err:
if (eth_handle != NULL) {
esp_eth_driver_uninstall(eth_handle);
}
if (mac != NULL) {
mac->del(mac);
}
if (phy != NULL) {
phy->del(phy);
}
return ret;
}
#endif // CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
/** Original init function in the example */
esp_err_t original_eth_init(esp_eth_handle_t *eth_handles_out[],
uint8_t *eth_cnt_out) {
esp_err_t ret = ESP_OK;
esp_eth_handle_t *eth_handles = NULL;
uint8_t eth_cnt = 0;
#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \
CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
ESP_GOTO_ON_FALSE(
eth_handles_out != NULL && eth_cnt_out != NULL, ESP_ERR_INVALID_ARG, err,
TAG,
"invalid arguments: initialized handles array or number of interfaces");
eth_handles = calloc(SPI_ETHERNETS_NUM + INTERNAL_ETHERNETS_NUM,
sizeof(esp_eth_handle_t));
ESP_GOTO_ON_FALSE(eth_handles != NULL, ESP_ERR_NO_MEM, err, TAG, "no memory");
#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET
eth_handles[eth_cnt] = eth_init_internal(NULL, NULL);
ESP_GOTO_ON_FALSE(eth_handles[eth_cnt], ESP_FAIL, err, TAG,
"internal Ethernet init failed");
eth_cnt++;
#endif // CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET
#if CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
ESP_GOTO_ON_ERROR(spi_bus_init(), err, TAG, "SPI bus init failed");
// Init specific SPI Ethernet module configuration from Kconfig (CS GPIO,
// Interrupt GPIO, etc.)
spi_eth_module_config_t
spi_eth_module_config[CONFIG_SNAPCLIENT_SPI_ETHERNETS_NUM] = {0};
INIT_SPI_ETH_MODULE_CONFIG(spi_eth_module_config, 0);
// The SPI Ethernet module(s) might not have a burned factory MAC address,
// hence use manually configured address(es). In this example, Locally
// Administered MAC address derived from ESP32x base MAC address is used. Note
// that Locally Administered OUI range should be used only when testing on a
// LAN under your control!
uint8_t base_mac_addr[ETH_ADDR_LEN];
ESP_GOTO_ON_ERROR(esp_efuse_mac_get_default(base_mac_addr), err, TAG,
"get EFUSE MAC failed");
uint8_t local_mac_1[ETH_ADDR_LEN];
esp_derive_local_mac(local_mac_1, base_mac_addr);
spi_eth_module_config[0].mac_addr = local_mac_1;
#if CONFIG_SNAPCLIENT_SPI_ETHERNETS_NUM > 1
INIT_SPI_ETH_MODULE_CONFIG(spi_eth_module_config, 1);
uint8_t local_mac_2[ETH_ADDR_LEN];
base_mac_addr[ETH_ADDR_LEN - 1] += 1;
esp_derive_local_mac(local_mac_2, base_mac_addr);
spi_eth_module_config[1].mac_addr = local_mac_2;
#endif
#if CONFIG_SNAPCLIENT_SPI_ETHERNETS_NUM > 2
#error Maximum number of supported SPI Ethernet devices is currently limited to 2 by this example.
#endif
for (int i = 0; i < CONFIG_SNAPCLIENT_SPI_ETHERNETS_NUM; i++) {
eth_handles[eth_cnt] = eth_init_spi(&spi_eth_module_config[i], NULL, NULL);
ESP_GOTO_ON_FALSE(eth_handles[eth_cnt], ESP_FAIL, err, TAG,
"SPI Ethernet init failed");
eth_cnt++;
}
#endif // CONFIG_ETH_USE_SPI_ETHERNET
#else
ESP_LOGD(TAG, "no Ethernet device selected to init");
#endif // CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET ||
// CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
*eth_handles_out = eth_handles;
*eth_cnt_out = eth_cnt;
return ret;
#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \
CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
err:
free(eth_handles);
return ret;
#endif
}
/** Event handler for Ethernet events */
static void eth_event_handler(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data) {
uint8_t mac_addr[6] = {0};
/* we can get the Ethernet driver handle from event data */
/* we can get the ethernet driver handle from event data */
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
switch (event_id) {
@@ -53,7 +361,6 @@ static void eth_event_handler(void *arg, esp_event_base_t event_base,
ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4],
mac_addr[5]);
break;
case ETHERNET_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "Ethernet Link Down");
@@ -86,112 +393,64 @@ static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
xEventGroupSetBits(s_eth_event_group, ETH_CONNECTED_BIT);
}
/** Init function that exposes to the main application */
void eth_init(void) {
// Initialize TCP/IP network interface (should be called only once in
// application)
// Initialize Ethernet driver
uint8_t eth_port_cnt = 0;
esp_eth_handle_t *eth_handles;
ESP_ERROR_CHECK(original_eth_init(&eth_handles, &eth_port_cnt));
// Initialize TCP/IP network interface aka the esp-netif (should be called
// only once in application)
ESP_ERROR_CHECK(esp_netif_init());
// Create default event loop that running in background
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_inherent_config_t esp_netif_config =
ESP_NETIF_INHERENT_DEFAULT_ETH();
// Warning: the interface desc is used in tests to capture actual connection
// details (IP, gw, mask)
esp_netif_config.if_desc = "eth";
esp_netif_config.route_prio = 64;
esp_netif_config_t netif_config = {.base = &esp_netif_config,
.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH};
esp_netif_t *netif = esp_netif_new(&netif_config);
assert(netif);
// Create instance(s) of esp-netif for Ethernet(s)
if (eth_port_cnt == 1) {
// Use ESP_NETIF_DEFAULT_ETH when just one Ethernet interface is used and
// you don't need to modify default esp-netif configuration parameters.
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
esp_netif_t *eth_netif = esp_netif_new(&cfg);
// Attach Ethernet driver to TCP/IP stack
ESP_ERROR_CHECK(
esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[0])));
} else {
// Use ESP_NETIF_INHERENT_DEFAULT_ETH when multiple Ethernet interfaces are
// used and so you need to modify esp-netif configuration parameters for
// each interface (name, priority, etc.).
esp_netif_inherent_config_t esp_netif_config =
ESP_NETIF_INHERENT_DEFAULT_ETH();
esp_netif_config_t cfg_spi = {.base = &esp_netif_config,
.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH};
char if_key_str[10];
char if_desc_str[10];
char num_str[3];
for (int i = 0; i < eth_port_cnt; i++) {
itoa(i, num_str, 10);
strcat(strcpy(if_key_str, "ETH_"), num_str);
strcat(strcpy(if_desc_str, "eth"), num_str);
esp_netif_config.if_key = if_key_str;
esp_netif_config.if_desc = if_desc_str;
esp_netif_config.route_prio -= i * 5;
esp_netif_t *eth_netif = esp_netif_new(&cfg_spi);
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
mac_config.rx_task_stack_size = 2048;
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = CONFIG_SNAPCLIENT_ETH_PHY_ADDR;
phy_config.reset_gpio_num = CONFIG_SNAPCLIENT_ETH_PHY_RST_GPIO;
#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
esp32_emac_config.smi_mdc_gpio_num = CONFIG_SNAPCLIENT_ETH_MDC_GPIO;
esp32_emac_config.smi_mdio_gpio_num = CONFIG_SNAPCLIENT_ETH_MDIO_GPIO;
s_mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
#if CONFIG_SNAPCLIENT_ETH_PHY_IP101
s_phy = esp_eth_phy_new_ip101(&phy_config);
#elif CONFIG_SNAPCLIENT_ETH_PHY_RTL8201
s_phy = esp_eth_phy_new_rtl8201(&phy_config);
#elif CONFIG_SNAPCLIENT_ETH_PHY_LAN8720
s_phy = esp_eth_phy_new_lan87xx(&phy_config);
#elif CONFIG_SNAPCLIENT_ETH_PHY_DP83848
s_phy = esp_eth_phy_new_dp83848(&phy_config);
#elif CONFIG_SNAPCLIENT_ETH_PHY_KSZ8041
s_phy = esp_eth_phy_new_ksz80xx(&phy_config);
#endif
#elif CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
gpio_install_isr_service(0);
spi_bus_config_t buscfg = {
.miso_io_num = CONFIG_SNAPCLIENT_ETH_SPI_MISO_GPIO,
.mosi_io_num = CONFIG_SNAPCLIENT_ETH_SPI_MOSI_GPIO,
.sclk_io_num = CONFIG_SNAPCLIENT_ETH_SPI_SCLK_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
};
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_SNAPCLIENT_ETH_SPI_HOST, &buscfg,
SPI_DMA_CH_AUTO));
spi_device_interface_config_t spi_devcfg = {
.mode = 0,
.clock_speed_hz = CONFIG_SNAPCLIENT_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
.spics_io_num = CONFIG_SNAPCLIENT_ETH_SPI_CS_GPIO,
.queue_size = 20};
#if CONFIG_SNAPCLIENT_USE_DM9051
/* dm9051 ethernet driver is based on spi driver */
eth_dm9051_config_t dm9051_config =
ETH_DM9051_DEFAULT_CONFIG(CONFIG_SNAPCLIENT_ETH_SPI_HOST, &spi_devcfg);
dm9051_config.int_gpio_num = CONFIG_SNAPCLIENT_ETH_SPI_INT_GPIO;
s_mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
s_phy = esp_eth_phy_new_dm9051(&phy_config);
#elif CONFIG_SNAPCLIENT_USE_W5500
/* w5500 ethernet driver is based on spi driver */
eth_w5500_config_t w5500_config =
ETH_W5500_DEFAULT_CONFIG(CONFIG_SNAPCLIENT_ETH_SPI_HOST, &spi_devcfg);
w5500_config.int_gpio_num = CONFIG_SNAPCLIENT_ETH_SPI_INT_GPIO;
s_mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
s_phy = esp_eth_phy_new_w5500(&phy_config);
#endif
#elif CONFIG_SNAPCLIENT_USE_OPENETH
phy_config.autonego_timeout_ms = 100;
s_mac = esp_eth_mac_new_openeth(&mac_config);
s_phy = esp_eth_phy_new_dp83848(&phy_config);
#endif
// Install Ethernet driver
esp_eth_config_t config = ETH_DEFAULT_CONFIG(s_mac, s_phy);
ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle));
#if !CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET
/* The SPI Ethernet module might doesn't have a burned factory MAC address, we
cat to set it manually. We set the ESP_MAC_ETH mac address as the default,
if you want to use ESP_MAC_EFUSE_CUSTOM mac address, please enable the
configuration: `ESP_MAC_USE_CUSTOM_MAC_AS_BASE_MAC`
*/
uint8_t eth_mac[6] = {0};
ESP_ERROR_CHECK(esp_read_mac(eth_mac, ESP_MAC_ETH));
ESP_ERROR_CHECK(esp_eth_ioctl(s_eth_handle, ETH_CMD_S_MAC_ADDR, eth_mac));
#endif
// combine driver with netif
s_eth_glue = esp_eth_new_netif_glue(s_eth_handle);
esp_netif_attach(netif, s_eth_glue);
// Attach Ethernet driver to TCP/IP stack
ESP_ERROR_CHECK(
esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[i])));
}
}
// Register user defined event handers
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID,
&eth_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP,
&got_ip_event_handler, NULL));
#ifdef CONFIG_SNAPCLIENT_CONNECT_IPV6
ESP_ERROR_CHECK(esp_event_handler_register(
ETH_EVENT, ETHERNET_EVENT_CONNECTED, &on_eth_event, netif));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6,
&eth_on_got_ipv6, NULL));
#endif
esp_eth_start(s_eth_handle);
// Start Ethernet driver state machine
for (int i = 0; i < eth_port_cnt; i++) {
ESP_ERROR_CHECK(esp_eth_start(eth_handles[i]));
}
/* Waiting until either the connection is established (ETH_CONNECTED_BIT) or
* connection failed for the maximum number of re-tries (ETH_FAIL_BIT). The

View File

@@ -1,6 +1,13 @@
#ifndef _ETH_INTERFACE_H_
#define _ETH_INTERFACE_H_
#pragma once
#include "esp_eth_driver.h"
#ifdef __cplusplus
extern "C" {
#endif
void eth_init(void);
#endif /* _ETH_INTERFACE_H_ */
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.15)
# Build as an ESP-IDF component
idf_component_register(
SRCS "improvWifi.cpp" "improv_wrapper.cpp" "wifi_provisioning.c"
PRIV_INCLUDE_DIRS "Improv-WiFi-Library/src" "priv_include"
INCLUDE_DIRS "include"
PRIV_REQUIRES driver esp_wifi wifi_interface
#SRCS "Improv-WiFi-Library/src/ImprovWiFiLibrary.cpp" "wifi_provisioning.c"
#INCLUDE_DIRS "Improv-WiFi-Library/src" "include"
)

View File

@@ -0,0 +1,414 @@
/*
* improvWifi.cpp
*
* Created on: Apr 29, 2024
* Author: karl
*/
#include "improvWifi.h"
#include <string>
void ImprovWiFi::handleSerial(const uint8_t *data, size_t length) {
while (data && (length > 0)) {
uint8_t b = *data;
if (parseImprovSerial(_position, b, _buffer)) {
_buffer[_position++] = b;
} else {
_position = 0;
}
length--;
data++;
}
}
void ImprovWiFi::SerialWriteCallback(const unsigned char *txData, int length) {
if (serWriteCallback) {
serWriteCallback(txData, length);
}
}
void ImprovWiFi::onErrorCallback(ImprovTypes::Error err) {
if (onImproErrorCallback) {
onImproErrorCallback(err);
}
}
bool ImprovWiFi::onCommandCallback(ImprovTypes::ImprovCommand cmd) {
switch (cmd.command) {
case ImprovTypes::Command::GET_CURRENT_STATE: {
if (isConnected()) {
setState(ImprovTypes::State::STATE_PROVISIONED);
sendDeviceUrl(cmd.command);
} else {
setState(ImprovTypes::State::STATE_AUTHORIZED);
}
break;
}
case ImprovTypes::Command::WIFI_SETTINGS: {
if (cmd.ssid.empty()) {
setError(ImprovTypes::Error::ERROR_INVALID_RPC);
break;
}
setState(ImprovTypes::STATE_PROVISIONING);
bool success = false;
if (customConnectWiFiCallback) {
success =
customConnectWiFiCallback(cmd.ssid.c_str(), cmd.password.c_str());
}
if (success) {
setError(ImprovTypes::Error::ERROR_NONE);
setState(ImprovTypes::STATE_PROVISIONED);
sendDeviceUrl(cmd.command);
if (onImprovConnectedCallback) {
onImprovConnectedCallback(cmd.ssid.c_str(), cmd.password.c_str());
}
} else {
setState(ImprovTypes::STATE_STOPPED);
setError(ImprovTypes::ERROR_UNABLE_TO_CONNECT);
onErrorCallback(ImprovTypes::ERROR_UNABLE_TO_CONNECT);
}
break;
}
case ImprovTypes::Command::GET_DEVICE_INFO: {
std::vector<std::string> infos = {
// Firmware name
improvWiFiParams.firmwareName,
// Firmware version
improvWiFiParams.firmwareVersion,
// Hardware chip/variant
CHIP_FAMILY_DESC[improvWiFiParams.chipFamily],
// Device name
improvWiFiParams.deviceName};
std::vector<uint8_t> data =
build_rpc_response(ImprovTypes::GET_DEVICE_INFO, infos, false);
sendResponse(data);
break;
}
case ImprovTypes::Command::GET_WIFI_NETWORKS: {
getAvailableWifiNetworks();
break;
}
default: {
setError(ImprovTypes::ERROR_UNKNOWN_RPC);
return false;
}
}
return true;
}
void ImprovWiFi::setDeviceInfo(ImprovTypes::ChipFamily chipFamily,
const char *firmwareName,
const char *firmwareVersion,
const char *deviceName) {
improvWiFiParams.chipFamily = chipFamily;
improvWiFiParams.firmwareName = firmwareName;
improvWiFiParams.firmwareVersion = firmwareVersion;
improvWiFiParams.deviceName = deviceName;
}
void ImprovWiFi::setDeviceInfo(ImprovTypes::ChipFamily chipFamily,
const char *firmwareName,
const char *firmwareVersion,
const char *deviceName, const char *deviceUrl) {
setDeviceInfo(chipFamily, firmwareName, firmwareVersion, deviceName);
improvWiFiParams.deviceUrl = deviceUrl;
}
bool ImprovWiFi::isConnected() {
if (customIsConnectedCallback) {
customIsConnectedCallback();
}
return 0;
}
void ImprovWiFi::sendDeviceUrl(ImprovTypes::Command cmd) {
// URL where user can finish onboarding or use device
// Recommended to use website hosted by device
uint8_t address[4] = {0, 0, 0, 0};
char buffer[16];
if (customGetLocalIpCallback) {
customGetLocalIpCallback(address);
}
sprintf(buffer, "%d.%d.%d.%d", address[0], address[1], address[2],
address[3]);
std::string ipStr = std::string{buffer};
if (improvWiFiParams.deviceUrl.empty()) {
improvWiFiParams.deviceUrl = "http://" + ipStr;
} else {
replaceAll(improvWiFiParams.deviceUrl, "{LOCAL_IPV4}", ipStr);
}
std::vector<uint8_t> data =
build_rpc_response(cmd, {improvWiFiParams.deviceUrl}, false);
sendResponse(data);
}
void ImprovWiFi::serialWrite(SerialWrite *serWriteCb) {
serWriteCallback = serWriteCb;
}
void ImprovWiFi::onImprovError(OnImprovError *errorCallback) {
onImproErrorCallback = errorCallback;
}
void ImprovWiFi::onImprovConnected(OnImprovConnected *connectedCallback) {
onImprovConnectedCallback = connectedCallback;
}
void ImprovWiFi::setCustomConnectWiFi(CustomConnectWiFi *connectWiFiCallBack) {
customConnectWiFiCallback = connectWiFiCallBack;
}
void ImprovWiFi::setCustomScanWiFi(CustomScanWiFi *scanWiFiCallBack) {
customScanWiFiCallback = scanWiFiCallBack;
}
void ImprovWiFi::setCustomisConnected(CustomIsConnected *isConnectedCallBack) {
customIsConnectedCallback = isConnectedCallBack;
}
void ImprovWiFi::setCustomGetLocalIpCallback(
CustomGetLocalIpCallback *getLocalIpCallback) {
customGetLocalIpCallback = getLocalIpCallback;
}
// for string delimiter
std::vector<std::string> ImprovWiFi::split(std::string s,
std::string delimiter) {
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
std::string token;
std::vector<std::string> res;
while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) {
token = s.substr(pos_start, pos_end - pos_start);
pos_start = pos_end + delim_len;
res.push_back(token);
}
res.push_back(s.substr(pos_start));
return res;
}
void ImprovWiFi::getAvailableWifiNetworks() {
unsigned char apBuffer[256] = {
0,
};
uint16_t networkNum = 0;
int bufLen = sizeof(apBuffer);
// printf("scanning\n");
if (customScanWiFiCallback) {
customScanWiFiCallback(apBuffer, bufLen, &networkNum);
}
size_t pos = 0;
std::string token;
std::string delimiter = "\n";
std::string apString{std::begin(apBuffer), std::end(apBuffer)};
for (int id = 0; id < networkNum; ++id) {
if ((pos = apString.find(delimiter)) != std::string::npos) {
token = apString.substr(0, pos);
std::vector<std::string> splitStr = split(token.c_str(), ",");
std::vector<std::string> wifinetworks = {splitStr};
std::vector<uint8_t> data = build_rpc_response(
ImprovTypes::GET_WIFI_NETWORKS, wifinetworks, false);
sendResponse(data);
apString.erase(0, pos + delimiter.length());
}
}
// final response
std::vector<uint8_t> data = build_rpc_response(
ImprovTypes::GET_WIFI_NETWORKS, std::vector<std::string>{}, false);
sendResponse(data);
}
inline void ImprovWiFi::replaceAll(std::string &str, const std::string &from,
const std::string &to) {
size_t start_pos = 0;
while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length();
}
}
bool ImprovWiFi::parseImprovSerial(size_t position, uint8_t byte,
const uint8_t *buffer) {
if (position == 0) return byte == 'I';
if (position == 1) return byte == 'M';
if (position == 2) return byte == 'P';
if (position == 3) return byte == 'R';
if (position == 4) return byte == 'O';
if (position == 5) return byte == 'V';
if (position == 6) {
return byte == ImprovTypes::IMPROV_SERIAL_VERSION;
}
if (position <= 8) return true;
uint8_t type = buffer[7];
uint8_t data_len = buffer[8];
if (position <= 8 + data_len) return true;
if (position == 8 + data_len + 1) {
uint8_t checksum = 0x00;
for (size_t i = 0; i < position; i++) checksum += buffer[i];
if (checksum != byte) {
_position = 0;
onErrorCallback(ImprovTypes::Error::ERROR_INVALID_RPC);
return false;
}
if (type == ImprovTypes::ImprovSerialType::TYPE_RPC) {
_position = 0;
auto command = parseImprovData(&buffer[9], data_len, false);
return onCommandCallback(command);
}
}
return false;
}
ImprovTypes::ImprovCommand ImprovWiFi::parseImprovData(
const std::vector<uint8_t> &data, bool check_checksum) {
return parseImprovData(data.data(), data.size(), check_checksum);
}
ImprovTypes::ImprovCommand ImprovWiFi::parseImprovData(const uint8_t *data,
size_t length,
bool check_checksum) {
ImprovTypes::ImprovCommand improv_command;
ImprovTypes::Command command = (ImprovTypes::Command)data[0];
uint8_t data_length = data[1];
if (data_length != length - 2 - check_checksum) {
improv_command.command = ImprovTypes::Command::UNKNOWN;
return improv_command;
}
if (check_checksum) {
uint8_t checksum = data[length - 1];
uint32_t calculated_checksum = 0;
for (uint8_t i = 0; i < length - 1; i++) {
calculated_checksum += data[i];
}
if ((uint8_t)calculated_checksum != checksum) {
improv_command.command = ImprovTypes::Command::BAD_CHECKSUM;
return improv_command;
}
}
if (command == ImprovTypes::Command::WIFI_SETTINGS) {
uint8_t ssid_length = data[2];
uint8_t ssid_start = 3;
size_t ssid_end = ssid_start + ssid_length;
uint8_t pass_length = data[ssid_end];
size_t pass_start = ssid_end + 1;
size_t pass_end = pass_start + pass_length;
std::string ssid(data + ssid_start, data + ssid_end);
std::string password(data + pass_start, data + pass_end);
return {.command = command, .ssid = ssid, .password = password};
}
improv_command.command = command;
return improv_command;
}
void ImprovWiFi::setState(ImprovTypes::State state) {
std::vector<uint8_t> data = {'I', 'M', 'P', 'R', 'O', 'V'};
data.resize(11);
data[6] = ImprovTypes::IMPROV_SERIAL_VERSION;
data[7] = ImprovTypes::TYPE_CURRENT_STATE;
data[8] = 1;
data[9] = state;
uint8_t checksum = 0x00;
for (uint8_t d : data) checksum += d;
data[10] = checksum;
SerialWriteCallback(data.data(), data.size());
}
void ImprovWiFi::setError(ImprovTypes::Error error) {
std::vector<uint8_t> data = {'I', 'M', 'P', 'R', 'O', 'V'};
data.resize(11);
data[6] = ImprovTypes::IMPROV_SERIAL_VERSION;
data[7] = ImprovTypes::TYPE_ERROR_STATE;
data[8] = 1;
data[9] = error;
uint8_t checksum = 0x00;
for (uint8_t d : data) checksum += d;
data[10] = checksum;
SerialWriteCallback(data.data(), data.size());
}
void ImprovWiFi::sendResponse(std::vector<uint8_t> &response) {
std::vector<uint8_t> data = {'I', 'M', 'P', 'R', 'O', 'V'};
data.resize(9);
data[6] = ImprovTypes::IMPROV_SERIAL_VERSION;
data[7] = ImprovTypes::TYPE_RPC_RESPONSE;
data[8] = response.size();
data.insert(data.end(), response.begin(), response.end());
uint8_t checksum = 0x00;
for (uint8_t d : data) checksum += d;
data.push_back(checksum);
SerialWriteCallback(data.data(), data.size());
}
std::vector<uint8_t> ImprovWiFi::build_rpc_response(
ImprovTypes::Command command, const std::vector<std::string> &datum,
bool add_checksum) {
std::vector<uint8_t> out;
uint32_t length = 0;
out.push_back(command);
for (const auto &str : datum) {
uint8_t len = str.length();
length += len + 1;
out.push_back(len);
out.insert(out.end(), str.begin(), str.end());
}
out.insert(out.begin() + 1, length);
if (add_checksum) {
uint32_t calculated_checksum = 0;
for (uint8_t byte : out) {
calculated_checksum += byte;
}
out.push_back(calculated_checksum);
}
return out;
}

View File

@@ -0,0 +1,100 @@
/*
* improv_wrapper.cpp
*
* Created on: Apr 28, 2024
* Author: karl
*/
#include "improv_wrapper.h"
ImprovWiFi *c = NULL;
extern "C" void improv_wifi_create(void) {
if (c != NULL) {
delete c;
}
c = new ImprovWiFi();
}
extern "C" void improv_wifi_destroy(void) {
if (c != NULL) {
delete c;
c = NULL;
}
}
extern "C" int improv_wifi_handle_serial(const uint8_t *data, size_t length) {
if (c != NULL) {
c->handleSerial(data, length);
return 0;
}
return -1;
}
extern "C" void improv_wifi_set_device_info(uint8_t chipFamily,
const char *firmwareName,
const char *firmwareVersion,
const char *deviceName,
const char *deviceUrl) {
if (c != NULL) {
c->setDeviceInfo((ImprovTypes::ChipFamily)chipFamily, firmwareName,
firmwareVersion, deviceName, deviceUrl);
}
}
extern "C" void improv_wifi_serialWrite(void *serWriteCb) {
ImprovWiFi::SerialWrite *cb = (ImprovWiFi::SerialWrite *)serWriteCb;
if (c != NULL) {
c->serialWrite(cb);
}
}
extern "C" void improv_wifi_onImprovError(void *onImprovErrorCb) {
ImprovWiFi::OnImprovError *cb = (ImprovWiFi::OnImprovError *)onImprovErrorCb;
if (c != NULL) {
c->onImprovError(cb);
}
}
extern "C" void improv_wifi_onImprovConnected(void *onImprovConnectedCb) {
ImprovWiFi::OnImprovConnected *cb =
(ImprovWiFi::OnImprovConnected *)onImprovConnectedCb;
if (c != NULL) {
c->onImprovConnected(cb);
}
}
extern "C" void improv_wifi_setCustomConnectWiFi(void *setCustomConnectWiFiCb) {
ImprovWiFi::CustomConnectWiFi *cb =
(ImprovWiFi::CustomConnectWiFi *)setCustomConnectWiFiCb;
if (c != NULL) {
c->setCustomConnectWiFi(cb);
}
}
extern "C" void improv_wifi_setCustomScanWiFi(void *setCustomScanWiFiCb) {
ImprovWiFi::CustomScanWiFi *cb =
(ImprovWiFi::CustomScanWiFi *)setCustomScanWiFiCb;
if (c != NULL) {
c->setCustomScanWiFi(cb);
}
}
extern "C" void improv_wifi_setCustomIsConnected(void *setCustomIsConnected) {
ImprovWiFi::CustomIsConnected *cb =
(ImprovWiFi::CustomIsConnected *)setCustomIsConnected;
if (c != NULL) {
c->setCustomisConnected(cb);
}
}
extern "C" void improv_wifi_setCustomGetLocalIpCallback(
void *getLocalIpCallback) {
ImprovWiFi::CustomGetLocalIpCallback *cb =
(ImprovWiFi::CustomGetLocalIpCallback *)getLocalIpCallback;
if (c != NULL) {
c->setCustomGetLocalIpCallback(cb);
}
}

View File

@@ -0,0 +1,22 @@
/*
* wifi_provisioning.h
*
* Created on: Apr 28, 2024
* Author: karl
*/
#ifndef COMPONENTS_WIFI_PROVISIONING_H_
#define COMPONENTS_WIFI_PROVISIONING_H_
#ifdef __cplusplus
extern "C" {
#endif
void improv_init(void);
void improv_deinit(void);
#ifdef __cplusplus
}
#endif
#endif /* COMPONENTS_WIFI_PROVISIONING_H_ */

View File

@@ -0,0 +1,215 @@
/*
* improvWifi.h
*
* Created on: Apr 29, 2024
* Author: karl
*/
#ifndef COMPONENTS_IMPROV_WIFI_INCLUDE_IMPROVWIFI_H_
#define COMPONENTS_IMPROV_WIFI_INCLUDE_IMPROVWIFI_H_
#include <stdint.h>
#include "ImprovTypes.h"
/**
* Improv WiFi class
*
* ### Description
*
* Handles the Improv WiFi Serial protocol (https://www.improv-wifi.com/serial/)
*
* ### Example
*
* Simple example of using ImprovWiFi lib. A complete one can be seen in
* `examples/` folder.
*
* ```cpp
* #include <ImprovWiFiLibrary.h>
*
* ImprovWiFi improvSerial(&Serial);
*
* void setup() {
* improvSerial.setDeviceInfo(ImprovTypes::ChipFamily::CF_ESP32,
* "My-Device-9a4c2b", "2.1.5", "My Device");
* }
*
* void loop() {
* improvSerial.handleSerial();
* }
* ```
*
*/
class ImprovWiFi {
private:
const char *const CHIP_FAMILY_DESC[5] = {"ESP32", "ESP32-C3", "ESP32-S2",
"ESP32-S3", "ESP8266"};
ImprovTypes::ImprovWiFiParamsStruct improvWiFiParams;
uint8_t _buffer[128];
uint8_t _position = 0;
// void *serial;
void sendDeviceUrl(ImprovTypes::Command cmd);
void SerialWriteCallback(const unsigned char *txData, int length);
bool onCommandCallback(ImprovTypes::ImprovCommand cmd);
void onErrorCallback(ImprovTypes::Error err);
void setState(ImprovTypes::State state);
void sendResponse(std::vector<uint8_t> &response);
void setError(ImprovTypes::Error error);
void getAvailableWifiNetworks();
inline void replaceAll(std::string &str, const std::string &from,
const std::string &to);
// improv SDK
bool parseImprovSerial(size_t position, uint8_t byte, const uint8_t *buffer);
ImprovTypes::ImprovCommand parseImprovData(const std::vector<uint8_t> &data,
bool check_checksum = true);
ImprovTypes::ImprovCommand parseImprovData(const uint8_t *data, size_t length,
bool check_checksum = true);
std::vector<uint8_t> build_rpc_response(ImprovTypes::Command command,
const std::vector<std::string> &datum,
bool add_checksum);
public:
/**
* ## Constructors
**/
/**
* Create an instance of ImprovWiFi
*
* # Parameters
*
* - `serial` - Pointer to stream object used to handle requests, for the most
* cases use `Serial`
*/
ImprovWiFi(void) {}
/**
* ## Type definition
*/
/**
* serial write function passed through user
*/
typedef void(SerialWrite)(const unsigned char *txData, int length);
/**
* Callback function called when any error occurs during the protocol handling
* or wifi connection.
*/
typedef void(OnImprovError)(ImprovTypes::Error);
/**
* Callback function called when the attempt of wifi connection is successful.
* It informs the SSID and Password used to that, it's a perfect time to save
* them for further use.
*/
typedef void(OnImprovConnected)(const char *ssid, const char *password);
/**
* Callback function to customize the wifi connection if you needed. Optional.
*/
typedef bool(CustomConnectWiFi)(const char *ssid, const char *password);
typedef void(CustomScanWiFi)(unsigned char *scanResponse, int bufLen,
uint16_t *count);
typedef bool(CustomIsConnected)(void);
typedef void(CustomGetLocalIpCallback)(uint8_t *addrIp4);
/**
* ## Methods
**/
/**
* Check if a communication via serial is happening. Put this call on your
* loop().
*
*/
void handleSerial(const uint8_t *data, size_t length);
/**
* Set details of your device.
*
* # Parameters
*
* - `chipFamily` - Chip variant, supported are CF_ESP32, CF_ESP32_C3,
* CF_ESP32_S2, CF_ESP32_S3, CF_ESP8266. Consult ESP Home
* [docs](https://esphome.io/components/esp32.html) for more information.
* - `firmwareName` - Firmware name
* - `firmwareVersion` - Firmware version
* - `deviceName` - Your device name
* - `deviceUrl`- The local URL to access your device. A placeholder called
* {LOCAL_IPV4} is available to form elaboreted URLs. E.g.
* `http://{LOCAL_IPV4}?name=Guest`. There is overloaded method without
* `deviceUrl`, in this case the URL will be the local IP.
*
*/
void setDeviceInfo(ImprovTypes::ChipFamily chipFamily,
const char *firmwareName, const char *firmwareVersion,
const char *deviceName, const char *deviceUrl);
void setDeviceInfo(ImprovTypes::ChipFamily chipFamily,
const char *firmwareName, const char *firmwareVersion,
const char *deviceName);
/**
* Method to set serial write callback
*/
void serialWrite(SerialWrite *serWriteCb);
/**
* Method to set the typedef OnImprovError callback.
*/
void onImprovError(OnImprovError *errorCallback);
/**
* Method to set the typedef OnImprovConnected callback.
*/
void onImprovConnected(OnImprovConnected *connectedCallback);
/**
* Method to set the typedef CustomConnectWiFi callback.
*/
void setCustomConnectWiFi(CustomConnectWiFi *connectWiFiCallBack);
void setCustomScanWiFi(CustomScanWiFi *scanWiFiCallBack);
void setCustomisConnected(CustomIsConnected *isConnectedCallBack);
void setCustomGetLocalIpCallback(
CustomGetLocalIpCallback *getLocalIpCallback);
//
// /**
// * Default method to connect in a WiFi network.
// * It waits `DELAY_MS_WAIT_WIFI_CONNECTION` milliseconds (default 500)
// during
// * `MAX_ATTEMPTS_WIFI_CONNECTION` (default 20) until it get connected. If
// it
// * does not happen, an error `ERROR_UNABLE_TO_CONNECT` is thrown.
// *
// */
// bool tryConnectToWifi(const char *ssid, const char *password);
/**
* Check if connection is established using `WiFi.status() == WL_CONNECTED`
*
*/
bool isConnected();
std::vector<std::string> split(std::string s, std::string delimiter);
private:
SerialWrite *serWriteCallback = NULL;
OnImprovError *onImproErrorCallback = NULL;
OnImprovConnected *onImprovConnectedCallback = NULL;
CustomConnectWiFi *customConnectWiFiCallback = NULL;
CustomScanWiFi *customScanWiFiCallback = NULL;
CustomIsConnected *customIsConnectedCallback = NULL;
CustomGetLocalIpCallback *customGetLocalIpCallback = NULL;
};
#endif /* COMPONENTS_IMPROV_WIFI_INCLUDE_IMPROVWIFI_H_ */

View File

@@ -0,0 +1,42 @@
/*
* improv_wrapper.h
*
* Created on: Apr 29, 2024
* Author: karl
*/
#ifndef COMPONENTS_IMPROV_WIFI_INCLUDE_IMPROV_WRAPPER_H_
#define COMPONENTS_IMPROV_WIFI_INCLUDE_IMPROV_WRAPPER_H_
#ifdef __cplusplus
#include "improvWifi.h"
extern "C" {
#else
enum ChipFamily_e {
CF_ESP32,
CF_ESP32_C3,
CF_ESP32_S2,
CF_ESP32_S3,
CF_ESP8266
};
#endif
void improv_wifi_create(void);
void improv_wifi_destroy(void);
int improv_wifi_handle_serial(const uint8_t *data, size_t length);
void improv_wifi_set_device_info(uint8_t chipFamily, const char *firmwareName,
const char *firmwareVersion,
const char *deviceName, const char *deviceUrl);
void improv_wifi_serialWrite(void *cb);
void improv_wifi_onImprovError(void *onImprovErrorCb);
void improv_wifi_onImprovConnected(void *onImprovConnectedCb);
void improv_wifi_setCustomConnectWiFi(void *setCustomConnectWiFiCb);
void improv_wifi_setCustomScanWiFi(void *setCustomScanWiFiCb);
void improv_wifi_setCustomIsConnected(void *setCustomIsConnected);
void improv_wifi_setCustomGetLocalIpCallback(void *getLocalIpCallback);
#ifdef __cplusplus
}
#endif
#endif /* COMPONENTS_IMPROV_WIFI_INCLUDE_IMPROV_WRAPPER_H_ */

View File

@@ -0,0 +1,249 @@
/*
* wifi_provisioning.c
*
* Created on: Apr 28, 2024
* Author: karl
*/
#include "wifi_provisioning.h"
#include <string.h>
#include "driver/uart.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#include "improv_wrapper.h"
#include "wifi_interface.h"
#define TAG "IMPROV"
#define RD_BUF_SIZE (UART_FIFO_LEN)
#define PATTERN_CHR_NUM (3)
static TaskHandle_t t_improv_task = NULL;
static const int uart_buffer_size = 2 * RD_BUF_SIZE;
static QueueHandle_t uart0_queue;
void uart_event_handler(void) {
uart_event_t event;
uint8_t dtmp[RD_BUF_SIZE];
size_t buffered_size;
// Waiting for UART event.
if (xQueueReceive(uart0_queue, (void *)&event, (TickType_t)portMAX_DELAY)) {
bzero(dtmp, RD_BUF_SIZE);
// ESP_LOGI(TAG, "uart[%d] event:", UART_NUM_0);
switch (event.type) {
// Event of UART receving data
/*We'd better handler data event fast, there would be much more data
events than other types of events. If we take too much time on data event,
the queue might be full.*/
case UART_DATA:
// ESP_LOGI(TAG, "[UART DATA]: %d", event.size);
uart_read_bytes(UART_NUM_0, dtmp, event.size, portMAX_DELAY);
// ESP_LOGI(TAG, "[DATA EVT]:");
improv_wifi_handle_serial(dtmp, event.size);
break;
// Event of HW FIFO overflow detected
case UART_FIFO_OVF:
// ESP_LOGI(TAG, "hw fifo overflow");
// If fifo overflow happened, you should consider adding flow control
// for your application. The ISR has already reset the rx FIFO, As an
// example, we directly flush the rx buffer here in order to read more
// data.
uart_flush_input(UART_NUM_0);
xQueueReset(uart0_queue);
break;
// Event of UART ring buffer full
case UART_BUFFER_FULL:
// ESP_LOGI(TAG, "ring buffer full");
// If buffer full happened, you should consider increasing your buffer
// size As an example, we directly flush the rx buffer here in order to
// read more data.
uart_flush_input(UART_NUM_0);
xQueueReset(uart0_queue);
break;
// Others
default:
// ESP_LOGI(TAG, "uart event type: %d", event.type);
break;
}
}
}
static void improv_task(void *pvParameters) {
while (1) {
uart_event_handler();
}
}
void uart_write(const unsigned char *txData, int length) {
uart_write_bytes(UART_NUM_0, txData, length);
}
void improv_wifi_scan(unsigned char *scanResponse, int bufLen,
uint16_t *count) {
uint16_t number = 16;
wifi_ap_record_t ap_info[16];
memset(ap_info, 0, sizeof(ap_info));
if (esp_wifi_scan_start(NULL, true) == ESP_ERR_WIFI_STATE) {
wifi_ap_record_t ap_info_tmp;
do {
esp_wifi_disconnect();
vTaskDelay(pdMS_TO_TICKS(500));
} while (esp_wifi_sta_get_ap_info(&ap_info_tmp) !=
ESP_ERR_WIFI_NOT_CONNECT);
esp_wifi_scan_start(NULL, true);
}
// ESP_LOGI(TAG, "Max AP number ap_info can hold = %u", number);
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info));
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(count));
// ESP_LOGI(TAG, "Total APs scanned = %u, actual AP number ap_info holds =
// %u",
// *count, number);
scanResponse[0] = 0;
for (int i = 0; i < number; i++) {
char rssiStr[8] = {
0,
};
char cipherStr[8] = {
0,
};
uint16_t neededLen;
itoa(ap_info[i].rssi, rssiStr, 10);
if (ap_info[i].authmode != WIFI_AUTH_OPEN) {
strcat(cipherStr, "YES");
} else {
strcat(cipherStr, "NO");
}
neededLen = strlen((const char *)ap_info[i].ssid) + strlen(rssiStr) +
strlen(cipherStr) + 3;
if ((bufLen - neededLen) > 0) {
strcat((char *)scanResponse, (char *)ap_info[i].ssid);
strcat((char *)scanResponse, (char *)",");
strcat((char *)scanResponse, (char *)rssiStr);
strcat((char *)scanResponse, (char *)",");
strcat((char *)scanResponse, (char *)cipherStr);
strcat((char *)scanResponse, (char *)"\n");
bufLen -= neededLen;
}
}
// ESP_LOGI(TAG, "APs \t\t%s", scanResponse);
}
bool improv_wifi_connect(const char *ssid, const char *password) {
uint8_t count = 0;
wifi_ap_record_t apRec;
esp_err_t err;
while ((err = esp_wifi_sta_get_ap_info(&apRec)) != ESP_ERR_WIFI_NOT_CONNECT) {
esp_wifi_disconnect();
vTaskDelay(pdMS_TO_TICKS(100));
}
wifi_config_t wifi_config;
ESP_ERROR_CHECK(esp_wifi_get_config(WIFI_IF_STA, &wifi_config));
strcpy((char *)wifi_config.sta.ssid, ssid);
strcpy((char *)wifi_config.sta.password, password);
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
esp_wifi_connect();
while (esp_wifi_sta_get_ap_info(&apRec) != ESP_OK) {
vTaskDelay(pdMS_TO_TICKS(500));
if (count > 20) {
esp_wifi_disconnect();
return false;
}
count++;
}
return true;
}
bool improv_wifi_is_connected(void) {
wifi_ap_record_t apRec;
if (esp_wifi_sta_get_ap_info(&apRec) == ESP_OK) {
// printf("connected\n");
return true;
}
// printf("NOT connected\n");
return false;
}
void improv_wifi_get_local_ip(uint8_t *address) {
esp_netif_ip_info_t ip_info;
// TODO: find a better way to do this
do {
esp_netif_get_ip_info(get_current_netif(), &ip_info);
vTaskDelay(pdMS_TO_TICKS(200));
} while (ip_info.ip.addr == 0);
address[0] = ip_info.ip.addr >> 0;
address[1] = ip_info.ip.addr >> 8;
address[2] = ip_info.ip.addr >> 16;
address[3] = ip_info.ip.addr >> 24;
// ESP_LOGI(TAG, "%d.%d.%d.%d", address[0], address[1], address[2],
// address[3]);
}
void improv_init(void) {
uint8_t webPortStr[6] = {0};
uint16_t webPort = CONFIG_WEB_PORT;
uint8_t urlStr[26] = "http://{LOCAL_IPV4}:";
utoa(webPort, (char *)webPortStr, 10);
strcat((char *)urlStr, (char *)webPortStr);
improv_wifi_create();
improv_wifi_serialWrite(uart_write);
improv_wifi_set_device_info(CF_ESP32, "esp32_snapclient", "0.0.3",
"snapclient", (const char *)urlStr);
improv_wifi_setCustomConnectWiFi(improv_wifi_connect);
improv_wifi_setCustomScanWiFi(improv_wifi_scan);
improv_wifi_setCustomIsConnected(improv_wifi_is_connected);
improv_wifi_setCustomGetLocalIpCallback(improv_wifi_get_local_ip);
// Set UART pins(TX: IO4, RX: IO5, RTS: IO18, CTS: IO19)
// ESP_ERROR_CHECK(uart_set_pin(UART_NUM_0, 1, 3, -1, -1));
// Install UART driver using an event queue here
ESP_ERROR_CHECK(uart_driver_install(UART_NUM_0, uart_buffer_size,
uart_buffer_size, 10, &uart0_queue, 0));
xTaskCreatePinnedToCore(&improv_task, "improv", 4 * 1024, NULL, 4,
&t_improv_task, tskNO_AFFINITY);
}
void improv_deinit(void) {
if (t_improv_task) {
vTaskDelete(t_improv_task);
uart_driver_delete(UART_NUM_0);
t_improv_task = NULL;
}
improv_wifi_destroy();
}

View File

@@ -7,6 +7,10 @@
#include "sdkconfig.h"
#include "snapcast.h"
#ifdef __cplusplus
extern "C" {
#endif
#define I2S_PORT I2S_NUM_0
// TODO: maybe calculate this dynamically based on chunk duration and buffer
@@ -78,5 +82,7 @@ int32_t get_diff_to_server(int64_t *tDiff);
int32_t server_now(int64_t *sNow, int64_t *diff2Server);
int32_t pcm_chunk_queue_msg_waiting(void);
#ifdef __cplusplus
}
#endif
#endif // __PLAYER_H__

View File

@@ -1,6 +1,10 @@
#ifndef __SNAPCAST_H__
#define __SNAPCAST_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@@ -107,5 +111,8 @@ typedef struct time_message {
int time_message_serialize(time_message_t *msg, char *data, uint32_t size);
int time_message_deserialize(time_message_t *msg, const char *data,
uint32_t size);
#ifdef __cplusplus
}
#endif
#endif // __SNAPCAST_H__

View File

@@ -108,10 +108,12 @@ static bool i2sEnabled = false;
*
*/
esp_err_t my_i2s_channel_disable(i2s_chan_handle_t handle) {
if (i2sEnabled == true) {
i2sEnabled = false;
if (tx_chan != NULL) {
if (i2sEnabled == true) {
i2sEnabled = false;
return i2s_channel_disable(handle);
return i2s_channel_disable(handle);
}
}
return ESP_OK;
@@ -121,10 +123,12 @@ esp_err_t my_i2s_channel_disable(i2s_chan_handle_t handle) {
*
*/
esp_err_t my_i2s_channel_enable(i2s_chan_handle_t handle) {
if (i2sEnabled == false) {
i2sEnabled = true;
if (tx_chan != NULL) {
if (i2sEnabled == false) {
i2sEnabled = true;
return i2s_channel_enable(handle);
return i2s_channel_enable(handle);
}
}
return ESP_OK;
@@ -142,7 +146,6 @@ static esp_err_t player_setup_i2s(i2s_port_t i2sNum,
// works for all decoders. We set it to 100 so
// there will be free space for sample stuffing in each round
i2sDmaBufMaxLen = 100;
#else
int fi2s_clk;
const int __dmaBufMaxLen = 1024;
@@ -199,6 +202,9 @@ static esp_err_t player_setup_i2s(i2s_port_t i2sNum,
}
#endif
ESP_LOGI(TAG, "player_setup_i2s: dma_buf_len is %ld, dma_buf_count is %ld",
i2sDmaBufMaxLen, i2sDmaBufCnt);
if (tx_chan) {
my_i2s_channel_disable(tx_chan);
i2s_del_channel(tx_chan);
@@ -240,8 +246,13 @@ static esp_err_t player_setup_i2s(i2s_port_t i2sNum,
};
i2s_std_config_t tx_std_cfg = {
.clk_cfg = i2s_clkcfg,
#if CONFIG_I2S_USE_MSB_FORMAT
.slot_cfg =
I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(bits, I2S_SLOT_MODE_STEREO),
I2S_STD_MSB_SLOT_DEFAULT_CONFIG(setting->bits, I2S_SLOT_MODE_STEREO),
#else
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(setting->bits,
I2S_SLOT_MODE_STEREO),
#endif
.gpio_cfg =
{
.mclk = pin_config0.mck_io_num,
@@ -251,19 +262,31 @@ static esp_err_t player_setup_i2s(i2s_port_t i2sNum,
.din = pin_config0.data_in_num,
.invert_flags =
{
#if CONFIG_INVERT_MCLK_LEVEL
.mclk_inv = true,
#else
.mclk_inv = false,
#endif
#if CONFIG_INVERT_BCLK_LEVEL
.bclk_inv = true,
#else
.bclk_inv = false,
#endif
#if CONFIG_INVERT_WORD_SELECT_LEVEL
.ws_inv = true,
#else
.ws_inv = false,
#endif
},
},
};
ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_chan, &tx_std_cfg));
ESP_LOGI(TAG,
"player_setup_i2s: dma_buf_len is %ld, dma_buf_count is %ld, sample "
"rate: %ld",
i2sDmaBufMaxLen, i2sDmaBufCnt, setting->sr);
// my_i2s_channel_enable(tx_chan);
return 0;
}
@@ -383,8 +406,6 @@ int init_player(void) {
tg0_timer_init();
ESP_LOGI(TAG, "test");
if (playerTaskHandle == NULL) {
ESP_LOGI(TAG, "Start player_task");
@@ -445,15 +466,6 @@ int32_t player_latency_insert(int64_t newValue) {
// ESP_LOGI(TAG, "(not full) latency median: %lldus", medianValue);
// }
#if LATENCY_MEDIAN_age_DIVISOR
// ESP_LOGI(TAG, "actual latency median: %lldus", medianValue);
// medianValue = MEDIANFILTER_get_median(&latencyMedianFilter,
// ceil((float)LATENCY_MEDIAN_FILTER_LEN /
// (float)LATENCY_MEDIAN_age_DIVISOR));
medianValue = MEDIANFILTER_get_median(&latencyMedianFilter, 32);
// ESP_LOGI(TAG, "age latency median: %lldus", medianValue);
#endif
latencyToServer = medianValue;
xSemaphoreGive(latencyBufSemaphoreHandle);
@@ -1114,13 +1126,10 @@ int32_t insert_pcm_chunk(pcm_chunk_message_t *pcmChunk) {
// if (xQueueSend(pcmChkQHdl, &pcmChunk, pdMS_TO_TICKS(10)) != pdTRUE) {
if (xQueueSend(pcmChkQHdl, &pcmChunk, pdMS_TO_TICKS(1)) != pdTRUE) {
// if (xQueueSend(pcmChkQHdl, &pcmChunk, portMAX_DELAY) != pdTRUE) {
ESP_LOGW(TAG, "send: pcmChunkQueue full, messages waiting %d",
uxQueueMessagesWaiting(pcmChkQHdl));
free_pcm_chunk(pcmChunk);
} else {
// ESP_LOGI(TAG, "PCM chunk inserted");
}
return 0;
@@ -1411,6 +1420,37 @@ static void player_task(void *pvParameters) {
// get actual age after alarm
age = (int64_t)timer_val - (-age);
// check if we need to write remaining data
if (size != 0) {
do {
written = 0;
if (i2s_custom_write(I2S_NUM_0, p_payload, (size_t)size, &written,
portMAX_DELAY) != ESP_OK) {
ESP_LOGE(TAG, "i2s_playback_task: I2S write error");
}
if (written < size) {
ESP_LOGE(TAG,
"i2s_playback_task: I2S didn't "
"write all data");
}
size -= written;
p_payload += written;
if (size == 0) {
if (fragment->nextFragment != NULL) {
fragment = fragment->nextFragment;
p_payload = fragment->payload;
size = fragment->size;
} else {
free_pcm_chunk(chnk);
chnk = NULL;
break;
}
}
} while (1);
}
initialSync = 1;
// TODO: use a timer to un-mute non blocking

View File

@@ -1,6 +1,10 @@
#ifndef _NET_FUNCTIONS_H_
#define _NET_FUNCTIONS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "mdns.h"
#define SNTP_TIMEZONE CONFIG_SNTP_TIMEZONE
@@ -13,4 +17,8 @@ uint32_t find_mdns_service(const char* service_name, const char* proto);
void set_time_from_sntp(void);
#ifdef __cplusplus
}
#endif
#endif /* _NET_FUNCTIONS_H_ */

View File

@@ -1,6 +1,10 @@
#ifndef __UI_HTTP_SERVER_H__
#define __UI_HTTP_SERVER_H__
#ifdef __cplusplus
extern "C" {
#endif
void init_http_server_task(char *key);
typedef struct {
@@ -11,4 +15,8 @@ typedef struct {
float gain_3;
} URL_t;
#ifdef __cplusplus
}
#endif
#endif // __UI_HTTP_SERVER_H__

View File

@@ -1,3 +1,3 @@
idf_component_register(SRCS "wifi_interface.c"
INCLUDE_DIRS "include"
REQUIRES wifi_provisioning esp_event esp_wifi esp_hw_support)
REQUIRES wifi_provisioning esp_event esp_wifi esp_hw_support nvs_flash improv_wifi)

View File

@@ -3,21 +3,7 @@ menu "Wifi Configuration"
bool "enable WiFi provisioning"
default n
help
Enable WiFi provisioning so espressif APP can be used to provison WiFi credentials
config WIFI_PROVISIONING_SSID
string "WiFi provisioning SSID"
default "prov_snapclient"
depends on ENABLE_WIFI_PROVISIONING
help
SSID (network name) to use for provisioning access point. Shouldn't be longer than 20 characters.
config WIFI_PROVISIONING_PASSWORD
string "WiFi provisioning password"
default "12345678"
depends on ENABLE_WIFI_PROVISIONING
help
WiFi password (WPA or WPA2) to use for provisioning access point
Enable WiFi provisioning through improv WiFi (https://github.com/improv-wifi), try it using https://web.esphome.io/
config WIFI_SSID
string "WiFi SSID"
@@ -34,7 +20,7 @@ menu "Wifi Configuration"
WiFi password (WPA or WPA2) for the example to use.
config WIFI_MAXIMUM_RETRY
int "Maximum retry"
int "Maximum connection retry"
default 5
help
Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.

View File

@@ -10,33 +10,59 @@
#include "esp_event.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "esp_timer.h"
#include "esp_wifi.h"
#include "nvs_flash.h"
#if ENABLE_WIFI_PROVISIONING
#include <string.h> // for memcpy
#include <wifi_provisioning/manager.h>
#include <wifi_provisioning/scheme_softap.h>
#endif
#if ENABLE_WIFI_PROVISIONING
static const char *provPwd = CONFIG_WIFI_PROVISIONING_PASSWORD;
static const char *provSsid = CONFIG_WIFI_PROVISIONING_SSID;
#include "wifi_provisioning.h"
#endif
static const char *TAG = "WIFI";
static void reset_reason_timer_counter_cb(void *);
static char mac_address[18];
EventGroupHandle_t s_wifi_event_group;
static int s_retry_num = 0;
static wifi_config_t wifi_config;
static esp_netif_t *esp_wifi_netif = NULL;
/* FreeRTOS event group to signal when we are connected & ready to make a
* request */
// static EventGroupHandle_t wifi_event_group;
#if ENABLE_WIFI_PROVISIONING
static esp_timer_handle_t resetReasonTimerHandle = NULL;
static const esp_timer_create_args_t resetReasonTimerArgs = {
.callback = &reset_reason_timer_counter_cb,
.dispatch_method = ESP_TIMER_TASK,
.name = "rstCnt",
.skip_unhandled_events = false};
static uint8_t resetReasonCounter = 0;
static void reset_reason_timer_counter_cb(void *args) {
nvs_handle_t nvs_handle;
esp_err_t err = nvs_open("storage", NVS_READWRITE, &nvs_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Error (%s) opening NVS handle!", __func__,
esp_err_to_name(err));
} else {
ESP_LOGI(TAG, "resetting POR reset counter ...");
resetReasonCounter = 0;
err |= nvs_set_u8(nvs_handle, "restart_counter", resetReasonCounter);
err |= nvs_commit(nvs_handle);
ESP_LOGI(TAG, "%s", (err != ESP_OK) ? "Failed!" : "Done");
nvs_close(nvs_handle);
}
esp_timer_delete(resetReasonTimerHandle);
}
#endif
/* The event group allows multiple bits for each event,
but we only care about one event - are we connected
@@ -65,61 +91,9 @@ static void event_handler(void *arg, esp_event_base_t event_base, int event_id,
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG, "connect to the AP fail");
} else {
#if ENABLE_WIFI_PROVISIONING
if (event_base == WIFI_PROV_EVENT) {
switch (event_id) {
case WIFI_PROV_START:
ESP_LOGI(TAG, "Provisioning started");
break;
case WIFI_PROV_CRED_RECV: {
wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data;
ESP_LOGI(TAG,
"Received Wi-Fi credentials"
"\n\tSSID : %s\n\tPassword : %s",
(const char *)wifi_sta_cfg->ssid,
(const char *)wifi_sta_cfg->password);
memcpy(&(wifi_config.sta), wifi_sta_cfg, sizeof(wifi_sta_config_t));
break;
}
case WIFI_PROV_CRED_FAIL: {
wifi_prov_sta_fail_reason_t *reason =
(wifi_prov_sta_fail_reason_t *)event_data;
ESP_LOGE(TAG,
"Provisioning failed!\n\tReason : %s"
"\n\tPlease reset to factory and retry provisioning",
(*reason == WIFI_PROV_STA_AUTH_ERROR)
? "Wi-Fi station authentication failed"
: "Wi-Fi access-point not found");
break;
}
case WIFI_PROV_CRED_SUCCESS:
ESP_LOGI(TAG, "Provisioning successful");
break;
case WIFI_PROV_END:
/* De-initialize manager once provisioning is finished */
ESP_LOGI(TAG, "Provisioning end");
break;
default:
break;
}
}
#endif
}
}
#if ENABLE_WIFI_PROVISIONING
static void get_device_service_name(char *service_name, size_t max) {
uint8_t eth_mac[6];
const char *ssid_prefix = provSsid;
esp_wifi_get_mac(WIFI_IF_STA, eth_mac);
snprintf(service_name, max, "%s_%02X%02X%02X", ssid_prefix, eth_mac[3],
eth_mac[4], eth_mac[5]);
}
#endif
void wifi_init(void) {
s_wifi_event_group = xEventGroupCreate();
@@ -132,121 +106,83 @@ void wifi_init(void) {
ESP_ERROR_CHECK(
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
(esp_event_handler_t)&event_handler, NULL));
#if ENABLE_WIFI_PROVISIONING
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_PROV_EVENT, ESP_EVENT_ANY_ID,
&event_handler, NULL));
#endif
esp_wifi_netif = esp_netif_create_default_wifi_sta();
#if ENABLE_WIFI_PROVISIONING
esp_netif_create_default_wifi_ap();
#endif
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// esp_wifi_set_bandwidth (WIFI_IF_STA, WIFI_BW_HT20);
esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW_HT40);
esp_wifi_set_protocol(
WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
// esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G);
// esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B);
// esp_wifi_set_ps(WIFI_PS_MIN_MODEM);
// esp_wifi_set_ps(WIFI_PS_NONE);
#if ENABLE_WIFI_PROVISIONING
// Configuration for the provisioning manager
wifi_prov_mgr_config_t config = {
.scheme = wifi_prov_scheme_softap,
.scheme_event_handler = WIFI_PROV_EVENT_HANDLER_NONE};
esp_reset_reason_t resetReason = esp_reset_reason();
ESP_LOGI(TAG, "reset reason was: %d", resetReason);
esp_timer_create(&resetReasonTimerArgs, &resetReasonTimerHandle);
esp_timer_start_once(resetReasonTimerHandle, 5000000);
if (resetReason == ESP_RST_POWERON) {
nvs_handle_t nvs_handle;
esp_err_t err = nvs_open("storage", NVS_READWRITE, &nvs_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Error (%s) opening NVS handle!", __func__,
esp_err_to_name(err));
} else {
ESP_LOGI(TAG, "get POR reset counter ...");
err |= nvs_get_u8(nvs_handle, "restart_counter", &resetReasonCounter);
// Initialize provisioning manager with the
// configuration parameters set above
ESP_ERROR_CHECK(wifi_prov_mgr_init(config));
ESP_LOGI(TAG, "reset counter %d", resetReasonCounter);
bool provisioned = false;
/* Let's find out if the device is provisioned */
ESP_ERROR_CHECK(wifi_prov_mgr_is_provisioned(&provisioned));
resetReasonCounter++;
/* If device is not yet provisioned start provisioning service */
if (!provisioned) {
ESP_LOGI(TAG, "Starting provisioning");
if (resetReasonCounter > 3) {
ESP_LOGW(TAG, "resetting WIFI credentials!");
// Wi-Fi SSID when scheme is wifi_prov_scheme_softap
char service_name[27];
get_device_service_name(service_name, sizeof(service_name));
resetReasonCounter = 0;
/* What is the security level that we want (0 or 1):
* - WIFI_PROV_SECURITY_0 is simply plain text communication.
* - WIFI_PROV_SECURITY_1 is secure communication which consists of
* secure handshake using X25519 key exchange and proof of possession
* (pop) and AES-CTR for encryption/decryption of messages.
*/
wifi_prov_security_t security = WIFI_PROV_SECURITY_1;
esp_wifi_restore();
// esp_wifi_set_bandwidth (WIFI_IF_STA, WIFI_BW_HT20);
esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW_HT40);
esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B |
WIFI_PROTOCOL_11G |
WIFI_PROTOCOL_11N);
/* Do we want a proof-of-possession (ignored if Security 0 is selected):
* - this should be a string with length > 0
* - NULL if not used
*/
const char *pop = NULL; //"abcd1234";
esp_timer_stop(resetReasonTimerHandle);
esp_timer_delete(resetReasonTimerHandle);
}
/* What is the service key (could be NULL)
* This translates to :
* - Wi-Fi password when scheme is wifi_prov_scheme_softap
* - simply ignored when scheme is wifi_prov_scheme_ble
*/
const char *service_key = provPwd;
err |= nvs_set_u8(nvs_handle, "restart_counter", resetReasonCounter);
err |= nvs_commit(nvs_handle);
ESP_LOGI(TAG, "%s", (err != ESP_OK) ? "Failed!" : "Done");
/* An optional endpoint that applications can create if they expect to
* get some additional custom data during provisioning workflow.
* The endpoint name can be anything of your choice.
* This call must be made before starting the provisioning.
*/
// wifi_prov_mgr_endpoint_create("custom-data");
/* Start provisioning service */
ESP_ERROR_CHECK(wifi_prov_mgr_start_provisioning(
security, pop, service_name, service_key));
/* The handler for the optional endpoint created above.
* This call must be made after starting the provisioning, and only if
* the endpoint has already been created above.
*/
// wifi_prov_mgr_endpoint_register("custom-data",
// custom_prov_data_handler, NULL);
/* Uncomment the following to wait for the provisioning to finish and
* then release the resources of the manager. Since in this case
* de-initialization is triggered by the default event loop handler, we
* don't need to call the following */
wifi_prov_mgr_wait();
wifi_prov_mgr_deinit();
} else {
ESP_LOGI(TAG, "Already provisioned, starting Wi-Fi STA");
/* We don't need the manager as device is already provisioned,
* so let's release it's resources */
wifi_prov_mgr_deinit();
/* Start Wi-Fi station */
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
wifi_config_t wifi_config;
ESP_ERROR_CHECK(esp_wifi_get_config(WIFI_IF_STA, &wifi_config));
wifi_config.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL;
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "wifi_init_sta finished.");
nvs_close(nvs_handle);
}
}
/* Start Wi-Fi station */
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
wifi_config_t wifi_config;
ESP_ERROR_CHECK(esp_wifi_get_config(WIFI_IF_STA, &wifi_config));
wifi_config.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL;
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "Starting provisioning");
improv_init();
#else
wifi_config_t wifi_config = {
.sta =
{
.ssid = WIFI_SSID,
.password = WIFI_PASSWORD,
.sort_method = WIFI_CONNECT_AP_BY_SIGNAL,
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
.pmf_cfg = {.capable = true, .required = false},
},

View File

@@ -1,32 +0,0 @@
dependencies:
espressif/esp-dsp:
component_hash: fa7fe74305df6da25867437ebcd4213e047cbfc0556cf92067ab657fce537c6e
dependencies:
- name: idf
require: private
version: '>=4.2'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.5.2
espressif/mdns:
component_hash: d36b265164be5139f92de993f08f5ecaa0de0c0acbf84deee1f10bb5902d04ff
dependencies:
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 1.4.3
idf:
source:
type: idf
version: 5.1.5
direct_dependencies:
- espressif/esp-dsp
- espressif/mdns
- idf
manifest_hash: 01df6f188570b9e5362f7a00a294b1d3403de1f5ce8cbd848004d3bc88aa09a8
target: esp32
version: 2.0.0

View File

@@ -1,5 +1,5 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS "."
PRIV_REQUIRES esp_timer esp_wifi nvs_flash wifi_interface audio_board audio_hal audio_sal net_functions opus flac ota_server
ui_http_server eth_interface
ui_http_server improv_wifi eth_interface
)

View File

@@ -17,7 +17,8 @@
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#if CONFIG_SNAPCLIENT_ENABLE_ETHERNET
#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \
CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
#include "eth_interface.h"
#endif
@@ -25,6 +26,8 @@
#include "wifi_interface.h"
// Minimum ESP-IDF stuff only hardware abstraction stuff
#include <wifi_provisioning.h>
#include "board.h"
#include "es8388.h"
#include "esp_netif.h"
@@ -79,10 +82,11 @@ static FLAC__StreamDecoder *flacDecoder = NULL;
const char *VERSION_STRING = "0.0.3";
#define HTTP_TASK_PRIORITY 9
#define HTTP_TASK_CORE_ID tskNO_AFFINITY // 1 // tskNO_AFFINITY
#define HTTP_TASK_CORE_ID tskNO_AFFINITY
#define OTA_TASK_PRIORITY 4
#define OTA_TASK_PRIORITY 6
#define OTA_TASK_CORE_ID tskNO_AFFINITY
// 1 // tskNO_AFFINITY
TaskHandle_t t_ota_task = NULL;
TaskHandle_t t_http_get_task = NULL;
@@ -414,22 +418,6 @@ void error_callback(const FLAC__StreamDecoder *decoder,
FLAC__StreamDecoderErrorStatusString[status]);
}
/*
* Add one timeval to another.
*/
tv_t timeval_add(tv_t *a, tv_t *b) {
tv_t result;
result.sec = a->sec + b->sec;
result.usec = a->usec + b->usec;
if (result.usec >= 1000000) {
result.sec += 1;
result.usec -= 1000000;
}
return result;
} // timeval_add
/**
*
*/
@@ -621,7 +609,8 @@ static void http_get_task(void *pvParameters) {
char mac_address[18];
uint8_t base_mac[6];
// Get MAC address for WiFi station
#if CONFIG_SNAPCLIENT_ENABLE_ETHERNET
#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \
CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
esp_read_mac(base_mac, ESP_MAC_ETH);
#else
esp_read_mac(base_mac, ESP_MAC_WIFI_STA);
@@ -1749,8 +1738,6 @@ static void http_get_task(void *pvParameters) {
}
if (codec == OPUS) {
// ESP_LOGI(TAG, "OPUS not
// mplemented yet"); return;
uint16_t channels;
uint32_t rate;
uint16_t bits;
@@ -2408,15 +2395,20 @@ void app_main(void) {
ESP_ERROR_CHECK(ret);
esp_log_level_set("*", ESP_LOG_INFO);
// esp_log_level_set("c_I2S", ESP_LOG_NONE);
// if enabled these cause a timer srv stack overflow
esp_log_level_set("HEADPHONE", ESP_LOG_NONE);
esp_log_level_set("gpio", ESP_LOG_NONE);
esp_log_level_set("i2s_std", ESP_LOG_DEBUG);
esp_log_level_set("i2s_common", ESP_LOG_DEBUG);
esp_log_level_set("gpio", ESP_LOG_WARN);
esp_log_level_set("uart", ESP_LOG_WARN);
// esp_log_level_set("i2s_std", ESP_LOG_DEBUG);
// esp_log_level_set("i2s_common", ESP_LOG_DEBUG);
esp_log_level_set("wifi", ESP_LOG_WARN);
esp_log_level_set("wifi_init", ESP_LOG_WARN);
esp_log_level_set("wifi", ESP_LOG_WARN);
esp_log_level_set("wifi_init", ESP_LOG_WARN);
#if CONFIG_SNAPCLIENT_ENABLE_ETHERNET
#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \
CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
// clang-format off
// nINT/REFCLKO Function Select Configuration Strap
// • When nINTSEL is floated or pulled to
@@ -2516,9 +2508,35 @@ void app_main(void) {
// ESP_LOGI(TAG, "init player");
init_player();
// setup_ma120();
#if CONFIG_SNAPCLIENT_ENABLE_ETHERNET
// ensure there is no noise from DAC
{
board_i2s_pin_t pin_config0;
get_i2s_pins(I2S_NUM_0, &pin_config0);
gpio_config_t gpioCfg = {
.pin_bit_mask =
BIT64(pin_config0.mck_io_num) | BIT64(pin_config0.data_out_num) |
BIT64(pin_config0.bck_io_num) | BIT64(pin_config0.ws_io_num),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&gpioCfg);
gpio_set_level(pin_config0.mck_io_num, 0);
gpio_set_level(pin_config0.data_out_num, 0);
gpio_set_level(pin_config0.bck_io_num, 0);
gpio_set_level(pin_config0.ws_io_num, 0);
gpioCfg.pin_bit_mask = BIT64(pin_config0.data_in_num);
gpioCfg.mode = GPIO_MODE_INPUT;
gpioCfg.pull_up_en = GPIO_PULLUP_ENABLE;
gpio_config(&gpioCfg);
}
#if CONFIG_SNAPCLIENT_USE_INTERNAL_ETHERNET || \
CONFIG_SNAPCLIENT_USE_SPI_ETHERNET
eth_init();
// pass "WIFI_STA_DEF", "WIFI_AP_DEF", "ETH_DEF"
init_http_server_task("ETH_DEF");

1978
sdkconfig_PCM5102A Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2038
sdkconfig_TAS5805M Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff