Merge branch 'feature/update_factory_demo_for_box_and_boxlite' into 'master'

examples: update for support box and box_lite

See merge request ae_group/esp-box!27
This commit is contained in:
Wu Jian Gang
2022-03-08 13:00:43 +08:00
249 changed files with 195568 additions and 526703 deletions
+19
View File
@@ -0,0 +1,19 @@
name: Build examples
on:
push:
branches:
- master
pull_request:
jobs:
build-release-v4_4:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: esp-idf build
uses: espressif/[email protected]
with:
path: 'examples/factory_demo'
+2
View File
@@ -80,3 +80,5 @@ build
# lock files for examples and components
dependencies.lock
# managed_components for examples
managed_components
-7
View File
@@ -28,16 +28,9 @@ before_script:
build_demo_cmake:
<<: *build_examples_template
script:
- cd idf_patch
- python3 apply_patch.py -d $IDF_PATH
- cd ../
- cd examples/factory_demo
- idf.py fullclean
- idf.py build
- rm sdkconfig sdkconfig.defaults
- cp sdkconfig.defaults.cn sdkconfig.defaults
- idf.py build
- idf.py fullclean
- cd ../
- cd image_display
- idf.py fullclean
+3 -30
View File
@@ -1,39 +1,12 @@
[submodule "componets/lvgl/lvgl"]
path = componets/lvgl/lvgl
url = https://github.com/lvgl/lvgl.git
[submodule "componets/lvgl/lv_demos"]
path = componets/lvgl/lv_demos
url = https://github.com/lvgl/lv_demos.git
[submodule "components/lvgl/lv_demos"]
path = components/lvgl/lv_demos
url = https://github.com/lvgl/lv_demos.git
[submodule "components/lvgl/lvgl"]
path = components/lvgl/lvgl
url = https://github.com/lvgl/lvgl.git
[submodule "components/esp32-camera"]
path = components/esp32-camera
url = https://github.com/espressif/esp32-camera.git
[submodule "components/lvgl/lv_lib/lv_lib_png"]
path = components/lvgl/lv_lib/lv_lib_png
url = https://github.com/lvgl/lv_lib_png.git
[submodule "components/lvgl/lv_lib/lv_lib_bmp"]
path = components/lvgl/lv_lib/lv_lib_bmp
url = https://github.com/lvgl/lv_lib_bmp.git
[submodule "components/lvgl/lv_lib/lv_lib_split_jpg"]
path = components/lvgl/lv_lib/lv_lib_split_jpg
url = https://github.com/lvgl/lv_lib_split_jpg.git
[submodule "components/lvgl/lv_lib/lv_lib_gif"]
path = components/lvgl/lv_lib/lv_lib_gif
url = https://github.com/lvgl/lv_lib_gif.git
[submodule "components/lvgl/lv_lib/lv_lib_freetype"]
path = components/lvgl/lv_lib/lv_lib_freetype
url = https://github.com/lvgl/lv_lib_freetype.git
[submodule "examples/lvgl/freetype/main/lib/freetype"]
path = examples/lvgl/freetype/main/lib/freetype
url = https://gitlab.freedesktop.org/freetype/freetype.git
[submodule "components/esp-sr"]
path = components/esp-sr
url = https://github.com/espressif/esp-sr.git
[submodule "examples/freetype/main/lib/freetype"]
path = examples/freetype/main/lib/freetype
url = https://gitlab.freedesktop.org/freetype/freetype.git
[submodule "components/esp-rainmaker"]
path = components/esp-rainmaker
url = https://github.com/espressif/esp-rainmaker.git
+24 -3
View File
@@ -2,8 +2,11 @@
# ESP-BOX AIoT Development Framework
[![Build examples](https://github.com/espressif/esp-box/actions/workflows/build.yml/badge.svg)](https://github.com/espressif/esp-box/actions/workflows/build.yml)
**Important Note:**
> We recommend [updating the application firmware](./docs/firmware_update.md) when you first receive the product to have the latest features and bugfix.
> We recommend [updating the application firmware](./docs/firmware_update.md) when you first receive the product to have the new features and bugfix. Click [here](./docs/getting_started.md) to access the user guide of the latest release firmware. Click [here](https://github.com/espressif/esp-box/releases) to visit the older firmware.
The ESP-BOX is a new generation AIoT development platform released by Espressif Systems. The ESP32-S3-BOX and ESP32-S3-BOX-Lite are AIoT development boards that are based on Espressifs ESP32-S3 Wi-Fi + Bluetooth 5 (LE) SoC. They provide a platform for developing the control of home appliances using Voice Assistance + touch and screen controller, sensor, infrared controller, and intelligent Wi-Fi gateway. Development boards come with pre-built firmware that supports offline voice interaction, with the SDKs and examples provided by Espressif, you will be able to develop a wide variety of AIoT applications based on the BOX series products such as online and offline voice assistants, voice-enabled devices, human-computer interaction devices, control panels, multi-protocol gateways easily.
@@ -16,18 +19,29 @@ The ESP-BOX is a new generation AIoT development platform released by Espressif
| ESP-Box | Dependent ESP-IDF | Branch Note | Support State |
| :--------------: | :---------------: | :----------------------------------------------------: | -------------- |
| master | release/v4.4<br>commit id: 35b20cadce65 | esp-sr version: v0.9.6<br>commit id: a289a0c7 | new feature develop |
| master | release/v4.4<br>commit id: 2bdea81b2a | Latest developing firmware <br/>esp-sr version: dev/v2.0<br>commit id: c873a35 | New feature develop, compatible with ESP32-S3-BOX and ESP32-S3-BOX-Lite |
| Tag 0.2.1 | release/v4.4 with [patch](https://github.com/espressif/esp-box/tree/v0.2.1/idf_patch) | esp-sr version: close v1.0<br/>commit id: 3ce34fe | Support ESP32-S3-BOX only |
| Tag 0.1.1 | release/v4.4 with [patch](https://github.com/espressif/esp-box/tree/v0.1.1/idf_patch) | esp-sr version: v0.9.6<br/>commit id: 3ce34fe | Support ESP32-S3-BOX only |
## Features
* Supports far-field voice interaction with 2 mics
* Offline voice wake-up with high wake-up rate
* Offline speech commands recognition in Chinese and English languages with high recognition rate
* Reconfigurable 200+ speech commands in Chinese and English languages
* Continuous Identification and Wakeup Interrupt
* Flexible and reusable GUI framework
* End-to-end AIoT dvelopment framwork ESP-RainMaker
* Pmod™ compatible headers support expand peripheral modules
## Open-Source Content
* [Schematic and PCB Source File](./hardware)
@@ -41,6 +55,7 @@ The ESP-BOX is a new generation AIoT development platform released by Espressif
* For getting start of BOX serial development boards, please refer to the [Getting Started](./docs/getting_started.md)
* For experiencing voice assistant, please refer to the [Voice Assistance Control and Customization](./docs/getting_started.md#offline-voice-assistant-with-your-device)
* For experiencing a more humanized interactive experience, please refer to the [Continuous Speech Recognition](./docs/getting_started.md#continuous-recognition)
* For defining the speech commands by mobile APP, please refer to the [ESP-BOX APP User Guide](./docs/getting_started.md#voice-command-customization)
* For product exploded-view and disassembly tutorial, please refer to [Disassembly Tutorial](docs/disassembly_tutorial.md)
* For more detils of hardware information, please refer to the [Hardware Overview](./docs/hardware_overview).
@@ -59,5 +74,11 @@ The ESP-BOX is a new generation AIoT development platform released by Espressif
## Contact Us
* If you have any technical issues, please submit issue tickets at [GitHub Issues](https://github.com/espressif/esp-box/issues) or forum [esp32.com](https://esp32.com/) for help.
* If you are interested in ESP-BOX project, welcome to the [ESP-BOX forum](https://esp32.com/viewforum.php?f=44) to share with us your ideas.
* We welcome any open-source software or hardware contribution. Please commit to the [Pull Requests](https://github.com/espressif/esp-box/pulls) to contribute your code.
## Contributing Examples
We welcome any open-source software or hardware contribution. If you have any examples you want to share with us, please click the [Contributions Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/contribute/index.html) and commit to the [Pull Requests](https://github.com/espressif/esp-box/pulls) to contribute your code.
+16 -5
View File
@@ -3,8 +3,10 @@
# ESP-BOX AIoT 开发框架
[![Build examples](https://github.com/espressif/esp-box/actions/workflows/build.yml/badge.svg)](https://github.com/espressif/esp-box/actions/workflows/build.yml)
**重要提醒:**
> 我们建议您在第一次收到产品时[更新应用固件](./docs/firmware_update_cn.md)以获得最新功能和 bug 的修复。
> 我们建议您在第一次收到产品时[更新应用固件](./docs/firmware_update_cn.md)以获得最新功能和 bug 的修复,点此[链接](./docs/getting_started_cn.md)获取应用固件的使用说明。点击[此处](https://github.com/espressif/esp-box/releases)查看历史固件
ESP-BOX 是乐鑫信息科技发布的新一代 AIoT 应用开发平台。ESP32-S3-BOX 和 ESP32-S3-BOX-Lite 是目前对应的 AIoT 应用开发板,搭载支持 AI 加速的 ESP32-S3 Wi-Fi + Bluetooth 5 (LE) SoC。他们为用户提供了一个基于语音助手 + 触摸屏控制、传感器、红外控制器和智能 Wi-Fi 网关等功能,开发和控制智能家居设备的平台。开发板出厂支持离线语音交互功能,用户通过乐鑫丰富的 SDK 和解决方案,能够轻松构建在线和离线语音助手、智能语音设备、HMI 人机交互设备、控制面板、多协议网关等多样的应用。
@@ -15,9 +17,11 @@ ESP-BOX 是乐鑫信息科技发布的新一代 AIoT 应用开发平台。ESP32-
## 版本信息
| ESP-Box | 依赖的 ESP-IDF | 分支信息 | 支持状态 |
| :--------------: | :---------------: | :----------------------------------------------------: | -------------- |
| master | release/v4.4<br>commit id: 35b20cadce65 | esp-sr version: v0.9.6<br>commit id: a289a0c7 | 新功能开发分支 |
| ESP-Box | 依赖的 ESP-IDF | 分支信息 | 支持状态 |
| :-------: | :----------------------------------------------------------: | :----------------------------------------------------------: | ------------------------------------------------------- |
| master | release/v4.4<br/>commit id: 2bdea81b2a | Latest developing firmware <br/>esp-sr version: dev/v2.0<br/>commit id: c873a35 | 新功能开发分支,兼容 ESP32-S3-BOX 和 ESP32-S3-BOX-Lite |
| Tag 0.2.1 | release/v4.4 with [patch](https://github.com/espressif/esp-box/tree/v0.2.1/idf_patch) | esp-sr version: close v1.0<br/>commit id: 3ce34fe | 仅支持 ESP32-S3-BOX |
| Tag 0.1.1 | Release/v4.4 with [patch](https://github.com/espressif/esp-box/tree/v0.1.1/idf_patch) | esp-sr version: v0.9.6<br/>commit id: 3ce34fe | 仅支持 ESP32-S3-BOX |
## 支持特性
@@ -25,6 +29,7 @@ ESP-BOX 是乐鑫信息科技发布的新一代 AIoT 应用开发平台。ESP32-
* 高唤醒率的离线语音唤醒
* 高识别率的离线中英文命令词识别
* 可动态配置 200+ 中英文命令词
* 连续识别和唤醒打断
* 灵活可复用的 GUI 框架
* 端到端一站式接入云平台
* Pmod™ 兼容接口支持多种外设扩展
@@ -42,6 +47,7 @@ ESP-BOX 是乐鑫信息科技发布的新一代 AIoT 应用开发平台。ESP32-
* 首次拿到 BOX 系列开发板,您可以查看 [首次使用操作指引](./docs/getting_started_cn.md#给设备供电)
* 想要体验离线语音助手功能,您可以查看 [离线语音识别](./docs/getting_started_cn.md#体验离线语音识别)
* 体验更人性化的语音交互,可查看 [连续语音识别](./docs/getting_started_cn.md#连续语音识别)
* 想要通过手机 APP 设置独特的语音命令词,请查看 [ESP-BOX APP 操作指引](./docs/getting_started_cn.md#语音命令词自定义)
* 想要了解产品爆炸图和拆机说明,请查看 [拆机教程](docs/disassembly_tutorial.md)
* 想要了解开发板硬件和接口细节,请查看 [硬件总览](./docs/hardware_overview)
@@ -60,5 +66,10 @@ ESP-BOX 是乐鑫信息科技发布的新一代 AIoT 应用开发平台。ESP32-
## 联系我们
* 如果有任何开发和使用问题,您可添加 [GitHub Issues](https://github.com/espressif/esp-box/issues) 或到 [esp32.com](https://esp32.com/) 论坛寻求帮助;
* 如果你对 ESP-BOX 项目感兴趣,欢迎到论坛 [ESP-BOX 版块](https://www.esp32.com/viewforum.php?f=43) 交流想法;
* 我们欢迎任何软件或硬件相关的开源贡献,您可直接提交 [Pull Requests](https://github.com/espressif/esp-box/pulls) 贡献代码。
## 贡献示例
我们欢迎任何软件或硬件相关的开源贡献,如果您有任何要与我们分享的示例,请参考 [贡献指南](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/contribute/index.html) 后提交 [Pull Requests](https://github.com/espressif/esp-box/pulls) 贡献代码。
+20 -19
View File
@@ -1,29 +1,30 @@
file(GLOB_RECURSE BSP_SRCS
"src/bsp_codec.c"
"src/bsp_i2c.c"
"src/bsp_i2s.c"
"src/bsp_tp.c"
"src/lcd/*.c"
"src/storage/*.c")
if(CONFIG_ESP32_S3_BOX_BOARD)
list(APPEND BSP_BOARD_SRC "./boards/esp32_s3_box.c")
endif()
if(CONFIG_ESP_CUSTOM_BOARD)
list(APPEND BSP_BOARD_SRC "./boards/esp_custom_board.c")
endif()
idf_component_register(
SRCS
${BSP_SRCS}
${BSP_BOARD_SRC}
SRC_DIRS
"src/boards"
"src/peripherals"
"src/storage"
"src/codec/es7210"
"src/codec/es7243e"
"src/codec/es8156"
"src/codec/es8311"
"src/codec/es8388"
INCLUDE_DIRS
"boards"
"src/boards"
"include"
"src/codec/es7210"
"src/codec/es7243e"
"src/codec/es8156"
"src/codec/es8311"
"src/codec/es8388"
"src/codec/include"
REQUIRES
codec
i2c_devices
iot_button
esp_hid
esp_lcd
fatfs
i2c_bus
i2c_devices
spiffs)
+2 -155
View File
@@ -1,16 +1,6 @@
menu "HMI Board Config"
choice HMI_BOARD
prompt "HMI board"
default ESP32_S3_BOX_BOARD
help
Select an HMI board to use with the HMI project
config ESP32_S3_BOX_BOARD
bool "ESP32-S3 Box Dev Board"
depends on IDF_TARGET_ESP32S3
config ESP_CUSTOM_BOARD
bool "Custom HMI board"
endchoice
choice LCD_INTERFACE
prompt "Select LCD interface"
@@ -28,149 +18,6 @@ menu "HMI Board Config"
endchoice
menu "I80 LCD GPIO configuration"
depends on LCD_INTERFACE_I80
choice LCD_BIT_WIDTH
prompt "LCD Data Line Width"
default LCD_BIT_WIDTH_8_BIT
help
Lines of LCD data bus.
config LCD_BIT_WIDTH_8_BIT
bool "8 Bit"
config LCD_BIT_WIDTH_16_BIT
bool "16 Bit"
endchoice
config LCD_WR_GPIO
int "LCD WR GPIO"
range 0 48
default 34
config LCD_RS_GPIO
int "LCD RS GPIO"
range 0 48
default 33
config LCD_D00_GPIO
int "LCD D00 GPIO"
range 0 48
default 16
config LCD_D01_GPIO
int "LCD D01 GPIO"
range 0 48
default 15
config LCD_D02_GPIO
int "LCD D02 GPIO"
range 0 48
default 14
config LCD_D03_GPIO
int "LCD D03 GPIO"
range 0 48
default 13
config LCD_D04_GPIO
int "LCD D04 GPIO"
range 0 48
default 12
config LCD_D05_GPIO
int "LCD D05 GPIO"
range 0 48
default 11
config LCD_D06_GPIO
int "LCD D06 GPIO"
range 0 48
default 10
config LCD_D07_GPIO
int "LCD D07 GPIO"
range 0 48
default 9
config LCD_D08_GPIO
int "LCD D08 GPIO"
range 0 48
default 8
depends on LCD_BIT_WIDTH_16_BIT
config LCD_D09_GPIO
int "LCD D09 GPIO"
range 0 48
default 7
depends on LCD_BIT_WIDTH_16_BIT
config LCD_D10_GPIO
int "LCD D10 GPIO"
range 0 48
default 6
depends on LCD_BIT_WIDTH_16_BIT
config LCD_D11_GPIO
int "LCD D11 GPIO"
range 0 48
default 5
depends on LCD_BIT_WIDTH_16_BIT
config LCD_D12_GPIO
int "LCD D12 GPIO"
range 0 48
default 4
depends on LCD_BIT_WIDTH_16_BIT
config LCD_D13_GPIO
int "LCD D13 GPIO"
range 0 48
default 3
depends on LCD_BIT_WIDTH_16_BIT
config LCD_D14_GPIO
int "LCD D14 GPIO"
range 0 48
default 2
depends on LCD_BIT_WIDTH_16_BIT
config LCD_D15_GPIO
int "LCD D15 GPIO"
range 0 48
default 1
depends on LCD_BIT_WIDTH_16_BIT
endmenu
menu "I2C GPIO configuration"
depends on ESP_CUSTOM_BOARD
config I2C_SCL_GPIO
int "I2C SCL GPIO"
range 0 48
default 36
config I2C_SDA_GPIO
int "I2C SDA GPIO"
range 0 48
default 35
endmenu
menu "SPI GPIO configuration"
depends on ESP_CUSTOM_BOARD
config SPI_CS_GPIO
int "SPI CS GPIO"
range 0 48
default 37
config SPI_MISO_GPIO
int "SPI MISO GPIO"
range 0 48
default 40
config SPI_MOSI_GPIO
int "SPI MOSI GPIO"
range 0 48
default 38
config SPI_SCLK_GPIO
int "SPI SCLK GPIO"
range 0 48
default 39
endmenu
menu "Touch Panel Drivers"
depends on ESP_CUSTOM_BOARD
menu "Config Input Value"
config TOUCH_PANEL_INVERSE_X
bool "Reverse X Axis"
default n
config TOUCH_PANEL_INVERSE_Y
bool "Reverse Y Axis"
default n
config TOUCH_PANEL_SWAP_XY
bool "Swap X and Y Axis"
default n
endmenu
endmenu
endmenu
-98
View File
@@ -1,98 +0,0 @@
/**
* @file esp32_s3_box.c
* @brief
* @version 0.1
* @date 2021-07-28
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "driver/gpio.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_rom_sys.h"
#include "bsp_board.h"
#include "bsp_i2c.h"
#define GPIO_MUTE_NUM GPIO_NUM_1
#define GPIO_MUTE_LEVEL 1
static const char *TAG = "board";
__attribute__((weak)) void mute_btn_handler(void *arg)
{
if (GPIO_MUTE_LEVEL == gpio_get_level(GPIO_MUTE_NUM)) {
esp_rom_printf(DRAM_STR("Mute Off"));
} else {
esp_rom_printf(DRAM_STR("Mute On"));
}
}
esp_err_t bsp_board_init(void)
{
/*!< Mute_Button on ESP32-S3-Box */
gpio_config_t io_conf_key;
io_conf_key.intr_type = GPIO_INTR_ANYEDGE;
io_conf_key.mode = GPIO_MODE_INPUT;
io_conf_key.pin_bit_mask = 1ULL << GPIO_MUTE_NUM;
io_conf_key.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf_key.pull_up_en = GPIO_PULLUP_ENABLE;
ESP_ERROR_CHECK(gpio_config(&io_conf_key));
/* Install GPIO ISR service to enable GPIO ISR callback */
gpio_install_isr_service(0);
ESP_ERROR_CHECK(gpio_isr_handler_add(GPIO_MUTE_NUM, mute_btn_handler, NULL));
/*!< Initialize I2C bus, used for TP ,audio codec and IMU */
bsp_i2c_init(I2C_NUM_0, 400 * 1000);
return ESP_OK;
}
esp_err_t bsp_board_power_ctrl(power_module_t module, bool on)
{
/* Config power control IO */
static esp_err_t bsp_io_config_state = ESP_FAIL;
if (ESP_OK != bsp_io_config_state) {
gpio_config_t io_conf;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = 1ULL << GPIO_PWR_CTRL;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
bsp_io_config_state = gpio_config(&io_conf);
}
/* Checko IO config result */
if (ESP_OK != bsp_io_config_state) {
ESP_LOGE(TAG, "Failed initialize power control IO");
return bsp_io_config_state;
}
/* Control independent power domain */
switch (module) {
case POWER_MODULE_LCD:
gpio_set_level(GPIO_LCD_BL, on ? (GPIO_LCD_BL_ON) : (!GPIO_LCD_BL_ON));
break;
case POWER_MODULE_AUDIO:
case POWER_MODULE_ALL:
gpio_set_level(GPIO_PWR_CTRL, on ? (GPIO_PWR_ON_LEVEL) : (!GPIO_PWR_ON_LEVEL));
break;
default:
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
-127
View File
@@ -1,127 +0,0 @@
/**
* @file esp32_s3_box.h
* @version 0.1
* @date 2021-06-25
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "driver/gpio.h"
/**
* @brief ESP32-S3-Box LCD GPIO defination and config
*
*/
#define FUNC_LCD_EN (1)
#define LCD_BUS_WIDTH (1)
#define LCD_IFACE_SPI (1)
#define LCD_DISP_IC_ST (1)
#define LCD_WIDTH (320)
#define LCD_HEIGHT (240)
#define LCD_FREQ (40 * 1000 * 1000)
#define LCD_HOST (SPI2_HOST)
#define LCD_SWAP_XY (0)
#define LCD_MIRROR_X (true)
#define LCD_MIRROR_Y (true)
#define LCD_COLOR_INV (false)
#define GPIO_LCD_BL (GPIO_NUM_45)
#define GPIO_LCD_BL_ON (1)
#define GPIO_LCD_CS (GPIO_NUM_5)
#define GPIO_LCD_RST (GPIO_NUM_48)
#define GPIO_LCD_DC (GPIO_NUM_4)
#define GPIO_LCD_CLK (GPIO_NUM_7)
#define GPIO_LCD_DIN (GPIO_NUM_6)
#define GPIO_LCD_DOUT (GPIO_NUM_NC)
#define TOUCH_PANEL_SWAP_XY (0)
#define TOUCH_PANEL_INVERSE_X (1)
#define TOUCH_PANEL_INVERSE_Y (0)
/**
* @brief ESP32-S3-Box I2C GPIO defineation
*
*/
#define FUNC_I2C_EN (1)
#define GPIO_I2C_SCL (GPIO_NUM_18)
#define GPIO_I2C_SDA (GPIO_NUM_8)
/**
* @brief ESP32-S3-Box SDMMC GPIO defination
*
* @note Only avaliable when PMOD connected
*/
#define FUNC_SDMMC_EN (1)
#define SDMMC_BUS_WIDTH (4)
#define GPIO_SDMMC_CLK (GPIO_NUM_13)
#define GPIO_SDMMC_CMD (GPIO_NUM_11)
#define GPIO_SDMMC_D0 (GPIO_NUM_14)
#define GPIO_SDMMC_D1 (GPIO_NUM_12)
#define GPIO_SDMMC_D2 (GPIO_NUM_10)
#define GPIO_SDMMC_D3 (GPIO_NUM_9)
#define GPIO_SDMMC_DET (GPIO_NUM_NC)
/**
* @brief ESP32-S3-Box SDSPI GPIO definationv
*
*/
#define FUNC_SDSPI_EN (0)
#define SDSPI_HOST (SPI2_HOST)
#define GPIO_SDSPI_CS (GPIO_NUM_NC)
#define GPIO_SDSPI_SCLK (GPIO_NUM_NC)
#define GPIO_SDSPI_MISO (GPIO_NUM_NC)
#define GPIO_SDSPI_MOSI (GPIO_NUM_NC)
/**
* @brief ESP32-S3-Box SPI GPIO defination
*
*/
#define FUNC_SPI_EN (0)
#define GPIO_SPI_CS (GPIO_NUM_NC)
#define GPIO_SPI_MISO (GPIO_NUM_NC)
#define GPIO_SPI_MOSI (GPIO_NUM_NC)
#define GPIO_SPI_SCLK (GPIO_NUM_NC)
/**
* @brief ESP32-S3-Box RMT GPIO defination
*
*/
#define FUNC_RMT_EN (0)
#define GPIO_RMT_IR (GPIO_NUM_NC)
#define GPIO_RMT_LED (GPIO_NUM_39)
/**
* @brief ESP32-S3-Box I2S GPIO defination
*
*/
#define FUNC_I2S_EN (1)
#define GPIO_I2S_LRCK (GPIO_NUM_47)
#define GPIO_I2S_MCLK (GPIO_NUM_2)
#define GPIO_I2S_SCLK (GPIO_NUM_17)
#define GPIO_I2S_SDIN (GPIO_NUM_16)
#define GPIO_I2S_DOUT (GPIO_NUM_15)
/**
* @brief ESP32-S3-HMI-DevKit power control IO
*
* @note Some power control pins might not be listed yet
*
*/
#define FUNC_PWR_CTRL (1)
#define GPIO_PWR_CTRL (GPIO_NUM_46)
#define GPIO_PWR_ON_LEVEL (1)
-42
View File
@@ -1,42 +0,0 @@
/**
* @file esp_custom_board.c
* @brief
* @version 0.1
* @date 2021-10-20
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdbool.h>
#include "bsp_board.h"
#include "esp_custom_board.h"
#include "esp_err.h"
esp_err_t bsp_board_init(void)
{
/* **************** ADD BOARD INITIAL CODE HERE **************** */
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t bsp_board_power_ctrl(power_module_t module, bool on)
{
(void) module;
(void) on;
/* **************** ADD BOARD POWER CONTROL CODE HERE **************** */
return ESP_ERR_NOT_SUPPORTED;
}
-127
View File
@@ -1,127 +0,0 @@
/**
* @file esp_custom_board.h
* @version 0.1
* @date 2021-06-25
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "driver/gpio.h"
/**
* @brief ESP-Dev-Board LCD GPIO defination and config
*
*/
#define FUNC_LCD_EN (1)
#define LCD_BUS_WIDTH (1)
#define LCD_IFACE_SPI (1)
#define LCD_DISP_IC_ST (1)
#define LCD_WIDTH (320)
#define LCD_HEIGHT (240)
#define LCD_FREQ (40 * 1000 * 1000)
#define LCD_HOST (SPI2_HOST)
#define LCD_SWAP_XY (0)
#define LCD_MIRROR_X (false)
#define LCD_MIRROR_Y (false)
#define LCD_COLOR_INV (false)
#define GPIO_LCD_BL (GPIO_NUM_NC)
#define GPIO_LCD_BL_ON (1)
#define GPIO_LCD_CS (GPIO_NUM_NC)
#define GPIO_LCD_RST (GPIO_NUM_NC)
#define GPIO_LCD_DC (GPIO_NUM_NC)
#define GPIO_LCD_CLK (GPIO_NUM_NC)
#define GPIO_LCD_DIN (GPIO_NUM_NC)
#define GPIO_LCD_DOUT (GPIO_NUM_NC)
#define TOUCH_PANEL_SWAP_XY (0)
#define TOUCH_PANEL_INVERSE_X (0)
#define TOUCH_PANEL_INVERSE_Y (0)
/**
* @brief ESP-Dev-Board I2C GPIO defineation
*
*/
#define FUNC_I2C_EN (1)
#define GPIO_I2C_SCL (GPIO_NUM_NC)
#define GPIO_I2C_SDA (GPIO_NUM_NC)
/**
* @brief ESP-Dev-Board SDMMC GPIO defination
*
* @note Only avaliable when PMOD connected
*/
#define FUNC_SDMMC_EN (1)
#define SDMMC_BUS_WIDTH (4)
#define GPIO_SDMMC_CLK (GPIO_NUM_NC)
#define GPIO_SDMMC_CMD (GPIO_NUM_NC)
#define GPIO_SDMMC_D0 (GPIO_NUM_NC)
#define GPIO_SDMMC_D1 (GPIO_NUM_NC)
#define GPIO_SDMMC_D2 (GPIO_NUM_NC)
#define GPIO_SDMMC_D3 (GPIO_NUM_NC)
#define GPIO_SDMMC_DET (GPIO_NUM_NC)
/**
* @brief ESP-Dev-Board SDSPI GPIO definationv
*
*/
#define FUNC_SDSPI_EN (0)
#define SDSPI_HOST (SPI2_HOST)
#define GPIO_SDSPI_CS (GPIO_NUM_NC)
#define GPIO_SDSPI_SCLK (GPIO_NUM_NC)
#define GPIO_SDSPI_MISO (GPIO_NUM_NC)
#define GPIO_SDSPI_MOSI (GPIO_NUM_NC)
/**
* @brief ESP-Dev-Board SPI GPIO defination
*
*/
#define FUNC_SPI_EN (0)
#define GPIO_SPI_CS (GPIO_NUM_NC)
#define GPIO_SPI_MISO (GPIO_NUM_NC)
#define GPIO_SPI_MOSI (GPIO_NUM_NC)
#define GPIO_SPI_SCLK (GPIO_NUM_NC)
/**
* @brief ESP-Dev-Board RMT GPIO defination
*
*/
#define FUNC_RMT_EN (0)
#define GPIO_RMT_IR (GPIO_NUM_NC)
#define GPIO_RMT_LED (GPIO_NUM_39)
/**
* @brief ESP-Dev-Board I2S GPIO defination
*
*/
#define FUNC_I2S_EN (1)
#define GPIO_I2S_LRCK (GPIO_NUM_NC)
#define GPIO_I2S_MCLK (GPIO_NUM_NC)
#define GPIO_I2S_SCLK (GPIO_NUM_NC)
#define GPIO_I2S_SDIN (GPIO_NUM_NC)
#define GPIO_I2S_DOUT (GPIO_NUM_NC)
/**
* @brief ESP32-S3-HMI-DevKit power control IO
*
* @note Some power control pins might not be listed yet
*
*/
#define FUNC_PWR_CTRL (1)
#define GPIO_PWR_CTRL (GPIO_NUM_NC)
#define GPIO_PWR_ON_LEVEL (1)
+219 -34
View File
@@ -1,49 +1,187 @@
/**
* @file bsp_board.h
* @brief
* @version 0.1
* @date 2021-06-25
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "esp_err.h"
/**
* @brief Add dev board pin defination and check target.
*
*/
#if CONFIG_ESP32_S3_BOX_BOARD
#include "esp32_s3_box.h"
#elif CONFIG_ESP_CUSTOM_BOARD
#include "esp_custom_board.h"
#else
#error "Please select type of dev board"
#endif
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "driver/adc.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_types.h"
#include "audio_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
BOARD_S3_BOX,
BOARD_S3_BOX_LITE,
} boards_id_t;
typedef enum {
BOARD_BTN_ID_BOOT = 0, // The index is the same as the sequence number of the board_button_t array
BOARD_BTN_ID_PREV = 1,
BOARD_BTN_ID_ENTER = 2,
BOARD_BTN_ID_NEXT = 3,
} board_btn_id_t;
typedef struct {
board_btn_id_t id;
uint32_t vol; // for adc button
gpio_num_t io_num; // for gpio button, Set GPIO_NUM_NC to indicate this button is adc button
bool active_level; // for gpio button
} board_button_t;
typedef struct {
gpio_num_t row1[4]; //The first row
gpio_num_t row2[4];
} pmod_pins_t;
typedef struct {
/**
* @brief ESP-Dev-Board LCD GPIO defination and config
*
*/
bool FUNC_LCD_EN ;
int LCD_BUS_WIDTH ;
int LCD_IFACE_SPI ;
int LCD_DISP_IC_ST ;
int LCD_WIDTH ;
int LCD_HEIGHT ;
int LCD_FREQ ;
int LCD_CMD_BITS ;
int LCD_PARAM_BITS ;
spi_host_device_t LCD_HOST;
bool LCD_SWAP_XY ;
bool LCD_MIRROR_X ;
bool LCD_MIRROR_Y ;
bool LCD_COLOR_INV ;
esp_lcd_color_space_t LCD_COLOR_SPACE;
int GPIO_LCD_BL ;
int GPIO_LCD_BL_ON ;
int GPIO_LCD_CS ;
int GPIO_LCD_RST ;
int GPIO_LCD_DC ;
int GPIO_LCD_CLK ;
int GPIO_LCD_DIN ;
int GPIO_LCD_DOUT ;
int GPIO_LCD_D00 ; // only use for OCTAL SPI(aka 8080 interface)
int GPIO_LCD_D01 ;
int GPIO_LCD_D02 ;
int GPIO_LCD_D03 ;
int GPIO_LCD_D04 ;
int GPIO_LCD_D05 ;
int GPIO_LCD_D06 ;
int GPIO_LCD_D07 ;
bool BSP_INDEV_IS_TP;
bool TOUCH_PANEL_SWAP_XY;
bool TOUCH_PANEL_INVERSE_X;
bool TOUCH_PANEL_INVERSE_Y;
int TOUCH_PANEL_I2C_ADDR;
bool TOUCH_WITH_HOME_BUTTON;
bool BSP_BUTTON_EN;
adc1_channel_t BUTTON_ADC_CHAN; // only use for adc button
const board_button_t *BUTTON_TAB;
uint8_t BUTTON_TAB_LEN;
/**
* @brief ESP-Dev-Board I2C GPIO defineation
*
*/
bool FUNC_I2C_EN ;
int GPIO_I2C_SCL ;
int GPIO_I2C_SDA ;
/**
* @brief ESP-Dev-Board SDMMC GPIO defination
*
* @note Only avaliable when PMOD connected
*/
bool FUNC_SDMMC_EN ;
int SDMMC_BUS_WIDTH ;
int GPIO_SDMMC_CLK ;
int GPIO_SDMMC_CMD ;
int GPIO_SDMMC_D0 ;
int GPIO_SDMMC_D1 ;
int GPIO_SDMMC_D2 ;
int GPIO_SDMMC_D3 ;
int GPIO_SDMMC_DET ;
/**
* @brief ESP-Dev-Board SDSPI GPIO definationv
*
*/
bool FUNC_SDSPI_EN ;
int SDSPI_HOST ;
int GPIO_SDSPI_CS ;
int GPIO_SDSPI_SCLK ;
int GPIO_SDSPI_MISO ;
int GPIO_SDSPI_MOSI ;
/**
* @brief ESP-Dev-Board SPI GPIO defination
*
*/
bool FUNC_SPI_EN ;
int GPIO_SPI_CS ;
int GPIO_SPI_MISO ;
int GPIO_SPI_MOSI ;
int GPIO_SPI_SCLK ;
/**
* @brief ESP-Dev-Board RMT GPIO defination
*
*/
bool FUNC_RMT_EN ;
int GPIO_RMT_IR ;
int GPIO_RMT_LED ;
/**
* @brief ESP-Dev-Board I2S GPIO defination
*
*/
bool FUNC_I2S_EN ;
int GPIO_I2S_LRCK ;
int GPIO_I2S_MCLK ;
int GPIO_I2S_SCLK ;
int GPIO_I2S_SDIN ;
int GPIO_I2S_DOUT ;
int CODEC_I2C_ADDR;
int AUDIO_ADC_I2C_ADDR;
int IMU_I2C_ADDR;
/**
* @brief ESP32-S3-HMI-DevKit power control IO
*
* @note Some power control pins might not be listed yet
*
*/
int FUNC_PWR_CTRL ;
int GPIO_PWR_CTRL ;
int GPIO_PWR_ON_LEVEL ;
int GPIO_MUTE_NUM ;
int GPIO_MUTE_LEVEL ;
const pmod_pins_t *PMOD1;
const pmod_pins_t *PMOD2;
} board_res_desc_t;
/**
* @brief Power module of dev board. This can be expanded in the future.
*
*
*/
typedef enum {
POWER_MODULE_LCD = 1, /*!< LCD power control */
@@ -51,18 +189,65 @@ typedef enum {
POWER_MODULE_ALL = 0xff, /*!< All module power control */
} power_module_t;
typedef struct {
boards_id_t id;
const char *name;
/**
* @brief Special config for dev board
*
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t (*board_init)(void);
/**
* @brief Control power of dev board
*
* @param module Refer to `power_module_t`
* @param on Turn on or off specified power module. On if true
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t (*board_power_ctrl)(power_module_t module, bool on);
/**
* @brief Get board description
*
* @return pointer of board_res_desc_t
*/
const board_res_desc_t *(*board_get_res_desc)(void);
} boards_info_t;
/**
* @brief Special config for dev board
*
*
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t bsp_board_init(void);
/**
* @brief Get the board information
*
* @return pointer of boards_info_t
*/
const boards_info_t *bsp_board_get_info(void);
/**
* @brief Get board description
*
* @return pointer of board_res_desc_t
*/
const board_res_desc_t *bsp_board_get_description(void);
/**
* @brief Control power of dev board
*
*
* @param module Refer to `power_module_t`
* @param on Turn on or off specified power module. On if true
* @return
+61
View File
@@ -0,0 +1,61 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include "esp_err.h"
#include "button.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Call default button init code
*
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t bsp_btn_init_default(void);
/**
* @brief Register callback for button event
*
* @param btn_id 0 based index of the button
* @param event Event of button to register
* @param callback Callback function
* @param user_data User data
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t bsp_btn_register_callback(board_btn_id_t btn_id, button_event_t event, button_cb_t callback, void *user_data);
/**
* @brief Remove all callbacks of the button
*
* @param btn_id 0 based index of the button
* @return
* - ESP_OK: Success
* - ESP_ERR_INVALID_STATE: button not be initialize
* - ESP_ERR_INVALID_ARG: button id error
*/
esp_err_t bsp_btn_rm_all_callback(board_btn_id_t btn_id);
/**
* @brief Get the press state of the button
*
* @param btn_id 0 based index of the button
*
* @return
* - TRUE pressed state
* - FALSE released state
*/
bool bsp_btn_get_state(board_btn_id_t btn_id);
#ifdef __cplusplus
}
#endif
+53 -18
View File
@@ -1,22 +1,7 @@
/**
* @author your name ([email protected])
* @brief
* @version 0.1
* @date 2021-07-20
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
@@ -28,6 +13,25 @@
extern "C" {
#endif
typedef enum {
CODEC_DEV_ES7210 = 0x01,
CODEC_DEV_ES7243 = 0x02,
CODEC_DEV_ES8156 = 0x04,
CODEC_DEV_ES8311 = 0x08,
// CODEC_DEV_ES8388,
} codec_dev_t;
/**
* @brief Detect Codecs on the board
*
* @param devices [out] bitmask of detected codec devices, see codec_dev_t
* @return
* - ESP_OK: Success
* - ESP_ERR_NOT_FOUND: Codec not detected on I2C bus
* - Others: Fail
*/
esp_err_t bsp_codec_detect(uint32_t *devices);
/**
* @brief Initialize Codec on dev board
*
@@ -40,6 +44,37 @@ extern "C" {
*/
esp_err_t bsp_codec_init(audio_hal_iface_samples_t sample_rate);
/**
* @brief Set output volume of Codec
*
* @param volume volume to set
* @return
* - ESP_OK: Success
* - ESP_ERR_NOT_FOUND: Codec not detected on I2C bus
*/
esp_err_t bsp_codec_set_voice_volume(uint8_t volume);
/**
* @brief Set input microphone gain of Codec
*
* @param channel_mask mask of channel
* @param volume volume to set
* @return
* - ESP_OK: Success
* - ESP_ERR_NOT_FOUND: Codec not detected on I2C bus
*/
esp_err_t bsp_codec_set_voice_gain(uint8_t channel_mask, uint8_t volume);
/**
* @brief Configure I2S format
*
* @param fmt: I2S format
* @return
* - ESP_OK: Success
* - ESP_FAIL: Fail
*/
esp_err_t bsp_codec_set_fmt(audio_hal_iface_format_t fmt);
#ifdef __cplusplus
}
#endif
+13 -19
View File
@@ -1,22 +1,7 @@
/**
* @file bsp_i2c.h
* @brief
* @version 0.1
* @date 2021-06-25
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
@@ -42,11 +27,20 @@ extern "C" {
*
* @param i2c_num I2C port num
* @param clk_speed I2C clock speed
* @param scl_io
* @param sda_io
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t bsp_i2c_init(i2c_port_t i2c_num, uint32_t clk_speed);
esp_err_t bsp_i2c_init(i2c_port_t i2c_num, uint32_t clk_speed, gpio_num_t scl_io, gpio_num_t sda_io);
/**
* @brief Deinitialize I2C bus
*
* @return esp_err_t
*/
esp_err_t bsp_i2c_deinit(void);
/**
* @brief Prob given address on I2C bus
+3 -18
View File
@@ -1,22 +1,7 @@
/**
* @file bsp_i2s.h
* @brief
* @version 0.1
* @date 2021-08-02
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
+14 -31
View File
@@ -1,22 +1,7 @@
/**
* @file bsp_lcd.h
* @brief
* @version 0.1
* @date 2021-07-05
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
@@ -24,8 +9,6 @@
#include <stdbool.h>
#include "bsp_board.h"
#include "esp_err.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_types.h"
#include "freertos/FreeRTOS.h"
#ifdef __cplusplus
@@ -89,17 +72,6 @@ esp_err_t bsp_lcd_flush_wait_done(TickType_t ticks_to_wait);
*/
esp_err_t bsp_lcd_set_cb(bool (*trans_done_cb)(void *), void *data);
/**
* @brief Init LCD with SPI interface
*
* @param p_io_handle LCD panel IO handle
* @param trans_done_cb callback function when a single flush transaction is finished
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t bsp_spi_lcd_init(esp_lcd_panel_io_handle_t *p_io_handle, bsp_lcd_trans_cb_t trans_done_cb);
/**
* @brief Deinit LCD with SPI interface
*
@@ -109,6 +81,17 @@ esp_err_t bsp_spi_lcd_init(esp_lcd_panel_io_handle_t *p_io_handle, bsp_lcd_trans
*/
esp_err_t bsp_spi_lcd_deinit(void);
/**
* @brief Set backlight
*
* @param en 0: OFF, other: ON
*
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t bsp_lcd_set_backlight(bool en);
#ifdef __cplusplus
}
#endif
+3 -18
View File
@@ -1,22 +1,7 @@
/**
* @file bsp_storage.h
* @brief
* @version 0.1
* @date 2021-07-06
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
-56
View File
@@ -1,56 +0,0 @@
/**
* @file bsp_tp.h
* @brief
* @version 0.1
* @date 2021-07-05
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "esp_err.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Init touch panel
*
* @return
* - ESP_OK: Success
* - ESP_ERR_NOT_SUPPORTED: Unsupported touch panel
* - Others: Fail
*/
esp_err_t bsp_tp_init(void);
/**
* @brief Read data from touch panel
*
* @param tp_num Touch point number
* @param x X coordinate
* @param y Y coordinate
* @param btn_val Button mask value
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t bsp_tp_read(uint8_t *tp_num, uint16_t *x, uint16_t *y, uint8_t *btn_val);
#ifdef __cplusplus
}
#endif
+75
View File
@@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include "esp_log.h"
#include "bsp_board.h"
#include "bsp_i2c.h"
#include "bsp_i2s.h"
#include "bsp_codec.h"
#include "esp32_s3_box.h"
#include "esp32_s3_box_lite.h"
static const char *TAG = "bsp boards";
static const boards_info_t g_boards_info[] = {
{BOARD_S3_BOX, "S3_BOX", bsp_board_s3_box_init, bsp_board_s3_box_power_ctrl, bsp_board_s3_box_get_res_desc},
{BOARD_S3_BOX_LITE, "S3_BOX_LITE", bsp_board_s3_box_lite_init, bsp_board_s3_box_lite_power_ctrl, bsp_board_s3_box_lite_get_res_desc},
};
static boards_info_t *g_board = NULL;
static esp_err_t bsp_board_detect()
{
esp_err_t ret = ESP_OK;
for (size_t i = 0; i < sizeof(g_boards_info) / sizeof(boards_info_t); i++) {
const board_res_desc_t *brd = g_boards_info[i].board_get_res_desc();
/*!< Initialize I2C bus, used for TP ,audio codec and IMU */
bsp_i2c_init(I2C_NUM_0, 400 * 1000, brd->GPIO_I2C_SCL, brd->GPIO_I2C_SDA);
uint32_t codecs = 0;
bsp_codec_detect(&codecs);
if ((CODEC_DEV_ES7210 | CODEC_DEV_ES8311) == codecs) {
g_board = (boards_info_t *)&g_boards_info[BOARD_S3_BOX];
} else if ((CODEC_DEV_ES7243 | CODEC_DEV_ES8156) == codecs) {
g_board = (boards_info_t *)&g_boards_info[BOARD_S3_BOX_LITE];
} else {
ESP_LOGE(TAG, "Can't Detect a correct board");
bsp_i2c_deinit();
ret = ESP_ERR_NOT_FOUND;
}
if (g_board) {
ESP_LOGI(TAG, "Detected board: [%s]", g_board->name);
break;
}
}
return ret;
}
const boards_info_t *bsp_board_get_info(void)
{
return g_board;
}
const board_res_desc_t *bsp_board_get_description(void)
{
return g_board->board_get_res_desc();
}
esp_err_t bsp_board_init(void)
{
if (ESP_OK == bsp_board_detect()) {
return g_board->board_init();
}
return ESP_FAIL;
}
esp_err_t bsp_board_power_ctrl(power_module_t module, bool on)
{
if (g_board) {
return g_board->board_power_ctrl(module, on);
}
return ESP_FAIL;
}
+201
View File
@@ -0,0 +1,201 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
#include "bsp_board.h"
#include "bsp_i2s.h"
#include "bsp_codec.h"
#include "button.h"
#include "bsp_btn.h"
static const board_button_t g_btns[] = {
{BOARD_BTN_ID_BOOT, 0, GPIO_NUM_0, 0},
};
static const pmod_pins_t g_pmod[2] = {
{
{9, 43, 44, 14},
{10, 11, 13, 12},
},
{
{38, 39, 40, 41},
{42, 21, 19, 20},
},
};
static const board_res_desc_t g_board_s3_box_res = {
.FUNC_LCD_EN = (1),
.LCD_BUS_WIDTH = (1),
.LCD_IFACE_SPI = (1),
.LCD_DISP_IC_ST = (1),
.LCD_WIDTH = (320),
.LCD_HEIGHT = (240),
.LCD_FREQ = (40 * 1000 * 1000),
.LCD_CMD_BITS = 8,
.LCD_PARAM_BITS = 8,
.LCD_HOST = (SPI2_HOST),
.LCD_SWAP_XY = (0),
.LCD_MIRROR_X = (true),
.LCD_MIRROR_Y = (true),
.LCD_COLOR_INV = (false),
.LCD_COLOR_SPACE = ESP_LCD_COLOR_SPACE_BGR,
.GPIO_LCD_BL = (GPIO_NUM_45),
.GPIO_LCD_BL_ON = (1),
.GPIO_LCD_CS = (GPIO_NUM_5),
.GPIO_LCD_RST = (GPIO_NUM_48),
.GPIO_LCD_DC = (GPIO_NUM_4),
.GPIO_LCD_CLK = (GPIO_NUM_7),
.GPIO_LCD_DIN = (GPIO_NUM_6),
.GPIO_LCD_DOUT = (GPIO_NUM_NC),
.BSP_INDEV_IS_TP = (1),
.TOUCH_PANEL_SWAP_XY = (0),
.TOUCH_PANEL_INVERSE_X = (1),
.TOUCH_PANEL_INVERSE_Y = (0),
.TOUCH_PANEL_I2C_ADDR = 0,
.TOUCH_WITH_HOME_BUTTON = 1,
.BSP_BUTTON_EN = (1),
.BUTTON_ADC_CHAN = ADC1_CHANNEL_0,
.BUTTON_TAB = g_btns,
.BUTTON_TAB_LEN = sizeof(g_btns) / sizeof(g_btns[0]),
.FUNC_I2C_EN = (1),
.GPIO_I2C_SCL = (GPIO_NUM_18),
.GPIO_I2C_SDA = (GPIO_NUM_8),
.FUNC_SDMMC_EN = (1),
.SDMMC_BUS_WIDTH = (4),
.GPIO_SDMMC_CLK = (GPIO_NUM_13),
.GPIO_SDMMC_CMD = (GPIO_NUM_11),
.GPIO_SDMMC_D0 = (GPIO_NUM_14),
.GPIO_SDMMC_D1 = (GPIO_NUM_12),
.GPIO_SDMMC_D2 = (GPIO_NUM_10),
.GPIO_SDMMC_D3 = (GPIO_NUM_9),
.GPIO_SDMMC_DET = (GPIO_NUM_NC),
.FUNC_SDSPI_EN = (0),
.SDSPI_HOST = (SPI2_HOST),
.GPIO_SDSPI_CS = (GPIO_NUM_NC),
.GPIO_SDSPI_SCLK = (GPIO_NUM_NC),
.GPIO_SDSPI_MISO = (GPIO_NUM_NC),
.GPIO_SDSPI_MOSI = (GPIO_NUM_NC),
.FUNC_SPI_EN = (0),
.GPIO_SPI_CS = (GPIO_NUM_NC),
.GPIO_SPI_MISO = (GPIO_NUM_NC),
.GPIO_SPI_MOSI = (GPIO_NUM_NC),
.GPIO_SPI_SCLK = (GPIO_NUM_NC),
.FUNC_RMT_EN = (0),
.GPIO_RMT_IR = (GPIO_NUM_NC),
.GPIO_RMT_LED = (GPIO_NUM_39),
.FUNC_I2S_EN = (1),
.GPIO_I2S_LRCK = (GPIO_NUM_47),
.GPIO_I2S_MCLK = (GPIO_NUM_2),
.GPIO_I2S_SCLK = (GPIO_NUM_17),
.GPIO_I2S_SDIN = (GPIO_NUM_16),
.GPIO_I2S_DOUT = (GPIO_NUM_15),
.CODEC_I2C_ADDR = 0,
.AUDIO_ADC_I2C_ADDR = 0,
.IMU_I2C_ADDR = 0,
.FUNC_PWR_CTRL = (1),
.GPIO_PWR_CTRL = (GPIO_NUM_46),
.GPIO_PWR_ON_LEVEL = (1),
.GPIO_MUTE_NUM = GPIO_NUM_1,
.GPIO_MUTE_LEVEL = 1,
.PMOD1 = &g_pmod[0],
.PMOD2 = &g_pmod[1],
};
static const char *TAG = "board";
__attribute__((weak)) void mute_btn_handler(void *arg)
{
if (g_board_s3_box_res.GPIO_MUTE_LEVEL == gpio_get_level(g_board_s3_box_res.GPIO_MUTE_NUM)) {
ets_printf(DRAM_STR("Mute Off"));
} else {
ets_printf(DRAM_STR("Mute On"));
}
}
esp_err_t bsp_board_s3_box_init(void)
{
/*!< Mute_Button on ESP32-S3-Box */
gpio_config_t io_conf_key;
io_conf_key.intr_type = GPIO_INTR_ANYEDGE;
io_conf_key.mode = GPIO_MODE_INPUT;
io_conf_key.pin_bit_mask = 1ULL << g_board_s3_box_res.GPIO_MUTE_NUM;
io_conf_key.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf_key.pull_up_en = GPIO_PULLUP_ENABLE;
ESP_ERROR_CHECK(gpio_config(&io_conf_key));
/* Install GPIO ISR service to enable GPIO ISR callback */
gpio_install_isr_service(0);
ESP_ERROR_CHECK(gpio_isr_handler_add(g_board_s3_box_res.GPIO_MUTE_NUM, mute_btn_handler, NULL));
bsp_btn_init_default();
/**
* @brief Initialize I2S and audio codec
*
* @note Actually the sampling rate can be reconfigured.
* `MP3GetLastFrameInfo` can fill the `MP3FrameInfo`, which includes `samprate`.
* So theoretically, the sampling rate can be dynamically changed according to the MP3 frame information.
*/
ESP_ERROR_CHECK(bsp_i2s_init(I2S_NUM_0, 16000));
ESP_ERROR_CHECK(bsp_codec_init(AUDIO_HAL_16K_SAMPLES));
return ESP_OK;
}
esp_err_t bsp_board_s3_box_power_ctrl(power_module_t module, bool on)
{
/* Config power control IO */
static esp_err_t bsp_io_config_state = ESP_FAIL;
if (ESP_OK != bsp_io_config_state) {
gpio_config_t io_conf;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = 1ULL << g_board_s3_box_res.GPIO_PWR_CTRL;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
bsp_io_config_state = gpio_config(&io_conf);
}
/* Checko IO config result */
if (ESP_OK != bsp_io_config_state) {
ESP_LOGE(TAG, "Failed initialize power control IO");
return bsp_io_config_state;
}
/* Control independent power domain */
switch (module) {
case POWER_MODULE_LCD:
gpio_set_level(g_board_s3_box_res.GPIO_LCD_BL, on ? (g_board_s3_box_res.GPIO_LCD_BL_ON) : (!g_board_s3_box_res.GPIO_LCD_BL_ON));
break;
case POWER_MODULE_AUDIO:
case POWER_MODULE_ALL:
gpio_set_level(g_board_s3_box_res.GPIO_PWR_CTRL, on ? (g_board_s3_box_res.GPIO_PWR_ON_LEVEL) : (!g_board_s3_box_res.GPIO_PWR_ON_LEVEL));
break;
default:
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
const board_res_desc_t *bsp_board_s3_box_get_res_desc(void)
{
return &g_board_s3_box_res;
}
+45
View File
@@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#include "bsp_board.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Special config for dev board
*
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t bsp_board_s3_box_init(void);
/**
* @brief Control power of dev board
*
* @param module Refer to `power_module_t`
* @param on Turn on or off specified power module. On if true
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t bsp_board_s3_box_power_ctrl(power_module_t module, bool on);
/**
* @brief Get board description
*
* @return pointer of board_res_desc_t
*/
const board_res_desc_t *bsp_board_s3_box_get_res_desc(void);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,183 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include "esp_log.h"
#include "bsp_board.h"
#include "bsp_i2s.h"
#include "bsp_codec.h"
#include "button.h"
#include "bsp_btn.h"
static const board_button_t g_btns[] = {
{BOARD_BTN_ID_BOOT, 0, GPIO_NUM_0, 0},
{BOARD_BTN_ID_PREV, 2971UL, GPIO_NUM_NC, 0},
{BOARD_BTN_ID_ENTER, 2427UL, GPIO_NUM_NC, 0},
{BOARD_BTN_ID_NEXT, 957UL, GPIO_NUM_NC, 0},
};
static const pmod_pins_t g_pmod[2] = {
{
{9, 43, 44, 14},
{10, 11, 13, 12},
},
{
{38, 39, 40, 41},
{42, 21, 19, 20},
},
};
static const board_res_desc_t g_board_s3_box_lite_res = {
.FUNC_LCD_EN = (1),
.LCD_BUS_WIDTH = (1),
.LCD_IFACE_SPI = (1),
.LCD_DISP_IC_ST = (1),
.LCD_WIDTH = (320),
.LCD_HEIGHT = (240),
.LCD_FREQ = (80 * 1000 * 1000),
.LCD_CMD_BITS = 8,
.LCD_PARAM_BITS = 8,
.LCD_HOST = (SPI2_HOST),
.LCD_SWAP_XY = (true),
.LCD_MIRROR_X = (false),
.LCD_MIRROR_Y = (true),
.LCD_COLOR_INV = (true),
.LCD_COLOR_SPACE = ESP_LCD_COLOR_SPACE_RGB,
.GPIO_LCD_BL = (GPIO_NUM_45),
.GPIO_LCD_BL_ON = (0),
.GPIO_LCD_CS = (GPIO_NUM_5),
.GPIO_LCD_RST = (GPIO_NUM_48),
.GPIO_LCD_DC = (GPIO_NUM_4),
.GPIO_LCD_CLK = (GPIO_NUM_7),
.GPIO_LCD_DIN = (GPIO_NUM_6),
.GPIO_LCD_DOUT = (GPIO_NUM_NC),
.BSP_INDEV_IS_TP = (0),
.TOUCH_PANEL_SWAP_XY = (0),
.TOUCH_PANEL_INVERSE_X = (1),
.TOUCH_PANEL_INVERSE_Y = (0),
.TOUCH_PANEL_I2C_ADDR = 0,
.TOUCH_WITH_HOME_BUTTON = 0,
.BSP_BUTTON_EN = (1),
.BUTTON_ADC_CHAN = ADC1_CHANNEL_0,
.BUTTON_TAB = g_btns,
.BUTTON_TAB_LEN = sizeof(g_btns) / sizeof(g_btns[0]),
.FUNC_I2C_EN = (1),
.GPIO_I2C_SCL = (GPIO_NUM_18),
.GPIO_I2C_SDA = (GPIO_NUM_8),
.FUNC_SDMMC_EN = (1),
.SDMMC_BUS_WIDTH = (4),
.GPIO_SDMMC_CLK = (GPIO_NUM_13),
.GPIO_SDMMC_CMD = (GPIO_NUM_11),
.GPIO_SDMMC_D0 = (GPIO_NUM_14),
.GPIO_SDMMC_D1 = (GPIO_NUM_12),
.GPIO_SDMMC_D2 = (GPIO_NUM_10),
.GPIO_SDMMC_D3 = (GPIO_NUM_9),
.GPIO_SDMMC_DET = (GPIO_NUM_NC),
.FUNC_SDSPI_EN = (0),
.SDSPI_HOST = (SPI2_HOST),
.GPIO_SDSPI_CS = (GPIO_NUM_NC),
.GPIO_SDSPI_SCLK = (GPIO_NUM_NC),
.GPIO_SDSPI_MISO = (GPIO_NUM_NC),
.GPIO_SDSPI_MOSI = (GPIO_NUM_NC),
.FUNC_SPI_EN = (0),
.GPIO_SPI_CS = (GPIO_NUM_NC),
.GPIO_SPI_MISO = (GPIO_NUM_NC),
.GPIO_SPI_MOSI = (GPIO_NUM_NC),
.GPIO_SPI_SCLK = (GPIO_NUM_NC),
.FUNC_RMT_EN = (0),
.GPIO_RMT_IR = (GPIO_NUM_NC),
.GPIO_RMT_LED = (GPIO_NUM_39),
.FUNC_I2S_EN = (1),
.GPIO_I2S_LRCK = (GPIO_NUM_47),
.GPIO_I2S_MCLK = (GPIO_NUM_2),
.GPIO_I2S_SCLK = (GPIO_NUM_17),
.GPIO_I2S_SDIN = (GPIO_NUM_16),
.GPIO_I2S_DOUT = (GPIO_NUM_15),
.CODEC_I2C_ADDR = 0,
.AUDIO_ADC_I2C_ADDR = 0,
.IMU_I2C_ADDR = 0,
.FUNC_PWR_CTRL = (1),
.GPIO_PWR_CTRL = (GPIO_NUM_46),
.GPIO_PWR_ON_LEVEL = (1),
.GPIO_MUTE_NUM = GPIO_NUM_1,
.GPIO_MUTE_LEVEL = 1,
.PMOD1 = &g_pmod[0],
.PMOD2 = &g_pmod[1],
};
static const char *TAG = "board";
esp_err_t bsp_board_s3_box_lite_init(void)
{
bsp_btn_init_default();
/**
* @brief Initialize I2S and audio codec
*
* @note Actually the sampling rate can be reconfigured.
* `MP3GetLastFrameInfo` can fill the `MP3FrameInfo`, which includes `samprate`.
* So theoretically, the sampling rate can be dynamically changed according to the MP3 frame information.
*/
ESP_ERROR_CHECK(bsp_i2s_init(I2S_NUM_0, 16000));
ESP_ERROR_CHECK(bsp_codec_init(AUDIO_HAL_16K_SAMPLES));
return ESP_OK;
}
esp_err_t bsp_board_s3_box_lite_power_ctrl(power_module_t module, bool on)
{
/* Config power control IO */
static esp_err_t bsp_io_config_state = ESP_FAIL;
if (ESP_OK != bsp_io_config_state) {
gpio_config_t io_conf;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = 1ULL << g_board_s3_box_lite_res.GPIO_PWR_CTRL;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
bsp_io_config_state = gpio_config(&io_conf);
}
/* Checko IO config result */
if (ESP_OK != bsp_io_config_state) {
ESP_LOGE(TAG, "Failed initialize power control IO");
return bsp_io_config_state;
}
/* Control independent power domain */
switch (module) {
case POWER_MODULE_LCD:
gpio_set_level(g_board_s3_box_lite_res.GPIO_LCD_BL, on ? (g_board_s3_box_lite_res.GPIO_LCD_BL_ON) : (!g_board_s3_box_lite_res.GPIO_LCD_BL_ON));
break;
case POWER_MODULE_AUDIO:
case POWER_MODULE_ALL:
gpio_set_level(g_board_s3_box_lite_res.GPIO_PWR_CTRL, on ? (g_board_s3_box_lite_res.GPIO_PWR_ON_LEVEL) : (!g_board_s3_box_lite_res.GPIO_PWR_ON_LEVEL));
break;
default:
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
const board_res_desc_t *bsp_board_s3_box_lite_get_res_desc(void)
{
return &g_board_s3_box_lite_res;
}
@@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#include "bsp_board.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Special config for dev board
*
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t bsp_board_s3_box_lite_init(void);
/**
* @brief Control power of dev board
*
* @param module Refer to `power_module_t`
* @param on Turn on or off specified power module. On if true
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t bsp_board_s3_box_lite_power_ctrl(power_module_t module, bool on);
/**
* @brief Get board description
*
* @return pointer of board_res_desc_t
*/
const board_res_desc_t *bsp_board_s3_box_lite_get_res_desc(void);
#ifdef __cplusplus
}
#endif
-143
View File
@@ -1,143 +0,0 @@
/**
* @file bsp_codec.c
* @brief
* @version 0.1
* @date 2021-07-20
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "bsp_codec.h"
#include "bsp_i2c.h"
#include "es7210.h"
#include "es8311.h"
#include "esp_log.h"
static const char *TAG = "codec";
typedef enum {
CODEC_TYPE_ES7210 = 0,
CODEC_TYPE_ES8311,
CODEC_TYPE_ES8388,
CODEC_TYPE_MAX,
CODEC_TYPE_NONE = -1,
} codec_type_t;
typedef struct {
uint8_t dev_addr;
char *dev_name;
codec_type_t dev_type;
} codec_dev_t;
static codec_dev_t codec_dev_list[] = {
{ 0x40, "ES7210", CODEC_TYPE_ES7210 },
{ 0x18, "ES8311", CODEC_TYPE_ES8311 },
{ 0x20, "ES8388", CODEC_TYPE_ES8388 },
};
static esp_err_t bsp_codec_prob(int *codec_type)
{
for (size_t i = 0; i < sizeof(codec_dev_list) / sizeof(codec_dev_list[0]); i++) {
if (ESP_OK == bsp_i2c_probe_addr(codec_dev_list[i].dev_addr)) {
*codec_type |= 1 << i;
ESP_LOGI(TAG, "Detected codec at 0x%02X. Name : %s",
codec_dev_list[i].dev_addr, codec_dev_list[i].dev_name);
}
}
if (0 == *codec_type) {
*codec_type = CODEC_TYPE_NONE;
ESP_LOGW(TAG, "Codec not detected");
return ESP_ERR_NOT_FOUND;
}
return ESP_OK;
}
esp_err_t bsp_codec_adc_init(audio_hal_iface_samples_t sample_rate)
{
esp_err_t ret_val = ESP_OK;
audio_hal_codec_config_t cfg = {
.codec_mode = AUDIO_HAL_CODEC_MODE_ENCODE,
.adc_input = AUDIO_HAL_ADC_INPUT_ALL,
.i2s_iface = {
.bits = AUDIO_HAL_BIT_LENGTH_16BITS,
.fmt = AUDIO_HAL_I2S_NORMAL,
.mode = AUDIO_HAL_MODE_SLAVE,
.samples = sample_rate,
},
};
ret_val |= es7210_adc_init(&cfg);
ret_val |= es7210_adc_config_i2s(cfg.codec_mode, &cfg.i2s_iface);
ret_val |= es7210_adc_set_gain(ES7210_INPUT_MIC1 | ES7210_INPUT_MIC2, GAIN_37_5DB);
ret_val |= es7210_adc_set_gain(ES7210_INPUT_MIC3 | ES7210_INPUT_MIC4, GAIN_0DB);
ret_val |= es7210_adc_ctrl_state(cfg.codec_mode, AUDIO_HAL_CTRL_START);
if (ESP_OK != ret_val) {
ESP_LOGE(TAG, "Failed initialize codec");
}
return ret_val;
}
esp_err_t bsp_codec_dac_init(audio_hal_iface_samples_t sample_rate)
{
esp_err_t ret_val = ESP_OK;
audio_hal_codec_config_t cfg = {
.codec_mode = AUDIO_HAL_CODEC_MODE_DECODE,
.dac_output = AUDIO_HAL_DAC_OUTPUT_LINE1,
.i2s_iface = {
.bits = AUDIO_HAL_BIT_LENGTH_16BITS,
.fmt = AUDIO_HAL_I2S_NORMAL,
.mode = AUDIO_HAL_MODE_SLAVE,
.samples = sample_rate,
},
};
ret_val |= es8311_codec_init(&cfg);
ret_val |= es8311_set_bits_per_sample(cfg.i2s_iface.bits);
ret_val |= es8311_config_fmt(cfg.i2s_iface.fmt);
ret_val |= es8311_codec_set_voice_volume(60);
ret_val |= es8311_codec_ctrl_state(cfg.codec_mode, AUDIO_HAL_CTRL_START);
if (ESP_OK != ret_val) {
ESP_LOGE(TAG, "Failed initialize codec");
}
return ret_val;
}
esp_err_t bsp_codec_init(audio_hal_iface_samples_t sample_rate)
{
esp_err_t ret_val = ESP_OK;
static int codec_type = 0;
ret_val |= bsp_codec_prob(&codec_type);
if(CODEC_TYPE_NONE == codec_type) {
return ESP_ERR_NOT_FOUND;
}
if (((1 << CODEC_TYPE_ES8311) + (1 << CODEC_TYPE_ES7210)) == codec_type) {
ret_val |= bsp_codec_adc_init(sample_rate);
ret_val |= bsp_codec_dac_init(sample_rate);
return ret_val;
}
ESP_LOGW(TAG, "Currently not support");
return ESP_ERR_NOT_SUPPORTED;
}
@@ -0,0 +1,91 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2021 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "bsp_i2c.h"
#include "es7243e.h"
#include "i2c_bus.h"
#include "esp_log.h"
#define ES7243_ADDR 0x10
static char *TAG = "DRV7243E";
static i2c_bus_handle_t i2c_handle;
static esp_err_t es7243e_write_reg(uint8_t reg_add, uint8_t data)
{
return i2c_bus_write_byte(i2c_handle, reg_add, data);
}
esp_err_t es7243e_adc_init(audio_hal_codec_config_t *codec_cfg)
{
esp_err_t ret = ESP_OK;
bsp_i2c_add_device(&i2c_handle, ES7243_ADDR);
ret |= es7243e_write_reg(0x01, 0x3A);
ret |= es7243e_write_reg(0x00, 0x80);
ret |= es7243e_write_reg(0xF9, 0x00);
ret |= es7243e_write_reg(0x04, 0x02);
ret |= es7243e_write_reg(0x04, 0x01);
ret |= es7243e_write_reg(0xF9, 0x01);
ret |= es7243e_write_reg(0x00, 0x1E);
ret |= es7243e_write_reg(0x01, 0x00);
ret |= es7243e_write_reg(0x02, 0x00);
ret |= es7243e_write_reg(0x03, 0x20);
ret |= es7243e_write_reg(0x04, 0x01);
ret |= es7243e_write_reg(0x0D, 0x00);
ret |= es7243e_write_reg(0x05, 0x00);
ret |= es7243e_write_reg(0x06, 0x03); // SCLK=MCLK/4
ret |= es7243e_write_reg(0x07, 0x00); // LRCK=MCLK/256
ret |= es7243e_write_reg(0x08, 0xFF); // LRCK=MCLK/256
ret |= es7243e_write_reg(0x09, 0xCA);
ret |= es7243e_write_reg(0x0A, 0x85);
ret |= es7243e_write_reg(0x0B, 0x00);
ret |= es7243e_write_reg(0x0E, 0xBF);
ret |= es7243e_write_reg(0x0F, 0x80);
ret |= es7243e_write_reg(0x14, 0x0C);
ret |= es7243e_write_reg(0x15, 0x0C);
ret |= es7243e_write_reg(0x17, 0x02);
ret |= es7243e_write_reg(0x18, 0x26);
ret |= es7243e_write_reg(0x19, 0x77);
ret |= es7243e_write_reg(0x1A, 0xF4);
ret |= es7243e_write_reg(0x1B, 0x66);
ret |= es7243e_write_reg(0x1C, 0x44);
ret |= es7243e_write_reg(0x1E, 0x00);
ret |= es7243e_write_reg(0x1F, 0x0C);
ret |= es7243e_write_reg(0x20, 0x1E); //PGA gain +30dB
ret |= es7243e_write_reg(0x21, 0x1E); //PGA gain +30dB
ret |= es7243e_write_reg(0x00, 0x80); //Slave Mode
ret |= es7243e_write_reg(0x01, 0x3A);
ret |= es7243e_write_reg(0x16, 0x3F);
ret |= es7243e_write_reg(0x16, 0x00);
if (ret) {
ESP_LOGE(TAG, "Es7243e initialize failed!");
return ESP_FAIL;
}
return ret;
}
@@ -0,0 +1,77 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2021 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef _ES7243E_H_
#define _ES7243E_H_
#include "esp_err.h"
#include "audio_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize ES7243E adc chip
*
* @param codec_cfg configuration of ES7243E
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es7243e_adc_init(audio_hal_codec_config_t *codec_cfg);
/**
* @brief Set gain of given mask
*
* @param[in] mic_mask Mask of MIC channel
*
* @param[in] gain: gain
*
* gain : value
* GAIN_0DB : 1
* GAIN_3DB : 2
* GAIN_6DB : 3
* ·
* ·
* ·
* GAIN_30DB : 10
* GAIN_33DB : 11
* GAIN_34_5DB : 12
* GAIN_36DB : 13
* GAIN_37_5DB : 14
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
// esp_err_t es7243_adc_set_gain(es7243_input_mics_t mic_mask, es7243_gain_value_t gain);
#ifdef __cplusplus
}
#endif
#endif
+136
View File
@@ -0,0 +1,136 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2021 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "bsp_i2c.h"
#include "string.h"
#include "esp_log.h"
#include "i2c_bus.h"
#include "es8156.h"
static const char *TAG = "es8156";
#define ES8156_ADDR (0x08)
static i2c_bus_handle_t i2c_handle;
static esp_err_t es8156_write_reg(uint8_t reg_addr, uint8_t data)
{
return i2c_bus_write_byte(i2c_handle, reg_addr, data);
}
static uint8_t es8156_read_reg(uint8_t reg_addr)
{
uint8_t data;
i2c_bus_read_byte(i2c_handle, reg_addr, &data);
return data;
}
esp_err_t es8156_codec_init(audio_hal_codec_config_t *cfg)
{
esp_err_t ret_val = ESP_OK;
ret_val |= bsp_i2c_add_device(&i2c_handle, ES8156_ADDR);
uint8_t misc_ctrl_reg_val = 0x00;
uint8_t dac_iface_reg_val = 0x00;
if (AUDIO_HAL_MODE_MASTER == cfg->i2s_iface.mode) {
misc_ctrl_reg_val |= 0b00100000;
} else {
misc_ctrl_reg_val |= 0b00000000;
}
switch (cfg->i2s_iface.bits) {
case AUDIO_HAL_BIT_LENGTH_16BITS:
dac_iface_reg_val |= 0b00110000;
break;
case AUDIO_HAL_BIT_LENGTH_24BITS:
dac_iface_reg_val |= 0b00000000;
break;
case AUDIO_HAL_BIT_LENGTH_32BITS:
dac_iface_reg_val |= 0b01000000;
break;
default: /* Use 32 bit as default */
dac_iface_reg_val |= 0b01000000;
break;
}
ret_val |= es8156_write_reg(0x09, misc_ctrl_reg_val); // MCLK from pad, Slave mode, power down DLL, enable pin pull up
ret_val |= es8156_write_reg(0x11, dac_iface_reg_val); // DAC Interface Config
ret_val |= es8156_write_reg(0x14, ES8156_VOL_MIN_3dB); // Set default volume to 0dB
return ret_val;
}
esp_err_t es8156_codec_deinit(void)
{
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t es8156_codec_set_voice_mute(bool enable)
{
int regv = es8156_read_reg(ES8156_DAC_MUTE_REG13);
if (enable) {
regv = regv | BIT(1) | BIT(2);
} else {
regv = regv & (~(BIT(1) | BIT(2))) ;
}
es8156_write_reg(ES8156_DAC_MUTE_REG13, regv);
return ESP_OK;
}
esp_err_t es8156_codec_set_voice_volume(uint8_t volume)
{
if (volume > 100) {
volume = 100;
}
uint8_t d = 0xBF - 60 + 6 * volume / 10;
if (0 == volume) {
d = 0;
}
return es8156_write_reg(ES8156_VOLUME_CONTROL_REG14, d);
}
esp_err_t es8156_codec_get_voice_volume(uint8_t *volume)
{
*volume = es8156_read_reg(ES8156_VOLUME_CONTROL_REG14);
return ESP_OK;
}
esp_err_t es8156_config_fmt(es_i2s_fmt_t fmt)
{
ESP_LOGW(TAG, "Not support config format for es8156 now");
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t es8156_set_channel(uint8_t is_right)
{
uint8_t reg = es8156_read_reg(ES8156_DAC_SDP_REG11);
if (is_right) {
reg |= 0b00000100;
} else {
reg &= 0b11111011;
}
return es8156_write_reg(ES8156_DAC_SDP_REG11, reg);
}
+174
View File
@@ -0,0 +1,174 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2021 <ESPRESSIF SYSTEMS (SHANGHAI) CO., LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef _ES8156_H
#define _ES8156_H
#include "audio_hal.h"
#include "esp_types.h"
#include "esxxx_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/* ES8156 register space */
/*
* RESET Control
*/
#define ES8156_RESET_REG00 0x00
/*
* Clock Managerment
*/
#define ES8156_MAINCLOCK_CTL_REG01 0x01
#define ES8156_SCLK_MODE_REG02 0x02
#define ES8156_LRCLK_DIV_H_REG03 0x03
#define ES8156_LRCLK_DIV_L_REG04 0x04
#define ES8156_SCLK_DIV_REG05 0x05
#define ES8156_NFS_CONFIG_REG06 0x06
#define ES8156_MISC_CONTROL1_REG07 0x07
#define ES8156_CLOCK_ON_OFF_REG08 0x08
#define ES8156_MISC_CONTROL2_REG09 0x09
#define ES8156_TIME_CONTROL1_REG0A 0x0a
#define ES8156_TIME_CONTROL2_REG0B 0x0b
/*
* System Control
*/
#define ES8156_CHIP_STATUS_REG0C 0x0c
#define ES8156_P2S_CONTROL_REG0D 0x0d
#define ES8156_DAC_OSR_COUNTER_REG10 0x10
/*
* SDP Control
*/
#define ES8156_DAC_SDP_REG11 0x11
#define ES8156_AUTOMUTE_SET_REG12 0x12
#define ES8156_DAC_MUTE_REG13 0x13
#define ES8156_VOLUME_CONTROL_REG14 0x14
/*
* ALC Control
*/
#define ES8156_ALC_CONFIG1_REG15 0x15
#define ES8156_ALC_CONFIG2_REG16 0x16
#define ES8156_ALC_CONFIG3_REG17 0x17
#define ES8156_MISC_CONTROL3_REG18 0x18
#define ES8156_EQ_CONTROL1_REG19 0x19
#define ES8156_EQ_CONTROL2_REG1A 0x1a
/*
* Analog System Control
*/
#define ES8156_ANALOG_SYS1_REG20 0x20
#define ES8156_ANALOG_SYS2_REG21 0x21
#define ES8156_ANALOG_SYS3_REG22 0x22
#define ES8156_ANALOG_SYS4_REG23 0x23
#define ES8156_ANALOG_LP_REG24 0x24
#define ES8156_ANALOG_SYS5_REG25 0x25
/*
* Chip Information
*/
#define ES8156_I2C_PAGESEL_REGFC 0xFC
#define ES8156_CHIPID1_REGFD 0xFD
#define ES8156_CHIPID0_REGFE 0xFE
#define ES8156_CHIP_VERSION_REGFF 0xFF
typedef enum {
ES8156_VOL_MIN = 0x00, /*!< -95.5dB */
ES8156_VOL_MIN_10dB = 0xAB, /*!< -10dB */
ES8156_VOL_MIN_9dB = 0xAD, /*!< -9dB */
ES8156_VOL_MIN_6dB = 0xB3, /*!< -6dB */
ES8156_VOL_MIN_3dB = 0xB9, /*!< -3dB */
ES8156_VOL_0dB = 0xBF, /*!< 0dB */
ES8156_VOL_3dB = 0xC5, /*!< +3dB */
ES8156_VOL_10dB = 0xD3, /*!< +10dB */
ES8156_VOL_MAX = 0xFF, /*!< +32dB */
} es8156_volume_t;
/*
* @brief Initialize ES8156 codec chip
*
* @param codec_cfg configuration of ES8156
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8156_codec_init(audio_hal_codec_config_t *codec_cfg);
/**
* @brief Deinitialize ES8156 codec chip
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8156_codec_deinit(void);
esp_err_t es8156_config_fmt(es_i2s_fmt_t fmt);
/**
* @brief Configure ES8156 DAC mute or not. Basically you can use this function to mute the output or unmute
*
* @param enable enable(1) or disable(0)
*
* @return
* - ESP_FAIL Parameter error
* - ESP_OK Success
*/
esp_err_t es8156_codec_set_voice_mute(bool enable);
/**
* @brief Set voice volume
*
* @param volume: voice volume (0~100)
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8156_codec_set_voice_volume(uint8_t volume);
/**
* @brief Get voice volume
*
* @param[out] *volume: voice volume (0~255)
*
* @return
* - ESP_OK
* - ESP_FAIL
*/
esp_err_t es8156_codec_get_voice_volume(uint8_t *volume);
/**
* @brief
*
* @param is_right
* @return esp_err_t
*/
esp_err_t es8156_set_channel(uint8_t is_right);
#ifdef __cplusplus
}
#endif
#endif
@@ -670,3 +670,14 @@ void es8311_read_all()
ets_printf("REG:%02x, %02x\n", reg, i);
}
}
esp_err_t es8311_set_channel(int is_right)
{
uint8_t reg_val = es8311_read_reg(ES8311_SDPIN_REG09);
if (is_right) {
reg_val |= 0b10000000;
} else {
reg_val &= 0b01111111;
}
return es8311_write_reg(ES8311_SDPIN_REG09, reg_val);
}
@@ -195,7 +195,6 @@ esp_err_t es8311_codec_get_voice_volume(int *volume);
/**
* @brief Configure ES8311 I2S format
*
* @param mod: set ADC or DAC or both
* @param cfg: ES8388 I2S format
*
* @return
@@ -207,7 +206,6 @@ esp_err_t es8311_config_fmt(es_i2s_fmt_t fmt);
/**
* @brief Configure ES8311 data sample bits
*
* @param mode: set ADC or DAC or both
* @param bit_per_sample: bit number of per sample
*
* @return
@@ -266,6 +264,14 @@ esp_err_t es8311_set_mic_gain(es8311_mic_gain_t gain_db);
*/
void es8311_read_all();
/**
* @brief
*
* @param is_right
* @return esp_err_t
*/
esp_err_t es8311_set_channel(int is_right);
#ifdef __cplusplus
}
#endif
-174
View File
@@ -1,174 +0,0 @@
/**
* @file bsp_lcd.c
* @brief
* @version 0.1
* @date 2021-06-25
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "bsp_lcd.h"
#include "bsp_board.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_compiler.h"
#include "esp_log.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "soc/soc_memory_layout.h"
static const char *TAG = "bsp_lcd";
static esp_lcd_panel_io_handle_t io_handle = NULL;
static esp_lcd_panel_handle_t panel_handle = NULL;
static void *p_user_data = NULL;
static bool (*p_on_trans_done_cb)(void *) = NULL;
static SemaphoreHandle_t bsp_lcd_flush_done_sem = NULL;
static bool lcd_trans_done_cb(esp_lcd_panel_io_handle_t, esp_lcd_panel_io_event_data_t *, void *);
esp_err_t bsp_lcd_init(void)
{
bsp_spi_lcd_init(&io_handle, lcd_trans_done_cb);
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = GPIO_LCD_RST,
.color_space = ESP_LCD_COLOR_SPACE_BGR,
.bits_per_pixel = 16,
};
#if LCD_DISP_IC_NT
ESP_ERROR_CHECK(esp_lcd_new_panel_nt35510(io_handle, &panel_config, &panel_handle));
#elif LCD_DISP_IC_ST
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
#else
#error "Invalid LCD type"
#endif
/**
* @brief Configure LCD rotation and mirror
*
*/
esp_err_t ret_val = ESP_OK;
ret_val |= esp_lcd_panel_reset(panel_handle);
ret_val |= esp_lcd_panel_init(panel_handle);
ret_val |= esp_lcd_panel_invert_color(panel_handle, LCD_COLOR_INV);
ret_val |= esp_lcd_panel_set_gap(panel_handle, 0, 0);
ret_val |= esp_lcd_panel_swap_xy(panel_handle, LCD_SWAP_XY);
ret_val |= esp_lcd_panel_mirror(panel_handle, LCD_MIRROR_X, LCD_MIRROR_Y);
/**
* @brief Configure LCD backlight IO.
*
*/
if (GPIO_NUM_NC != GPIO_LCD_BL) {
gpio_config_t bk_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
/*!< Prevent left shift negtive value warning */
.pin_bit_mask = GPIO_LCD_BL > 0 ? 1ULL << GPIO_LCD_BL : 0ULL,
};
gpio_config(&bk_gpio_config);
gpio_set_level(GPIO_LCD_BL, GPIO_LCD_BL_ON);
}
/**
* @brief Create mutex to receive LCD flush event.
*
*/
if (NULL != bsp_lcd_flush_done_sem) {
ESP_LOGE(TAG, "LCD already initialized");
return ESP_ERR_INVALID_STATE;
}
bsp_lcd_flush_done_sem = xSemaphoreCreateBinary();
if (NULL == bsp_lcd_flush_done_sem) {
return ESP_ERR_NO_MEM;
}
/* If any function is checking LCD trans status before transmition */
xSemaphoreGive(bsp_lcd_flush_done_sem);
return ESP_OK;
}
esp_err_t bsp_lcd_deinit(void)
{
esp_err_t ret_val = ESP_OK;
ret_val |= esp_lcd_panel_del(panel_handle);
ret_val |= esp_lcd_panel_io_del(io_handle);
ret_val |= bsp_spi_lcd_deinit();
return ret_val;
}
esp_err_t bsp_lcd_flush(int x1, int y1, int x2, int y2, const void *p_data, TickType_t ticks_to_wait)
{
/* Wait for previous tansmition done */
if (pdPASS != xSemaphoreTake(bsp_lcd_flush_done_sem, ticks_to_wait)) {
return ESP_ERR_TIMEOUT;
}
return esp_lcd_panel_draw_bitmap(panel_handle, x1, y1, x2, y2, p_data);
}
esp_err_t bsp_lcd_flush_wait_done(TickType_t ticks_to_wait)
{
if (pdPASS != xSemaphoreTake(bsp_lcd_flush_done_sem, ticks_to_wait)) {
return ESP_ERR_TIMEOUT;
}
xSemaphoreGive(bsp_lcd_flush_done_sem);
return ESP_OK;
}
esp_err_t bsp_lcd_set_cb(bool (*trans_done_cb)(void *), void *data)
{
if (esp_ptr_executable(trans_done_cb)) {
p_on_trans_done_cb = trans_done_cb;
p_user_data = data;
} else {
ESP_LOGE(TAG, "Invalid function pointer");
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
static bool lcd_trans_done_cb(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *user_data, void *event_data)
{
(void) panel_io;
(void) user_data;
(void) event_data;
/* Used for `bsp_lcd_flush_wait` */
if (likely(NULL != bsp_lcd_flush_done_sem)) {
xSemaphoreGive(bsp_lcd_flush_done_sem);
}
/* Call user registered function */
if (NULL != p_on_trans_done_cb) {
return p_on_trans_done_cb(p_user_data);
}
return false;
}
-114
View File
@@ -1,114 +0,0 @@
/**
* @file bsp_lcd_spi.c
* @brief
* @version 0.1
* @date 2021-08-25
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "bsp_lcd.h"
#include "bsp_board.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_compiler.h"
#include "esp_log.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "soc/soc_memory_layout.h"
static const char *TAG = "bsp_lcd_spi";
esp_err_t bsp_spi_lcd_init(esp_lcd_panel_io_handle_t *p_io_handle, bsp_lcd_trans_cb_t trans_done_cb)
{
esp_err_t ret_val = ESP_OK;
if (NULL == p_io_handle) {
ESP_LOGE(TAG, "Invalid LCD IO handle");
return ESP_ERR_INVALID_ARG;
}
spi_bus_config_t buscfg = {
.sclk_io_num = GPIO_LCD_CLK,
#if (LCD_BUS_WIDTH == 1)
.mosi_io_num = GPIO_LCD_DIN,
.miso_io_num = GPIO_NUM_NC,
.quadwp_io_num = GPIO_NUM_NC,
.quadhd_io_num = GPIO_NUM_NC,
#elif (LCD_BUS_WIDTH == 8)
.data0_io_num = GPIO_LCD_D00,
.data1_io_num = GPIO_LCD_D01,
.data2_io_num = GPIO_LCD_D02,
.data3_io_num = GPIO_LCD_D03,
.data4_io_num = GPIO_LCD_D04,
.data5_io_num = GPIO_LCD_D05,
.data6_io_num = GPIO_LCD_D06,
.data7_io_num = GPIO_LCD_D07,
.flags = SPICOMMON_BUSFLAG_OCTAL,
#endif
.max_transfer_sz = LCD_WIDTH * LCD_HEIGHT * sizeof(uint16_t)
};
ret_val |= spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO);
esp_lcd_panel_io_spi_config_t io_config = {
.dc_gpio_num = GPIO_LCD_DC,
.cs_gpio_num = GPIO_LCD_CS,
.pclk_hz = LCD_FREQ,
.spi_mode = 0,
.trans_queue_depth = 10,
.lcd_cmd_bits =
#if LCD_DISP_IC_NT
16,
#elif LCD_DISP_IC_ST
8,
#else
8, /* TBD */
#endif
.lcd_param_bits =
#if LCD_DISP_IC_NT
16,
#elif LCD_DISP_IC_ST
8,
#else
8, /* TBD */
#endif
.on_color_trans_done = trans_done_cb,
.user_ctx = NULL,
};
#if (LCD_BUS_WIDTH == 8)
io_config.flags.octal_mode = 1;
io_config.spi_mode = 3;
#endif
ret_val |= esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t) LCD_HOST, &io_config, p_io_handle);
return ESP_OK;
}
esp_err_t bsp_spi_lcd_deinit(void)
{
esp_err_t ret_val = ESP_OK;
ret_val |= spi_bus_free(LCD_HOST);
return ret_val;
}
+107
View File
@@ -0,0 +1,107 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "esp_check.h"
#include "bsp_board.h"
#include "driver/adc.h"
#include "esp_err.h"
#include "button.h"
static const char *TAG = "bsp btn";
static button_handle_t *g_btn_handle = NULL;
static esp_err_t adc_button_init(button_handle_t *handle, size_t btn_id, adc1_channel_t adc_chanel, uint32_t voltage_err, const uint32_t voltage)
{
esp_err_t ret_val = ESP_OK;
button_config_t btn_cfg = {
.type = BUTTON_TYPE_ADC,
.adc_button_config = {
.adc_channel = adc_chanel,
},
};
btn_cfg.adc_button_config.button_index = btn_id;
btn_cfg.adc_button_config.min = voltage - voltage_err;
btn_cfg.adc_button_config.max = voltage + voltage_err;
*handle = button_create(&btn_cfg);
return ret_val;
}
static esp_err_t gpio_btn_init(button_handle_t *handle, const gpio_num_t gpio, const bool active_level)
{
esp_err_t ret_val = ESP_OK;
button_config_t btn_cfg = {
.type = BUTTON_TYPE_GPIO,
.gpio_button_config = {
.active_level = 0,
.gpio_num = 0,
},
};
btn_cfg.gpio_button_config.gpio_num = gpio;
btn_cfg.gpio_button_config.active_level = active_level;
*handle = button_create(&btn_cfg);
return ret_val;
}
esp_err_t bsp_btn_init_default(void)
{
ESP_RETURN_ON_FALSE(NULL == g_btn_handle, ESP_ERR_INVALID_STATE, TAG, "button already initialized ");
esp_err_t ret = ESP_OK;
const board_res_desc_t *brd = bsp_board_get_description();
g_btn_handle = calloc(sizeof(button_handle_t), brd->BUTTON_TAB_LEN);
ESP_RETURN_ON_FALSE(NULL != g_btn_handle, ESP_ERR_NO_MEM, TAG, "memory is insufficient for button");
for (size_t i = 0; i < brd->BUTTON_TAB_LEN; i++) {
const board_button_t *btn = &brd->BUTTON_TAB[i];
if (GPIO_NUM_NC != btn->io_num) {
ret = gpio_btn_init(&g_btn_handle[btn->id], btn->io_num, btn->active_level);
} else {
ret = adc_button_init(&g_btn_handle[btn->id], btn->id, brd->BUTTON_ADC_CHAN, 150, btn->vol);
}
}
return ret;
}
esp_err_t bsp_btn_register_callback(board_btn_id_t btn_id, button_event_t event, button_cb_t callback, void *user_data)
{
ESP_RETURN_ON_FALSE(NULL != g_btn_handle, ESP_ERR_INVALID_STATE, TAG, "button not initialized");
const board_res_desc_t *brd = bsp_board_get_description();
ESP_RETURN_ON_FALSE(btn_id < brd->BUTTON_TAB_LEN, ESP_ERR_INVALID_ARG, TAG, "button id incorrect");
if (NULL == callback) {
return button_unregister_cb(g_btn_handle[btn_id], event);
}
button_dev_t *btn = (button_dev_t *) g_btn_handle[btn_id];
btn->cb_user_data = user_data;
return button_register_cb(g_btn_handle[btn_id], event, callback);
}
esp_err_t bsp_btn_rm_all_callback(board_btn_id_t btn_id)
{
ESP_RETURN_ON_FALSE(NULL != g_btn_handle, ESP_ERR_INVALID_STATE, TAG, "button not initialized");
const board_res_desc_t *brd = bsp_board_get_description();
ESP_RETURN_ON_FALSE(btn_id < brd->BUTTON_TAB_LEN, ESP_ERR_INVALID_ARG, TAG, "button id incorrect");
for (size_t event = 0; event < BUTTON_EVENT_MAX; event++) {
button_unregister_cb(g_btn_handle[btn_id], event);
}
return ESP_OK;
}
bool bsp_btn_get_state(board_btn_id_t btn_id)
{
const board_res_desc_t *brd = bsp_board_get_description();
ESP_RETURN_ON_FALSE(btn_id < brd->BUTTON_TAB_LEN, 0, TAG, "button id incorrect");
button_dev_t *btn = (button_dev_t *) g_btn_handle[btn_id];
return btn->event == BUTTON_PRESS_DOWN ? 1 : 0;
}
+195
View File
@@ -0,0 +1,195 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "bsp_codec.h"
#include "bsp_i2c.h"
#include "esp_err.h"
#include "es8156.h"
#include "es7210.h"
#include "es7243e.h"
#include "es8311.h"
#include "esp_log.h"
static const char *TAG = "codec";
typedef struct {
codec_dev_t dev;
uint8_t dev_addr;
char *dev_name;
esp_err_t (*init)(void);
} codec_desc_t;
static uint32_t s_codec_detect_flag = 0;
/**
* @brief Default init function declaration for aduio CODEC
*/
static esp_err_t es7210_init_default(void);
static esp_err_t es7243_init_default(void);
static esp_err_t es8156_init_default(void);
static esp_err_t es8311_init_default(void);
static codec_desc_t codec_dev_list[] = {
{CODEC_DEV_ES7210, 0x40, "ES7210", es7210_init_default },
{CODEC_DEV_ES7243, 0x08, "ES7243", es7243_init_default },
{CODEC_DEV_ES8156, 0x10, "ES8156", es8156_init_default },
{CODEC_DEV_ES8311, 0x18, "ES8311", es8311_init_default },
// { 0x20, "ES8388", es8388_init_default }, /* Currently not supported */
};
static esp_err_t es7210_init_default(void)
{
esp_err_t ret_val = ESP_OK;
audio_hal_codec_config_t cfg = {
.codec_mode = AUDIO_HAL_CODEC_MODE_ENCODE,
.adc_input = AUDIO_HAL_ADC_INPUT_ALL,
.i2s_iface = {
.bits = AUDIO_HAL_BIT_LENGTH_16BITS,
.fmt = AUDIO_HAL_I2S_NORMAL,
.mode = AUDIO_HAL_MODE_SLAVE,
.samples = AUDIO_HAL_16K_SAMPLES,
},
};
ret_val |= es7210_adc_init(&cfg);
ret_val |= es7210_adc_config_i2s(cfg.codec_mode, &cfg.i2s_iface);
ret_val |= es7210_adc_set_gain(ES7210_INPUT_MIC1 | ES7210_INPUT_MIC2, GAIN_37_5DB);
ret_val |= es7210_adc_set_gain(ES7210_INPUT_MIC3 | ES7210_INPUT_MIC4, GAIN_0DB);
ret_val |= es7210_adc_ctrl_state(cfg.codec_mode, AUDIO_HAL_CTRL_START);
if (ESP_OK != ret_val) {
ESP_LOGE(TAG, "Failed initialize codec");
}
return ret_val;
}
static esp_err_t es7243_init_default(void)
{
audio_hal_codec_config_t cfg = {
.i2s_iface = {
.bits = AUDIO_HAL_BIT_LENGTH_16BITS,
.mode = AUDIO_HAL_MODE_SLAVE,
}
};
return es7243e_adc_init(&cfg);
}
static esp_err_t es8156_init_default(void)
{
esp_err_t ret_val = ESP_OK;
audio_hal_codec_config_t cfg = {
.i2s_iface = {
.bits = AUDIO_HAL_BIT_LENGTH_16BITS,
.mode = AUDIO_HAL_MODE_SLAVE,
}
};
ret_val |= es8156_codec_init(&cfg);
ret_val |= es8156_codec_set_voice_volume(75);
if (ESP_OK != ret_val) {
ESP_LOGE(TAG, "Failed initialize codec");
}
return ret_val;
}
static esp_err_t es8311_init_default(void)
{
esp_err_t ret_val = ESP_OK;
audio_hal_codec_config_t cfg = {
.codec_mode = AUDIO_HAL_CODEC_MODE_DECODE,
.dac_output = AUDIO_HAL_DAC_OUTPUT_LINE1,
.i2s_iface = {
.bits = AUDIO_HAL_BIT_LENGTH_16BITS,
.fmt = AUDIO_HAL_I2S_NORMAL,
.mode = AUDIO_HAL_MODE_SLAVE,
.samples = AUDIO_HAL_16K_SAMPLES,
},
};
ret_val |= es8311_codec_init(&cfg);
ret_val |= es8311_set_bits_per_sample(cfg.i2s_iface.bits);
ret_val |= es8311_config_fmt(cfg.i2s_iface.fmt);
ret_val |= es8311_codec_set_voice_volume(75);
ret_val |= es8311_codec_ctrl_state(cfg.codec_mode, AUDIO_HAL_CTRL_START);
if (ESP_OK != ret_val) {
ESP_LOGE(TAG, "Failed initialize codec");
}
return ret_val;
}
bool bsp_codec_has_dev(codec_dev_t dev)
{
if (s_codec_detect_flag & dev) {
return true;
} return false;
}
esp_err_t bsp_codec_detect(uint32_t *devices)
{
for (size_t i = 0 ; i < sizeof(codec_dev_list) / sizeof(codec_dev_list[0]); i++) {
if (ESP_OK == bsp_i2c_probe_addr(codec_dev_list[i].dev_addr)) {
*devices |= codec_dev_list[i].dev;
ESP_LOGI(TAG, "Detected codec at 0x%02X. Name : %s",
codec_dev_list[i].dev_addr, codec_dev_list[i].dev_name);
}
}
return 0 == *devices ? ESP_ERR_NOT_FOUND : ESP_OK;
}
esp_err_t bsp_codec_init(audio_hal_iface_samples_t sample_rate)
{
esp_err_t ret_val = ESP_OK;
ret_val = bsp_codec_detect(&s_codec_detect_flag);
if (ESP_OK == ret_val) {
for (size_t i = 0; i < sizeof(codec_dev_list) / sizeof(codec_dev_list[0]); i++) {
if (codec_dev_list[i].dev & s_codec_detect_flag) {
ret_val |= codec_dev_list[i].init();
ESP_LOGI(TAG, "init %s", codec_dev_list[i].dev_name);
}
}
}
return ret_val;
}
esp_err_t bsp_codec_set_voice_volume(uint8_t volume)
{
if (bsp_codec_has_dev(CODEC_DEV_ES8311)) {
// reduce volume for S3-BOX board
float v = volume;
v *= 0.6f;
v = -0.01f * (v * v) + 2.0f * v;
return es8311_codec_set_voice_volume((int)v);
} else if (bsp_codec_has_dev(CODEC_DEV_ES8156)) {
return es8156_codec_set_voice_volume(volume);
}
return ESP_ERR_NOT_FOUND;
}
esp_err_t bsp_codec_set_fmt(audio_hal_iface_format_t fmt)
{
if (bsp_codec_has_dev(CODEC_DEV_ES8311)) {
return es8311_config_fmt(fmt);
} else if (bsp_codec_has_dev(CODEC_DEV_ES8156)) {
return es8156_config_fmt(fmt);
}
return ESP_ERR_NOT_FOUND;
}
esp_err_t bsp_codec_set_voice_gain(uint8_t channel_mask, uint8_t volume)
{
if (bsp_codec_has_dev(CODEC_DEV_ES7210)) {
return es7210_adc_set_gain(channel_mask, volume);
}
return ESP_ERR_NOT_FOUND;
}
@@ -1,22 +1,7 @@
/**
* @file bsp_i2c.c
* @brief
* @version 0.1
* @date 2021-06-25
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_log.h"
@@ -24,12 +9,13 @@
#include "bsp_board.h"
#include "driver/i2c.h"
static const char *TAG = "bsp_i2c";
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
static const char *TAG= "bsp_i2c";
static i2c_bus_handle_t i2c_bus_handle = NULL;
esp_err_t bsp_i2c_init(i2c_port_t i2c_num, uint32_t clk_speed)
esp_err_t bsp_i2c_init(i2c_port_t i2c_num, uint32_t clk_speed, gpio_num_t scl_io, gpio_num_t sda_io)
{
/* Check if bus is already created */
if (NULL != i2c_bus_handle) {
@@ -39,8 +25,8 @@ esp_err_t bsp_i2c_init(i2c_port_t i2c_num, uint32_t clk_speed)
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.scl_io_num = GPIO_I2C_SCL,
.sda_io_num = GPIO_I2C_SDA,
.scl_io_num = scl_io,
.sda_io_num = sda_io,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = clk_speed,
@@ -56,6 +42,19 @@ esp_err_t bsp_i2c_init(i2c_port_t i2c_num, uint32_t clk_speed)
return ESP_OK;
}
esp_err_t bsp_i2c_deinit(void)
{
/* Check if bus is already created */
if (NULL == i2c_bus_handle) {
ESP_LOGE(TAG, "I2C bus already deinitialized.");
return ESP_FAIL;
}
i2c_bus_delete(&i2c_bus_handle);
return ESP_OK;
}
esp_err_t bsp_i2c_add_device(i2c_bus_device_handle_t *i2c_device_handle, uint8_t dev_addr)
{
if (NULL == i2c_bus_handle) {
@@ -1,22 +1,7 @@
/**
* @file bsp_i2s.c
* @brief
* @version 0.1
* @date 2021-07-23
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#include "bsp_board.h"
@@ -51,19 +36,21 @@
esp_err_t bsp_i2s_init(i2s_port_t i2s_num, uint32_t sample_rate)
{
esp_err_t ret_val = ESP_OK;
const board_res_desc_t *brd = bsp_board_get_description();
i2s_config_t i2s_config = I2S_CONFIG_DEFAULT();
i2s_pin_config_t pin_config = {
.bck_io_num = GPIO_I2S_SCLK,
.ws_io_num = GPIO_I2S_LRCK,
.data_out_num = GPIO_I2S_DOUT,
.data_in_num = GPIO_I2S_SDIN,
.mck_io_num = GPIO_I2S_MCLK,
.bck_io_num = brd->GPIO_I2S_SCLK,
.ws_io_num = brd->GPIO_I2S_LRCK,
.data_out_num = brd->GPIO_I2S_DOUT,
.data_in_num = brd->GPIO_I2S_SDIN,
.mck_io_num = brd->GPIO_I2S_MCLK,
};
ret_val |= i2s_driver_install(i2s_num, &i2s_config, 0, NULL);
ret_val |= i2s_set_pin(i2s_num, &pin_config);
ret_val |= i2s_zero_dma_buffer(i2s_num);
return ret_val;
}
+228
View File
@@ -0,0 +1,228 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "bsp_lcd.h"
#include "bsp_board.h"
#include "esp_compiler.h"
#include "esp_log.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "soc/soc_memory_layout.h"
static const char *TAG = "bsp_lcd";
static esp_lcd_panel_io_handle_t io_handle = NULL;
static esp_lcd_panel_handle_t panel_handle = NULL;
static void *p_user_data = NULL;
static bool (*p_on_trans_done_cb)(void *) = NULL;
static SemaphoreHandle_t bsp_lcd_flush_done_sem = NULL;
static esp_err_t bsp_spi_lcd_init(esp_lcd_panel_io_handle_t *p_io_handle, bsp_lcd_trans_cb_t trans_done_cb)
{
esp_err_t ret_val = ESP_OK;
const board_res_desc_t *brd = bsp_board_get_description();
if (NULL == p_io_handle) {
ESP_LOGE(TAG, "Invalid LCD IO handle");
return ESP_ERR_INVALID_ARG;
}
if (brd->LCD_BUS_WIDTH == 8) {
spi_bus_config_t buscfg = {
.sclk_io_num = brd->GPIO_LCD_CLK,
.data0_io_num = brd->GPIO_LCD_D00,
.data1_io_num = brd->GPIO_LCD_D01,
.data2_io_num = brd->GPIO_LCD_D02,
.data3_io_num = brd->GPIO_LCD_D03,
.data4_io_num = brd->GPIO_LCD_D04,
.data5_io_num = brd->GPIO_LCD_D05,
.data6_io_num = brd->GPIO_LCD_D06,
.data7_io_num = brd->GPIO_LCD_D07,
.flags = SPICOMMON_BUSFLAG_OCTAL,
.max_transfer_sz = brd->LCD_WIDTH * brd->LCD_HEIGHT * sizeof(uint16_t)
};
ret_val |= spi_bus_initialize(brd->LCD_HOST, &buscfg, SPI_DMA_CH_AUTO);
} else if (brd->LCD_BUS_WIDTH == 1) {
spi_bus_config_t buscfg = {
.sclk_io_num = brd->GPIO_LCD_CLK,
.mosi_io_num = brd->GPIO_LCD_DIN,
.miso_io_num = GPIO_NUM_NC,
.quadwp_io_num = GPIO_NUM_NC,
.quadhd_io_num = GPIO_NUM_NC,
.max_transfer_sz = brd->LCD_WIDTH * brd->LCD_HEIGHT * sizeof(uint16_t)
};
ret_val |= spi_bus_initialize(brd->LCD_HOST, &buscfg, SPI_DMA_CH_AUTO);
}
esp_lcd_panel_io_spi_config_t io_config = {
.dc_gpio_num = brd->GPIO_LCD_DC,
.cs_gpio_num = brd->GPIO_LCD_CS,
.pclk_hz = brd->LCD_FREQ,
.spi_mode = 0,
.trans_queue_depth = 10,
.lcd_cmd_bits = brd->LCD_CMD_BITS,
.lcd_param_bits = brd->LCD_PARAM_BITS,
.on_color_trans_done = trans_done_cb,
.user_ctx = NULL,
};
if (brd->LCD_BUS_WIDTH == 8) {
io_config.flags.octal_mode = 1;
io_config.spi_mode = 3;
}
ret_val |= esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t) brd->LCD_HOST, &io_config, p_io_handle);
return ESP_OK;
}
esp_err_t bsp_spi_lcd_deinit(void)
{
esp_err_t ret_val = ESP_OK;
const board_res_desc_t *brd = bsp_board_get_description();
ret_val |= spi_bus_free(brd->LCD_HOST);
return ret_val;
}
static bool lcd_trans_done_cb(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *user_data, void *event_data)
{
(void) panel_io;
(void) user_data;
(void) event_data;
/* Used for `bsp_lcd_flush_wait` */
if (likely(NULL != bsp_lcd_flush_done_sem)) {
xSemaphoreGive(bsp_lcd_flush_done_sem);
}
/* Call user registered function */
if (NULL != p_on_trans_done_cb) {
return p_on_trans_done_cb(p_user_data);
}
return false;
}
esp_err_t bsp_lcd_init(void)
{
const board_res_desc_t *brd = bsp_board_get_description();
bsp_spi_lcd_init(&io_handle, lcd_trans_done_cb);
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = brd->GPIO_LCD_RST,
.color_space = brd->LCD_COLOR_SPACE,
.bits_per_pixel = 16,
};
if (!brd->LCD_DISP_IC_ST) {
ESP_ERROR_CHECK(esp_lcd_new_panel_nt35510(io_handle, &panel_config, &panel_handle));
} else {
ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));
}
/**
* @brief Configure LCD rotation and mirror
*
*/
esp_err_t ret_val = ESP_OK;
ret_val |= esp_lcd_panel_reset(panel_handle);
ret_val |= esp_lcd_panel_init(panel_handle);
ret_val |= esp_lcd_panel_invert_color(panel_handle, brd->LCD_COLOR_INV);
ret_val |= esp_lcd_panel_set_gap(panel_handle, 0, 0);
ret_val |= esp_lcd_panel_swap_xy(panel_handle, brd->LCD_SWAP_XY);
ret_val |= esp_lcd_panel_mirror(panel_handle, brd->LCD_MIRROR_X, brd->LCD_MIRROR_Y);
/**
* @brief Configure LCD backlight IO.
*
*/
if (GPIO_NUM_NC != brd->GPIO_LCD_BL) {
gpio_config_t bk_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
/*!< Prevent left shift negtive value warning */
.pin_bit_mask = brd->GPIO_LCD_BL > 0 ? 1ULL << brd->GPIO_LCD_BL : 0ULL,
};
gpio_config(&bk_gpio_config);
gpio_set_level(brd->GPIO_LCD_BL, !brd->GPIO_LCD_BL_ON);
}
/**
* @brief Create mutex to receive LCD flush event.
*
*/
if (NULL != bsp_lcd_flush_done_sem) {
ESP_LOGE(TAG, "LCD already initialized");
return ESP_ERR_INVALID_STATE;
}
bsp_lcd_flush_done_sem = xSemaphoreCreateBinary();
if (NULL == bsp_lcd_flush_done_sem) {
return ESP_ERR_NO_MEM;
}
/* If any function is checking LCD trans status before transmition */
xSemaphoreGive(bsp_lcd_flush_done_sem);
return ESP_OK;
}
esp_err_t bsp_lcd_deinit(void)
{
esp_err_t ret_val = ESP_OK;
ret_val |= esp_lcd_panel_del(panel_handle);
ret_val |= esp_lcd_panel_io_del(io_handle);
ret_val |= bsp_spi_lcd_deinit();
return ret_val;
}
esp_err_t bsp_lcd_flush(int x1, int y1, int x2, int y2, const void *p_data, TickType_t ticks_to_wait)
{
/* Wait for previous tansmition done */
if (pdPASS != xSemaphoreTake(bsp_lcd_flush_done_sem, ticks_to_wait)) {
return ESP_ERR_TIMEOUT;
}
return esp_lcd_panel_draw_bitmap(panel_handle, x1, y1, x2, y2, p_data);
}
esp_err_t bsp_lcd_flush_wait_done(TickType_t ticks_to_wait)
{
if (pdPASS != xSemaphoreTake(bsp_lcd_flush_done_sem, ticks_to_wait)) {
return ESP_ERR_TIMEOUT;
}
xSemaphoreGive(bsp_lcd_flush_done_sem);
return ESP_OK;
}
esp_err_t bsp_lcd_set_cb(bool (*trans_done_cb)(void *), void *data)
{
if (esp_ptr_executable(trans_done_cb)) {
p_on_trans_done_cb = trans_done_cb;
p_user_data = data;
} else {
ESP_LOGE(TAG, "Invalid function pointer");
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
esp_err_t bsp_lcd_set_backlight(bool en)
{
const board_res_desc_t *brd = bsp_board_get_description();
return gpio_set_level(brd->GPIO_LCD_BL, en ? brd->GPIO_LCD_BL_ON : !brd->GPIO_LCD_BL_ON);
}
+81 -107
View File
@@ -1,25 +1,11 @@
/**
* @file sdmmc_private.c
* @brief
* @version 0.1
* @date 2021-11-04
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "bsp_board.h"
#include "esp_err.h"
@@ -27,9 +13,9 @@
#include "esp_vfs_fat.h"
#include "sdmmc_cmd.h"
#if ((SOC_SDMMC_HOST_SUPPORTED) && (FUNC_SDMMC_EN))
#if (SOC_SDMMC_HOST_SUPPORTED)
#include "driver/sdmmc_host.h"
#endif /* ((SOC_SDMMC_HOST_SUPPORTED) && (FUNC_SDMMC_EN)) */
#endif
#define DEFAULT_FD_NUM 2
#define DEFAULT_MOUNT_POINT "/sdcard"
@@ -42,123 +28,111 @@ esp_err_t bsp_sdcard_init(char *mount_point, size_t max_files)
if (NULL != card) {
return ESP_ERR_INVALID_STATE;
}
const board_res_desc_t *brd = bsp_board_get_description();
/* Check if SD crad is supported */
if (!FUNC_SDMMC_EN && !FUNC_SDSPI_EN) {
ESP_LOGE(TAG, "SDMMC and SDSPI not supported on this board!");
return ESP_ERR_NOT_SUPPORTED;
}
if (!brd->FUNC_SDMMC_EN && !brd->FUNC_SDSPI_EN) {
ESP_LOGE(TAG, "SDMMC and SDSPI not supported on this board!");
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t ret_val = ESP_OK;
/**
* @brief Options for mounting the filesystem.
* If format_if_mount_failed is set to true, SD card will be partitioned and
* formatted in case when mounting fails.
*
*/
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
/**
* @brief Options for mounting the filesystem.
* If format_if_mount_failed is set to true, SD card will be partitioned and
* formatted in case when mounting fails.
*
*/
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false,
.max_files = max_files,
.allocation_unit_size = 16 * 1024
};
/**
* @brief Use settings defined above to initialize SD card and mount FAT filesystem.
* Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions.
* Please check its source code and implement error recovery when developing
* production applications.
*
*/
sdmmc_host_t host =
#if FUNC_SDMMC_EN
SDMMC_HOST_DEFAULT();
#else
SDSPI_HOST_DEFAULT();
spi_bus_config_t bus_cfg = {
.mosi_io_num = GPIO_SDSPI_MOSI,
.miso_io_num = GPIO_SDSPI_MISO,
.sclk_io_num = GPIO_SDSPI_SCLK,
.quadwp_io_num = GPIO_NUM_NC,
.quadhd_io_num = GPIO_NUM_NC,
.max_transfer_sz = 4000,
};
ret_val = spi_bus_initialize(host.slot, &bus_cfg, SPI_DMA_CH_AUTO);
if (ret_val != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize bus.");
return ret_val;
/**
* @brief Use settings defined above to initialize SD card and mount FAT filesystem.
* Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions.
* Please check its source code and implement error recovery when developing
* production applications.
*
*/
sdmmc_host_t host = {0};
if (brd->FUNC_SDMMC_EN) {
sdmmc_host_t h = SDMMC_HOST_DEFAULT();
memcpy(&host, &h, sizeof(sdmmc_host_t));
} else {
sdmmc_host_t h = SDSPI_HOST_DEFAULT();
memcpy(&host, &h, sizeof(sdmmc_host_t));
spi_bus_config_t bus_cfg = {
.mosi_io_num = brd->GPIO_SDSPI_MOSI,
.miso_io_num = brd->GPIO_SDSPI_MISO,
.sclk_io_num = brd->GPIO_SDSPI_SCLK,
.quadwp_io_num = GPIO_NUM_NC,
.quadhd_io_num = GPIO_NUM_NC,
.max_transfer_sz = 4000,
};
ret_val = spi_bus_initialize(host.slot, &bus_cfg, SPI_DMA_CH_AUTO);
if (ret_val != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize bus.");
return ret_val;
}
}
#endif
/**
* @brief This initializes the slot without card detect (CD) and write protect (WP) signals.
* Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
*
*/
#if FUNC_SDMMC_EN
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
#else
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
#endif
/**
* @brief This initializes the slot without card detect (CD) and write protect (WP) signals.
* Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
*
*/
if (brd->FUNC_SDMMC_EN) {
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
/* Config SD data width. 0, 4 or 8. Currently for SD card, 8 bit is not supported. */
slot_config.width = brd->SDMMC_BUS_WIDTH;
#if FUNC_SDMMC_EN
/* Config SD data width. 0, 4 or 8. Currently for SD card, 8 bit is not supported. */
slot_config.width = SDMMC_BUS_WIDTH;
/**
* @brief On chips where the GPIOs used for SD card can be configured, set them in
* the slot_config structure.
*
*/
/**
* @brief On chips where the GPIOs used for SD card can be configured, set them in
* the slot_config structure.
*
*/
#if SOC_SDMMC_USE_GPIO_MATRIX
slot_config.clk = GPIO_SDMMC_CLK;
slot_config.cmd = GPIO_SDMMC_CMD;
slot_config.d0 = GPIO_SDMMC_D0;
slot_config.d1 = GPIO_SDMMC_D1;
slot_config.d2 = GPIO_SDMMC_D2;
slot_config.d3 = GPIO_SDMMC_D3;
slot_config.clk = brd->GPIO_SDMMC_CLK;
slot_config.cmd = brd->GPIO_SDMMC_CMD;
slot_config.d0 = brd->GPIO_SDMMC_D0;
slot_config.d1 = brd->GPIO_SDMMC_D1;
slot_config.d2 = brd->GPIO_SDMMC_D2;
slot_config.d3 = brd->GPIO_SDMMC_D3;
#endif
slot_config.cd = GPIO_SDMMC_DET;
slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
#else
slot_config.gpio_cs = GPIO_SDSPI_CS;
slot_config.host_id = host.slot;
#endif
/**
* @brief Enable internal pullups on enabled pins. The internal pullups
* are insufficient however, please make sure 10k external pullups are
* connected on the bus. This is for debug / example purpose only.
*/
slot_config.cd = brd->GPIO_SDMMC_DET;
slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
ret_val = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);
} else {
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
slot_config.gpio_cs = brd->GPIO_SDSPI_CS;
slot_config.host_id = host.slot;
ret_val = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card);
}
/* get FAT filesystem on SD card registered in VFS. */
ret_val =
#if FUNC_SDMMC_EN
esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);
#else
esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card);
#endif
/* Check for SDMMC mount result. */
/* Check for SDMMC mount result. */
if (ret_val != ESP_OK) {
if (ret_val == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem. "
"If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
"If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
} else {
ESP_LOGE(TAG, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret_val));
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret_val));
}
return ret_val;
}
/* Card has been initialized, print its properties. */
sdmmc_card_print_info(stdout, card);
return ret_val;
return ret_val;
}
esp_err_t bsp_sdcard_init_default(void)
{
return bsp_sdcard_init(DEFAULT_MOUNT_POINT, DEFAULT_FD_NUM);
return bsp_sdcard_init(DEFAULT_MOUNT_POINT, DEFAULT_FD_NUM);
}
esp_err_t bsp_sdcard_deinit(char *mount_point)
@@ -173,7 +147,7 @@ esp_err_t bsp_sdcard_deinit(char *mount_point)
/* Make SD/MMC card information structure pointer NULL */
card = NULL;
return ret_val;
return ret_val;
}
esp_err_t bsp_sdcard_deinit_default(void)
+3 -18
View File
@@ -1,22 +1,7 @@
/**
* @file spiffs_private.c
* @brief
* @version 0.1
* @date 2021-11-04
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
-13
View File
@@ -1,13 +0,0 @@
idf_component_register(
SRC_DIRS
"es7210"
"es8311"
"es8388"
INCLUDE_DIRS
"es7210"
"es8311"
"es8388"
"include"
REQUIRES
bsp
i2c_bus)
+3 -18
View File
@@ -1,22 +1,7 @@
/**
* @file i2c_bus.c
* @brief
* @version 0.1
* @date 2021-03-07
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
+3 -18
View File
@@ -1,22 +1,7 @@
/**
* @file i2c_bus.h
* @brief
* @version 0.1
* @date 2021-03-07
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _I2C_BUS_H_
@@ -1,3 +1,8 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _ICM_42670_H_
#define _ICM_42670_H_
+3 -18
View File
@@ -1,22 +1,7 @@
/**
* @file ft5x06.c
* @brief FT5x06 Capacitive Touch Panel Controller Driver
* @version 0.1
* @date 2021-01-13
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_err.h"
@@ -1,22 +1,7 @@
/**
* @file ft5x06.h
* @brief FT5x06 driver header file.
* @version 0.1
* @date 2021-03-07
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
@@ -1,22 +1,7 @@
/**
* @file tt21100.h
* @brief
* @version 0.1
* @date 2021-09-06
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
+3 -18
View File
@@ -1,22 +1,7 @@
/**
* @file tt21100.c
* @brief
* @version 0.1
* @date 2021-09-06
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#include "bsp_i2c.h"
+3
View File
@@ -0,0 +1,3 @@
idf_component_register(SRCS "button_adc.c" "button_gpio.c" "iot_button.c"
INCLUDE_DIRS include
PRIV_REQUIRES esp_adc_cal)
+46
View File
@@ -0,0 +1,46 @@
menu "IoT Button"
config BUTTON_PERIOD_TIME_MS
int "BUTTON PERIOD TIME (MS)"
range 2 20
default 5
help
"Button scan interval"
config BUTTON_DEBOUNCE_TICKS
int "BUTTON DEBOUNCE TICKS"
range 1 8
default 2
config BUTTON_SHORT_PRESS_TIME_MS
int "BUTTON SHORT PRESS TIME (MS)"
range 50 800
default 180
config BUTTON_LONG_PRESS_TIME_MS
int "BUTTON LONG PRESS TIME (MS)"
range 500 5000
default 1500
config ADC_BUTTON_MAX_CHANNEL
int "ADC BUTTON MAX CHANNEL"
range 1 5
default 3
help
"Maximum number of channels for ADC buttons"
config ADC_BUTTON_MAX_BUTTON_PER_CHANNEL
int "ADC BUTTON MAX BUTTON PER CHANNEL"
range 1 10
default 8
help
"Maximum number of buttons per channel"
config ADC_BUTTON_SAMPLE_TIMES
int "ADC BUTTON SAMPLE TIMES"
range 1 4
default 1
help
"Number of samples per scan"
endmenu
+204
View File
@@ -0,0 +1,204 @@
// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "esp_log.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"
#include "button_adc.h"
#include "esp_timer.h"
static const char *TAG = "adc button";
#define ADC_BTN_CHECK(a, str, ret_val) \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): %s", __FUNCTION__, __LINE__, str); \
return (ret_val); \
}
#define DEFAULT_VREF 1100
#define NO_OF_SAMPLES CONFIG_ADC_BUTTON_SAMPLE_TIMES //Multisampling
#define ADC_BUTTON_WIDTH ADC_WIDTH_BIT_DEFAULT
#define ADC_BUTTON_ATTEN ADC_ATTEN_DB_11
#define ADC_BUTTON_ADC_UNIT ADC_UNIT_1
#define ADC_BUTTON_MAX_CHANNEL CONFIG_ADC_BUTTON_MAX_CHANNEL
#define ADC_BUTTON_MAX_BUTTON CONFIG_ADC_BUTTON_MAX_BUTTON_PER_CHANNEL
typedef struct {
uint16_t min;
uint16_t max;
} button_data_t;
typedef struct {
adc1_channel_t channel;
uint8_t is_init;
button_data_t btns[ADC_BUTTON_MAX_BUTTON]; /* all button on the channel */
uint64_t last_time; /* the last time of adc sample */
} btn_adc_channel_t;
typedef struct {
bool is_configured;
esp_adc_cal_characteristics_t adc_chars;
btn_adc_channel_t ch[ADC_BUTTON_MAX_CHANNEL];
uint8_t ch_num;
} adc_button_t;
static adc_button_t g_button = {0};
static int find_unused_channel(void)
{
for (size_t i = 0; i < ADC_BUTTON_MAX_CHANNEL; i++) {
if (0 == g_button.ch[i].is_init) {
return i;
}
}
return -1;
}
static int find_channel(adc1_channel_t channel)
{
for (size_t i = 0; i < ADC_BUTTON_MAX_CHANNEL; i++) {
if (channel == g_button.ch[i].channel) {
return i;
}
}
return -1;
}
esp_err_t button_adc_init(const button_adc_config_t *config)
{
ADC_BTN_CHECK(NULL != config, "Pointer of config is invalid", ESP_ERR_INVALID_ARG);
ADC_BTN_CHECK(config->adc_channel < ADC1_CHANNEL_MAX, "channel out of range", ESP_ERR_NOT_SUPPORTED);
ADC_BTN_CHECK(config->button_index < ADC_BUTTON_MAX_BUTTON, "button_index out of range", ESP_ERR_NOT_SUPPORTED);
ADC_BTN_CHECK(config->max > 0, "key max voltage invalid", ESP_ERR_INVALID_ARG);
int ch_index = find_channel(config->adc_channel);
if (ch_index >= 0) { /**< the channel has been initialized */
ADC_BTN_CHECK(g_button.ch[ch_index].btns[config->button_index].max == 0, "The button_index has been used", ESP_ERR_INVALID_STATE);
} else { /**< this is a new channel */
int unused_ch_index = find_unused_channel();
ADC_BTN_CHECK(unused_ch_index >= 0, "exceed max channel number, can't create a new channel", ESP_ERR_INVALID_STATE);
ch_index = unused_ch_index;
}
/** initialize adc */
if (0 == g_button.is_configured) {
//Configure ADC
adc1_config_width(ADC_BUTTON_WIDTH);
//Characterize ADC
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(ADC_BUTTON_ADC_UNIT, ADC_BUTTON_ATTEN, ADC_BUTTON_WIDTH, DEFAULT_VREF, &g_button.adc_chars);
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
ESP_LOGI(TAG, "Characterized using Two Point Value");
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
ESP_LOGI(TAG, "Characterized using eFuse Vref");
} else {
ESP_LOGI(TAG, "Characterized using Default Vref");
}
g_button.is_configured = 1;
}
/** initialize adc channel */
if (0 == g_button.ch[ch_index].is_init) {
adc1_config_channel_atten(config->adc_channel, ADC_BUTTON_ATTEN);
g_button.ch[ch_index].channel = config->adc_channel;
g_button.ch[ch_index].is_init = 1;
g_button.ch[ch_index].last_time = 0;
}
g_button.ch[ch_index].btns[config->button_index].max = config->max;
g_button.ch[ch_index].btns[config->button_index].min = config->min;
g_button.ch_num++;
return ESP_OK;
}
esp_err_t button_adc_deinit(adc1_channel_t channel, int button_index)
{
ADC_BTN_CHECK(channel < ADC1_CHANNEL_MAX, "channel out of range", ESP_ERR_INVALID_ARG);
ADC_BTN_CHECK(button_index < ADC_BUTTON_MAX_BUTTON, "button_index out of range", ESP_ERR_INVALID_ARG);
int ch_index = find_channel(channel);
ADC_BTN_CHECK(ch_index >= 0, "can't find the channel", ESP_ERR_INVALID_ARG);
g_button.ch[ch_index].btns[button_index].max = 0;
g_button.ch[ch_index].btns[button_index].min = 0;
/** check button usage on the channel*/
uint8_t unused_button = 0;
for (size_t i = 0; i < ADC_BUTTON_MAX_BUTTON; i++) {
if (0 == g_button.ch[ch_index].btns[i].max) {
unused_button++;
}
}
if (unused_button == ADC_BUTTON_MAX_BUTTON && g_button.ch[ch_index].is_init) { /**< if all button is unused, deinit the channel */
/* TODO: to deinit the channel */
g_button.ch[ch_index].is_init = 0;
g_button.ch[ch_index].channel = ADC1_CHANNEL_MAX;
ESP_LOGD(TAG, "all button is unused on channel%d, deinit the channel", g_button.ch[ch_index].channel);
}
/** check channel usage on the adc*/
uint8_t unused_ch = 0;
for (size_t i = 0; i < ADC_BUTTON_MAX_CHANNEL; i++) {
if (0 == g_button.ch[i].is_init) {
unused_ch++;
}
}
if (unused_ch == ADC_BUTTON_MAX_CHANNEL && g_button.is_configured) { /**< if all channel is unused, deinit the adc */
/* TODO: to deinit the peripheral adc */
g_button.is_configured = false;
memset(&g_button, 0, sizeof(adc_button_t));
ESP_LOGD(TAG, "all channel is unused, , deinit adc");
}
return ESP_OK;
}
static uint32_t get_adc_volatge(adc1_channel_t channel)
{
uint32_t adc_reading = 0;
//Multisampling
for (int i = 0; i < NO_OF_SAMPLES; i++) {
adc_reading += adc1_get_raw(channel);
}
adc_reading /= NO_OF_SAMPLES;
//Convert adc_reading to voltage in mV
uint32_t voltage = adc_reading; //esp_adc_cal_raw_to_voltage(adc_reading, &g_button.adc_chars);
ESP_LOGV(TAG, "Raw: %d\tVoltage: %dmV", adc_reading, voltage);
return voltage;
}
uint8_t button_adc_get_key_level(void *button_index)
{
static uint16_t vol = 0;
uint32_t ch = ADC_BUTTON_SPLIT_CHANNEL(button_index);
uint32_t index = ADC_BUTTON_SPLIT_INDEX(button_index);
ADC_BTN_CHECK(ch < ADC1_CHANNEL_MAX, "channel out of range", 0);
ADC_BTN_CHECK(index < ADC_BUTTON_MAX_BUTTON, "button_index out of range", 0);
int ch_index = find_channel(ch);
ADC_BTN_CHECK(ch_index >= 0, "The button_index is not init", 0);
/** It starts only when the elapsed time is more than 1ms */
if ((esp_timer_get_time() - g_button.ch[ch_index].last_time) > 1000) {
vol = get_adc_volatge(ch);
g_button.ch[ch_index].last_time = esp_timer_get_time();
}
if (vol <= g_button.ch[ch_index].btns[index].max &&
vol > g_button.ch[ch_index].btns[index].min) {
return 1;
}
return 0;
}
+65
View File
@@ -0,0 +1,65 @@
// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "esp_log.h"
#include "driver/gpio.h"
#include "button_gpio.h"
static const char *TAG = "gpio button";
#define GPIO_BTN_CHECK(a, str, ret_val) \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): %s", __FUNCTION__, __LINE__, str); \
return (ret_val); \
}
esp_err_t button_gpio_init(const button_gpio_config_t *config)
{
GPIO_BTN_CHECK(NULL != config, "Pointer of config is invalid", ESP_ERR_INVALID_ARG);
gpio_config_t gpio_conf;
gpio_conf.intr_type = GPIO_INTR_DISABLE;
gpio_conf.mode = GPIO_MODE_INPUT;
gpio_conf.pin_bit_mask = (1ULL << config->gpio_num);
if (config->active_level) {
gpio_conf.pull_down_en = GPIO_PULLDOWN_ENABLE;
gpio_conf.pull_up_en = GPIO_PULLUP_DISABLE;
} else {
gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
}
gpio_config(&gpio_conf);
return ESP_OK;
}
esp_err_t button_gpio_deinit(int gpio_num)
{
/** both disable pullup and pulldown */
gpio_config_t gpio_conf = {
.intr_type = GPIO_INTR_DISABLE,
.mode = GPIO_MODE_INPUT,
.pin_bit_mask = (1ULL << gpio_num),
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.pull_up_en = GPIO_PULLUP_DISABLE,
};
gpio_config(&gpio_conf);
return ESP_OK;
}
uint8_t button_gpio_get_key_level(void *gpio_num)
{
return (uint8_t)gpio_get_level((uint32_t)gpio_num);
}
+8
View File
@@ -0,0 +1,8 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
COMPONENT_ADD_INCLUDEDIRS := ./include
COMPONENT_SRCDIRS := .
+147
View File
@@ -0,0 +1,147 @@
// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _BUTTON_H_
#define _BUTTON_H_
#include "button_adc.h"
#include "button_gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (* button_cb_t)(void *);
typedef void *button_handle_t;
/**
* @brief Button events
*
*/
typedef enum {
BUTTON_PRESS_DOWN = 0,
BUTTON_PRESS_UP,
BUTTON_PRESS_REPEAT,
BUTTON_SINGLE_CLICK,
BUTTON_DOUBLE_CLICK,
BUTTON_LONG_PRESS_START,
BUTTON_LONG_PRESS_HOLD,
BUTTON_EVENT_MAX,
BUTTON_NONE_PRESS,
} button_event_t;
/**
* @brief Supported button type
*
*/
typedef enum {
BUTTON_TYPE_GPIO,
BUTTON_TYPE_ADC,
} button_type_t;
/**
* @brief Button configuration
*
*/
typedef struct {
button_type_t type; /**< button type, The corresponding button configuration must be filled */
union {
button_gpio_config_t gpio_button_config; /**< gpio button configuration */
button_adc_config_t adc_button_config; /**< adc button configuration */
}; /**< button configuration */
} button_config_t;
typedef struct Button {
uint16_t ticks;
uint8_t repeat;
button_event_t event;
uint8_t state: 3;
uint8_t debounce_cnt: 3;
uint8_t active_level: 1;
uint8_t button_level: 1;
uint8_t (*hal_button_Level)(void *usr_data);
void *usr_data;
button_type_t type;
button_cb_t cb[BUTTON_EVENT_MAX];
void *cb_user_data;
struct Button *next;
} button_dev_t;
/**
* @brief Create a button
*
* @param config pointer of button configuration, must corresponding the button type
*
* @return A handle to the created button, or NULL in case of error.
*/
button_handle_t button_create(const button_config_t *config);
/**
* @brief Delete a button
*
* @param btn_handle A button handle to delete
*
* @return
* - ESP_OK Success
* - ESP_FAIL Failure
*/
esp_err_t button_delete(button_handle_t btn_handle);
/**
* @brief Register the button event callback function.
*
* @param btn_handle A button handle to register
* @param event Button event
* @param cb Callback function.
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG Arguments is invalid.
*/
esp_err_t button_register_cb(button_handle_t btn_handle, button_event_t event, button_cb_t cb);
/**
* @brief Unregister the button event callback function.
*
* @param btn_handle A button handle to unregister
* @param event Button event
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG Arguments is invalid.
*/
esp_err_t button_unregister_cb(button_handle_t btn_handle, button_event_t event);
/**
* @brief Get button event
*
* @param btn_handle Button handle
*
* @return Current button event. See button_event_t
*/
button_event_t button_get_event(button_handle_t btn_handle);
/**
* @brief Get button repeat times
*
* @param btn_handle Button handle
*
* @return button pressed times. For example, double-click return 2, triple-click return 3, etc.
*/
uint8_t button_get_repeat(button_handle_t btn_handle);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,79 @@
// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _IOT_BUTTON_ADC_H_
#define _IOT_BUTTON_ADC_H_
#include "driver/gpio.h"
#include "driver/adc.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ADC_BUTTON_COMBINE(channel, index) ((channel)<<8 | (index))
#define ADC_BUTTON_SPLIT_INDEX(data) ((uint32_t)(data)&0xff)
#define ADC_BUTTON_SPLIT_CHANNEL(data) (((uint32_t)(data) >> 8) & 0xff)
/**
* @brief adc button configuration
*
*/
typedef struct {
adc1_channel_t adc_channel; /**< Channel of ADC */
uint8_t button_index; /**< button index on the channel */
uint16_t min; /**< min voltage in mv corresponding to the button */
uint16_t max; /**< max voltage in mv corresponding to the button */
} button_adc_config_t;
/**
* @brief Initialize gpio button
*
* @param config pointer of configuration struct
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG Arguments is NULL.
* - ESP_ERR_NOT_SUPPORTED Arguments out of range.
* - ESP_ERR_INVALID_STATE State is error.
*/
esp_err_t button_adc_init(const button_adc_config_t *config);
/**
* @brief Deinitialize gpio button
*
* @param channel ADC channel
* @param button_index Button index on the channel
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG Arguments is invalid.
*/
esp_err_t button_adc_deinit(adc1_channel_t channel, int button_index);
/**
* @brief Get the adc button level
*
* @param button_index It is compressed by ADC channel and button index, use the macro ADC_BUTTON_COMBINE to generate. It will be treated as a uint32_t variable.
*
* @return
* - 0 Not pressed
* - 1 Pressed
*/
uint8_t button_adc_get_key_level(void *button_index);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,65 @@
// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _IOT_BUTTON_GPIO_H_
#define _IOT_BUTTON_GPIO_H_
#include "driver/gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief gpio button configuration
*
*/
typedef struct {
int32_t gpio_num;
uint8_t active_level;
} button_gpio_config_t;
/**
* @brief Initialize gpio button
*
* @param config pointer of configuration struct
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG Arguments is NULL.
*/
esp_err_t button_gpio_init(const button_gpio_config_t *config);
/**
* @brief Deinitialize gpio button
*
* @param gpio_num gpio number of button
*
* @return Always return ESP_OK
*/
esp_err_t button_gpio_deinit(int gpio_num);
/**
* @brief Get current level on button gpio
*
* @param gpio_num gpio number of button, it will be treated as a uint32_t variable.
*
* @return Level on gpio
*/
uint8_t button_gpio_get_key_level(void *gpio_num);
#ifdef __cplusplus
}
#endif
#endif
+290
View File
@@ -0,0 +1,290 @@
// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "button.h"
#include "esp_timer.h"
#include "sdkconfig.h"
static const char *TAG = "button";
#define BTN_CHECK(a, str, ret_val) \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): %s", __FUNCTION__, __LINE__, str); \
return (ret_val); \
}
//button handle list head.
static button_dev_t *g_head_handle = NULL;
static esp_timer_handle_t g_button_timer_handle;
static bool g_is_timer_running = false;
#define TICKS_INTERVAL CONFIG_BUTTON_PERIOD_TIME_MS
#define DEBOUNCE_TICKS CONFIG_BUTTON_DEBOUNCE_TICKS //MAX 8
#define SHORT_TICKS (CONFIG_BUTTON_SHORT_PRESS_TIME_MS /TICKS_INTERVAL)
#define LONG_TICKS (CONFIG_BUTTON_LONG_PRESS_TIME_MS /TICKS_INTERVAL)
#define CALL_EVENT_CB(ev) if(btn->cb[ev])btn->cb[ev](btn)
/**
* @brief Button driver core function, driver state machine.
*/
static void button_handler(button_dev_t *btn)
{
uint8_t read_gpio_level = btn->hal_button_Level(btn->usr_data);
/** ticks counter working.. */
if ((btn->state) > 0) {
btn->ticks++;
}
/**< button debounce handle */
if (read_gpio_level != btn->button_level) {
if (++(btn->debounce_cnt) >= DEBOUNCE_TICKS) {
btn->button_level = read_gpio_level;
btn->debounce_cnt = 0;
}
} else {
btn->debounce_cnt = 0;
}
/** State machine */
switch (btn->state) {
case 0:
if (btn->button_level == btn->active_level) {
btn->event = (uint8_t)BUTTON_PRESS_DOWN;
CALL_EVENT_CB(BUTTON_PRESS_DOWN);
btn->ticks = 0;
btn->repeat = 1;
btn->state = 1;
} else {
btn->event = (uint8_t)BUTTON_NONE_PRESS;
}
break;
case 1:
if (btn->button_level != btn->active_level) {
btn->event = (uint8_t)BUTTON_PRESS_UP;
CALL_EVENT_CB(BUTTON_PRESS_UP);
btn->ticks = 0;
btn->state = 2;
} else if (btn->ticks > LONG_TICKS) {
btn->event = (uint8_t)BUTTON_LONG_PRESS_START;
CALL_EVENT_CB(BUTTON_LONG_PRESS_START);
btn->state = 5;
}
break;
case 2:
if (btn->button_level == btn->active_level) {
btn->event = (uint8_t)BUTTON_PRESS_DOWN;
CALL_EVENT_CB(BUTTON_PRESS_DOWN);
btn->repeat++;
CALL_EVENT_CB(BUTTON_PRESS_REPEAT); // repeat hit
btn->ticks = 0;
btn->state = 3;
} else if (btn->ticks > SHORT_TICKS) {
if (btn->repeat == 1) {
btn->event = (uint8_t)BUTTON_SINGLE_CLICK;
CALL_EVENT_CB(BUTTON_SINGLE_CLICK);
} else if (btn->repeat == 2) {
btn->event = (uint8_t)BUTTON_DOUBLE_CLICK;
CALL_EVENT_CB(BUTTON_DOUBLE_CLICK); // repeat hit
}
btn->state = 0;
}
break;
case 3:
if (btn->button_level != btn->active_level) {
btn->event = (uint8_t)BUTTON_PRESS_UP;
CALL_EVENT_CB(BUTTON_PRESS_UP);
if (btn->ticks < SHORT_TICKS) {
btn->ticks = 0;
btn->state = 2; //repeat press
} else {
btn->state = 0;
}
}
break;
case 5:
if (btn->button_level == btn->active_level) {
//continue hold trigger
btn->event = (uint8_t)BUTTON_LONG_PRESS_HOLD;
CALL_EVENT_CB(BUTTON_LONG_PRESS_HOLD);
} else { //releasd
btn->event = (uint8_t)BUTTON_PRESS_UP;
CALL_EVENT_CB(BUTTON_PRESS_UP);
btn->state = 0; //reset
}
break;
}
}
static void button_cb(void *args)
{
button_dev_t *target;
for (target = g_head_handle; target; target = target->next) {
button_handler(target);
}
}
static button_dev_t *button_create_com(uint8_t active_level, uint8_t (*hal_get_key_state)(void *usr_data), void *usr_data)
{
BTN_CHECK(NULL != hal_get_key_state, "Function pointer is invalid", NULL);
button_dev_t *btn = (button_dev_t *) calloc(1, sizeof(button_dev_t));
BTN_CHECK(NULL != btn, "Button memory alloc failed", NULL);
btn->usr_data = usr_data;
btn->event = BUTTON_NONE_PRESS;
btn->active_level = active_level;
btn->hal_button_Level = hal_get_key_state;
btn->button_level = !active_level;
/** Add handle to list */
btn->next = g_head_handle;
g_head_handle = btn;
if (false == g_is_timer_running) {
esp_timer_create_args_t button_timer;
button_timer.arg = NULL;
button_timer.callback = button_cb;
button_timer.dispatch_method = ESP_TIMER_TASK;
button_timer.name = "button_timer";
esp_timer_create(&button_timer, &g_button_timer_handle);
esp_timer_start_periodic(g_button_timer_handle, TICKS_INTERVAL * 1000U);
g_is_timer_running = true;
}
return btn;
}
static esp_err_t button_delete_com(button_dev_t *btn)
{
BTN_CHECK(NULL != btn, "Pointer of handle is invalid", ESP_ERR_INVALID_ARG);
button_dev_t **curr;
for (curr = &g_head_handle; *curr; ) {
button_dev_t *entry = *curr;
if (entry == btn) {
*curr = entry->next;
free(entry);
} else {
curr = &entry->next;
}
}
/* count button number */
uint16_t number = 0;
button_dev_t *target = g_head_handle;
while (target) {
target = target->next;
number++;
}
ESP_LOGD(TAG, "remain btn number=%d", number);
if (0 == number && g_is_timer_running) { /**< if all button is deleted, stop the timer */
esp_timer_stop(g_button_timer_handle);
esp_timer_delete(g_button_timer_handle);
g_is_timer_running = false;
}
return ESP_OK;
}
button_handle_t button_create(const button_config_t *config)
{
esp_err_t ret = ESP_OK;
button_dev_t *btn = NULL;
switch (config->type) {
case BUTTON_TYPE_GPIO: {
const button_gpio_config_t *cfg = &(config->gpio_button_config);
ret = button_gpio_init(cfg);
BTN_CHECK(ESP_OK == ret, "gpio button init failed", NULL);
btn = button_create_com(cfg->active_level, button_gpio_get_key_level, (void *)cfg->gpio_num);
} break;
case BUTTON_TYPE_ADC: {
const button_adc_config_t *cfg = &(config->adc_button_config);
ret = button_adc_init(cfg);
BTN_CHECK(ESP_OK == ret, "adc button init failed", NULL);
btn = button_create_com(1, button_adc_get_key_level, (void *)ADC_BUTTON_COMBINE(cfg->adc_channel, cfg->button_index));
} break;
default:
ESP_LOGE(TAG, "Unsupported button type");
break;
}
BTN_CHECK(NULL != btn, "button create failed", NULL);
btn->type = config->type;
return (button_handle_t)btn;
}
esp_err_t button_delete(button_handle_t btn_handle)
{
esp_err_t ret = ESP_OK;
BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", ESP_ERR_INVALID_ARG);
button_dev_t *btn = (button_dev_t *)btn_handle;
switch (btn->type) {
case BUTTON_TYPE_GPIO:
ret = button_gpio_deinit((int)(btn->usr_data));
break;
case BUTTON_TYPE_ADC:
ret = button_adc_deinit(ADC_BUTTON_SPLIT_CHANNEL(btn->usr_data), ADC_BUTTON_SPLIT_INDEX(btn->usr_data));
break;
default:
break;
}
BTN_CHECK(ESP_OK == ret, "button deinit failed", ESP_FAIL);
button_delete_com(btn);
return ESP_OK;
}
esp_err_t button_register_cb(button_handle_t btn_handle, button_event_t event, button_cb_t cb)
{
BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", ESP_ERR_INVALID_ARG);
BTN_CHECK(event < BUTTON_EVENT_MAX, "event is invalid", ESP_ERR_INVALID_ARG);
button_dev_t *btn = (button_dev_t *) btn_handle;
btn->cb[event] = cb;
return ESP_OK;
}
esp_err_t button_unregister_cb(button_handle_t btn_handle, button_event_t event)
{
BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", ESP_ERR_INVALID_ARG);
BTN_CHECK(event < BUTTON_EVENT_MAX, "event is invalid", ESP_ERR_INVALID_ARG);
button_dev_t *btn = (button_dev_t *) btn_handle;
btn->cb[event] = NULL;
return ESP_OK;
}
button_event_t button_get_event(button_handle_t btn_handle)
{
BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", BUTTON_NONE_PRESS);
button_dev_t *btn = (button_dev_t *) btn_handle;
return btn->event;
}
uint8_t button_get_repeat(button_handle_t btn_handle)
{
BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", 0);
button_dev_t *btn = (button_dev_t *) btn_handle;
return btn->repeat;
}
@@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS "."
PRIV_INCLUDE_DIRS "."
PRIV_REQUIRES unity test_utils)
+234
View File
@@ -0,0 +1,234 @@
// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "stdio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/timers.h"
#include "esp_log.h"
#include "unity.h"
#include "iot_button.h"
static const char *TAG = "BUTTON TEST";
#define BUTTON_IO_NUM 0
#define BUTTON_ACTIVE_LEVEL 0
#define BUTTON_NUM 16
static button_handle_t g_btns[BUTTON_NUM] = {0};
static int get_btn_index(button_handle_t btn)
{
for (size_t i = 0; i < BUTTON_NUM; i++) {
if (btn == g_btns[i]) {
return i;
}
}
return -1;
}
static void button_press_down_cb(void *arg)
{
TEST_ASSERT_EQUAL_HEX(BUTTON_PRESS_DOWN, iot_button_get_event(arg));
ESP_LOGI(TAG, "BTN%d: BUTTON_PRESS_DOWN", get_btn_index((button_handle_t)arg));
}
static void button_press_up_cb(void *arg)
{
TEST_ASSERT_EQUAL_HEX(BUTTON_PRESS_UP, iot_button_get_event(arg));
ESP_LOGI(TAG, "BTN%d: BUTTON_PRESS_UP", get_btn_index((button_handle_t)arg));
}
static void button_press_repeat_cb(void *arg)
{
ESP_LOGI(TAG, "BTN%d: BUTTON_PRESS_REPEAT[%d]", get_btn_index((button_handle_t)arg), iot_button_get_repeat((button_handle_t)arg));
}
static void button_single_click_cb(void *arg)
{
TEST_ASSERT_EQUAL_HEX(BUTTON_SINGLE_CLICK, iot_button_get_event(arg));
ESP_LOGI(TAG, "BTN%d: BUTTON_SINGLE_CLICK", get_btn_index((button_handle_t)arg));
}
static void button_double_click_cb(void *arg)
{
TEST_ASSERT_EQUAL_HEX(BUTTON_DOUBLE_CLICK, iot_button_get_event(arg));
ESP_LOGI(TAG, "BTN%d: BUTTON_DOUBLE_CLICK", get_btn_index((button_handle_t)arg));
}
static void button_long_press_start_cb(void *arg)
{
TEST_ASSERT_EQUAL_HEX(BUTTON_LONG_PRESS_START, iot_button_get_event(arg));
ESP_LOGI(TAG, "BTN%d: BUTTON_LONG_PRESS_START", get_btn_index((button_handle_t)arg));
}
static void button_long_press_hold_cb(void *arg)
{
TEST_ASSERT_EQUAL_HEX(BUTTON_LONG_PRESS_HOLD, iot_button_get_event(arg));
ESP_LOGI(TAG, "BTN%d: BUTTON_LONG_PRESS_HOLD", get_btn_index((button_handle_t)arg));
}
static void print_button_event(button_handle_t btn)
{
button_event_t evt = iot_button_get_event(btn);
switch (evt) {
case BUTTON_PRESS_DOWN:
ESP_LOGI(TAG, "BUTTON_PRESS_DOWN");
break;
case BUTTON_PRESS_UP:
ESP_LOGI(TAG, "BUTTON_PRESS_UP");
break;
case BUTTON_PRESS_REPEAT:
ESP_LOGI(TAG, "BUTTON_PRESS_REPEAT");
break;
case BUTTON_SINGLE_CLICK:
ESP_LOGI(TAG, "BUTTON_SINGLE_CLICK");
break;
case BUTTON_DOUBLE_CLICK:
ESP_LOGI(TAG, "BUTTON_DOUBLE_CLICK");
break;
case BUTTON_LONG_PRESS_START:
ESP_LOGI(TAG, "BUTTON_LONG_PRESS_START");
break;
case BUTTON_LONG_PRESS_HOLD:
ESP_LOGI(TAG, "BUTTON_LONG_PRESS_HOLD");
break;
default:
break;
}
}
TEST_CASE("gpio button test", "[button][iot]")
{
button_config_t cfg = {
.type = BUTTON_TYPE_GPIO,
.gpio_button_config = {
.gpio_num = 0,
.active_level = 0,
},
};
g_btns[0] = iot_button_create(&cfg);
TEST_ASSERT_NOT_NULL(g_btns[0]);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_DOWN, button_press_down_cb);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_UP, button_press_up_cb);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT, button_press_repeat_cb);
iot_button_register_cb(g_btns[0], BUTTON_SINGLE_CLICK, button_single_click_cb);
iot_button_register_cb(g_btns[0], BUTTON_DOUBLE_CLICK, button_double_click_cb);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_START, button_long_press_start_cb);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb);
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
iot_button_delete(g_btns[0]);
}
TEST_CASE("adc button test", "[button][iot]")
{
/** ESP32-LyraT-Mini board */
const uint16_t vol[6] = {380, 820, 1180, 1570, 1980, 2410};
button_config_t cfg = {0};
cfg.type = BUTTON_TYPE_ADC;
for (size_t i = 0; i < 6; i++) {
cfg.adc_button_config.adc_channel = 3,
cfg.adc_button_config.button_index = i;
if (i == 0) {
cfg.adc_button_config.min = (0 + vol[i]) / 2;
} else {
cfg.adc_button_config.min = (vol[i - 1] + vol[i]) / 2;
}
if (i == 5) {
cfg.adc_button_config.max = (vol[i] + 3000) / 2;
} else {
cfg.adc_button_config.max = (vol[i] + vol[i + 1]) / 2;
}
g_btns[i] = iot_button_create(&cfg);
TEST_ASSERT_NOT_NULL(g_btns[i]);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_DOWN, button_press_down_cb);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_UP, button_press_up_cb);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT, button_press_repeat_cb);
iot_button_register_cb(g_btns[i], BUTTON_SINGLE_CLICK, button_single_click_cb);
iot_button_register_cb(g_btns[i], BUTTON_DOUBLE_CLICK, button_double_click_cb);
iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_START, button_long_press_start_cb);
iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb);
}
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
for (size_t i = 0; i < 6; i++) {
iot_button_delete(g_btns[i]);
}
}
TEST_CASE("adc gpio button test", "[button][iot]")
{
button_config_t cfg = {
.type = BUTTON_TYPE_GPIO,
.gpio_button_config = {
.gpio_num = 0,
.active_level = 0,
},
};
g_btns[8] = iot_button_create(&cfg);
TEST_ASSERT_NOT_NULL(g_btns[8]);
iot_button_register_cb(g_btns[8], BUTTON_PRESS_DOWN, button_press_down_cb);
iot_button_register_cb(g_btns[8], BUTTON_PRESS_UP, button_press_up_cb);
iot_button_register_cb(g_btns[8], BUTTON_PRESS_REPEAT, button_press_repeat_cb);
iot_button_register_cb(g_btns[8], BUTTON_SINGLE_CLICK, button_single_click_cb);
iot_button_register_cb(g_btns[8], BUTTON_DOUBLE_CLICK, button_double_click_cb);
iot_button_register_cb(g_btns[8], BUTTON_LONG_PRESS_START, button_long_press_start_cb);
iot_button_register_cb(g_btns[8], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb);
/** ESP32-LyraT-Mini board */
const uint16_t vol[6] = {380, 820, 1180, 1570, 1980, 2410};
// button_config_t cfg = {0};
cfg.type = BUTTON_TYPE_ADC;
for (size_t i = 0; i < 6; i++) {
cfg.adc_button_config.adc_channel = 3,
cfg.adc_button_config.button_index = i;
if (i == 0) {
cfg.adc_button_config.min = (0 + vol[i]) / 2;
} else {
cfg.adc_button_config.min = (vol[i - 1] + vol[i]) / 2;
}
if (i == 5) {
cfg.adc_button_config.max = (vol[i] + 3000) / 2;
} else {
cfg.adc_button_config.max = (vol[i] + vol[i + 1]) / 2;
}
g_btns[i] = iot_button_create(&cfg);
TEST_ASSERT_NOT_NULL(g_btns[i]);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_DOWN, button_press_down_cb);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_UP, button_press_up_cb);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT, button_press_repeat_cb);
iot_button_register_cb(g_btns[i], BUTTON_SINGLE_CLICK, button_single_click_cb);
iot_button_register_cb(g_btns[i], BUTTON_DOUBLE_CLICK, button_double_click_cb);
iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_START, button_long_press_start_cb);
iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb);
}
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
for (size_t i = 0; i < 6; i++) {
iot_button_delete(g_btns[i]);
}
}
+5
View File
@@ -0,0 +1,5 @@
#
#Component Makefile
#
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
+4
View File
@@ -846,6 +846,10 @@ menu "LVGL configuration"
default y if !LV_CONF_MINIMAL
endmenu
config LV_PORT_SHOW_MOUSE_CURSOR
bool "Show mouse cursor icon on screen. It's useful when use HID device as input."
default n
config LV_BUILD_EXAMPLES
bool "Enable the examples to be built with the library."
default y
+478
View File
@@ -0,0 +1,478 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#if CONFIG_BT_BLE_42_FEATURES_SUPPORTED
#include <string.h>
#include <stdbool.h>
#include "esp_hid_gap.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
static const char *TAG = "ESP_HID_GAP";
// uncomment to print all devices that were seen during a scan
#define GAP_DBG_PRINTF(...) //printf(__VA_ARGS__)
//static const char * gap_bt_prop_type_names[5] = {"","BDNAME","COD","RSSI","EIR"};
static esp_hid_scan_result_t *bt_scan_results = NULL;
static size_t num_bt_scan_results = 0;
static esp_hid_scan_result_t *ble_scan_results = NULL;
static size_t num_ble_scan_results = 0;
static xSemaphoreHandle bt_hidh_cb_semaphore = NULL;
#define WAIT_BT_CB() xSemaphoreTake(bt_hidh_cb_semaphore, portMAX_DELAY)
#define SEND_BT_CB() xSemaphoreGive(bt_hidh_cb_semaphore)
static xSemaphoreHandle ble_hidh_cb_semaphore = NULL;
#define WAIT_BLE_CB() xSemaphoreTake(ble_hidh_cb_semaphore, portMAX_DELAY)
#define SEND_BLE_CB() xSemaphoreGive(ble_hidh_cb_semaphore)
#define SIZEOF_ARRAY(a) (sizeof(a)/sizeof(*a))
static const char *ble_gap_evt_names[] = { "ADV_DATA_SET_COMPLETE", "SCAN_RSP_DATA_SET_COMPLETE", "SCAN_PARAM_SET_COMPLETE", "SCAN_RESULT", "ADV_DATA_RAW_SET_COMPLETE", "SCAN_RSP_DATA_RAW_SET_COMPLETE", "ADV_START_COMPLETE", "SCAN_START_COMPLETE", "AUTH_CMPL", "KEY", "SEC_REQ", "PASSKEY_NOTIF", "PASSKEY_REQ", "OOB_REQ", "LOCAL_IR", "LOCAL_ER", "NC_REQ", "ADV_STOP_COMPLETE", "SCAN_STOP_COMPLETE", "SET_STATIC_RAND_ADDR", "UPDATE_CONN_PARAMS", "SET_PKT_LENGTH_COMPLETE", "SET_LOCAL_PRIVACY_COMPLETE", "REMOVE_BOND_DEV_COMPLETE", "CLEAR_BOND_DEV_COMPLETE", "GET_BOND_DEV_COMPLETE", "READ_RSSI_COMPLETE", "UPDATE_WHITELIST_COMPLETE"};
static const char *bt_gap_evt_names[] = { "DISC_RES", "DISC_STATE_CHANGED", "RMT_SRVCS", "RMT_SRVC_REC", "AUTH_CMPL", "PIN_REQ", "CFM_REQ", "KEY_NOTIF", "KEY_REQ", "READ_RSSI_DELTA"};
static const char *ble_addr_type_names[] = {"PUBLIC", "RANDOM", "RPA_PUBLIC", "RPA_RANDOM"};
const char *ble_addr_type_str(esp_ble_addr_type_t ble_addr_type)
{
if (ble_addr_type > BLE_ADDR_TYPE_RPA_RANDOM) {
return "UNKNOWN";
}
return ble_addr_type_names[ble_addr_type];
}
const char *ble_gap_evt_str(uint8_t event)
{
if (event >= SIZEOF_ARRAY(ble_gap_evt_names)) {
return "UNKNOWN";
}
return ble_gap_evt_names[event];
}
const char *bt_gap_evt_str(uint8_t event)
{
if (event >= SIZEOF_ARRAY(bt_gap_evt_names)) {
return "UNKNOWN";
}
return bt_gap_evt_names[event];
}
const char *esp_ble_key_type_str(esp_ble_key_type_t key_type)
{
const char *key_str = NULL;
switch (key_type) {
case ESP_LE_KEY_NONE:
key_str = "ESP_LE_KEY_NONE";
break;
case ESP_LE_KEY_PENC:
key_str = "ESP_LE_KEY_PENC";
break;
case ESP_LE_KEY_PID:
key_str = "ESP_LE_KEY_PID";
break;
case ESP_LE_KEY_PCSRK:
key_str = "ESP_LE_KEY_PCSRK";
break;
case ESP_LE_KEY_PLK:
key_str = "ESP_LE_KEY_PLK";
break;
case ESP_LE_KEY_LLK:
key_str = "ESP_LE_KEY_LLK";
break;
case ESP_LE_KEY_LENC:
key_str = "ESP_LE_KEY_LENC";
break;
case ESP_LE_KEY_LID:
key_str = "ESP_LE_KEY_LID";
break;
case ESP_LE_KEY_LCSRK:
key_str = "ESP_LE_KEY_LCSRK";
break;
default:
key_str = "INVALID BLE KEY TYPE";
break;
}
return key_str;
}
void esp_hid_scan_results_free(esp_hid_scan_result_t *results)
{
esp_hid_scan_result_t *r = NULL;
while (results) {
r = results;
results = results->next;
if (r->name != NULL) {
free((char *)r->name);
}
free(r);
}
}
static esp_hid_scan_result_t *find_scan_result(esp_bd_addr_t bda, esp_hid_scan_result_t *results)
{
esp_hid_scan_result_t *r = results;
while (r) {
if (memcmp(bda, r->bda, sizeof(esp_bd_addr_t)) == 0) {
return r;
}
r = r->next;
}
return NULL;
}
static void add_ble_scan_result(esp_bd_addr_t bda, esp_ble_addr_type_t addr_type, uint16_t appearance, uint8_t *name, uint8_t name_len, int rssi)
{
if (find_scan_result(bda, ble_scan_results)) {
ESP_LOGW(TAG, "Result already exists!");
return;
}
esp_hid_scan_result_t *r = (esp_hid_scan_result_t *)malloc(sizeof(esp_hid_scan_result_t));
if (r == NULL) {
ESP_LOGE(TAG, "Malloc ble_hidh_scan_result_t failed!");
return;
}
r->transport = ESP_HID_TRANSPORT_BLE;
memcpy(r->bda, bda, sizeof(esp_bd_addr_t));
r->ble.appearance = appearance;
r->ble.addr_type = addr_type;
r->usage = esp_hid_usage_from_appearance(appearance);
r->rssi = rssi;
r->name = NULL;
if (name_len && name) {
char *name_s = (char *)malloc(name_len + 1);
if (name_s == NULL) {
free(r);
ESP_LOGE(TAG, "Malloc result name failed!");
return;
}
memcpy(name_s, name, name_len);
name_s[name_len] = 0;
r->name = (const char *)name_s;
}
r->next = ble_scan_results;
ble_scan_results = r;
num_ble_scan_results++;
}
void print_uuid(esp_bt_uuid_t *uuid)
{
if (uuid->len == ESP_UUID_LEN_16) {
GAP_DBG_PRINTF("UUID16: 0x%04x", uuid->uuid.uuid16);
} else if (uuid->len == ESP_UUID_LEN_32) {
GAP_DBG_PRINTF("UUID32: 0x%08x", uuid->uuid.uuid32);
} else if (uuid->len == ESP_UUID_LEN_128) {
GAP_DBG_PRINTF("UUID128: %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x", uuid->uuid.uuid128[0],
uuid->uuid.uuid128[1], uuid->uuid.uuid128[2], uuid->uuid.uuid128[3],
uuid->uuid.uuid128[4], uuid->uuid.uuid128[5], uuid->uuid.uuid128[6],
uuid->uuid.uuid128[7], uuid->uuid.uuid128[8], uuid->uuid.uuid128[9],
uuid->uuid.uuid128[10], uuid->uuid.uuid128[11], uuid->uuid.uuid128[12],
uuid->uuid.uuid128[13], uuid->uuid.uuid128[14], uuid->uuid.uuid128[15]);
}
}
static void handle_ble_device_result(struct ble_scan_result_evt_param *scan_rst)
{
uint16_t uuid = 0;
uint16_t appearance = 0;
char name[64] = {0};
uint8_t uuid_len = 0;
uint8_t *uuid_d = esp_ble_resolve_adv_data(scan_rst->ble_adv, ESP_BLE_AD_TYPE_16SRV_CMPL, &uuid_len);
if (uuid_d != NULL && uuid_len) {
uuid = uuid_d[0] + (uuid_d[1] << 8);
}
uint8_t appearance_len = 0;
uint8_t *appearance_d = esp_ble_resolve_adv_data(scan_rst->ble_adv, ESP_BLE_AD_TYPE_APPEARANCE, &appearance_len);
if (appearance_d != NULL && appearance_len) {
appearance = appearance_d[0] + (appearance_d[1] << 8);
}
uint8_t adv_name_len = 0;
uint8_t *adv_name = esp_ble_resolve_adv_data(scan_rst->ble_adv, ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len);
if (adv_name == NULL) {
adv_name = esp_ble_resolve_adv_data(scan_rst->ble_adv, ESP_BLE_AD_TYPE_NAME_SHORT, &adv_name_len);
}
if (adv_name != NULL && adv_name_len) {
memcpy(name, adv_name, adv_name_len);
name[adv_name_len] = 0;
}
GAP_DBG_PRINTF("BLE: " ESP_BD_ADDR_STR ", ", ESP_BD_ADDR_HEX(scan_rst->bda));
GAP_DBG_PRINTF("RSSI: %d, ", scan_rst->rssi);
GAP_DBG_PRINTF("UUID: 0x%04x, ", uuid);
GAP_DBG_PRINTF("APPEARANCE: 0x%04x, ", appearance);
GAP_DBG_PRINTF("ADDR_TYPE: '%s'", ble_addr_type_str(scan_rst->ble_addr_type));
if (adv_name_len) {
GAP_DBG_PRINTF(", NAME: '%s'", name);
}
GAP_DBG_PRINTF("\n");
if (uuid == ESP_GATT_UUID_HID_SVC) {
add_ble_scan_result(scan_rst->bda, scan_rst->ble_addr_type, appearance, adv_name, adv_name_len, scan_rst->rssi);
}
}
/*
* BLE GAP
* */
static void ble_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
switch (event) {
/*
* SCAN
* */
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: {
ESP_LOGV(TAG, "BLE GAP EVENT SCAN_PARAM_SET_COMPLETE");
SEND_BLE_CB();
break;
}
case ESP_GAP_BLE_SCAN_RESULT_EVT: {
esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;
switch (scan_result->scan_rst.search_evt) {
case ESP_GAP_SEARCH_INQ_RES_EVT: {
handle_ble_device_result(&scan_result->scan_rst);
break;
}
case ESP_GAP_SEARCH_INQ_CMPL_EVT:
ESP_LOGV(TAG, "BLE GAP EVENT SCAN DONE: %d", scan_result->scan_rst.num_resps);
SEND_BLE_CB();
break;
default:
break;
}
break;
}
case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: {
ESP_LOGV(TAG, "BLE GAP EVENT SCAN CANCELED");
break;
}
/*
* ADVERTISEMENT
* */
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
ESP_LOGV(TAG, "BLE GAP ADV_DATA_SET_COMPLETE");
break;
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
ESP_LOGV(TAG, "BLE GAP ADV_START_COMPLETE");
break;
/*
* AUTHENTICATION
* */
case ESP_GAP_BLE_AUTH_CMPL_EVT:
if (!param->ble_security.auth_cmpl.success) {
ESP_LOGE(TAG, "BLE GAP AUTH ERROR: 0x%x", param->ble_security.auth_cmpl.fail_reason);
} else {
ESP_LOGI(TAG, "BLE GAP AUTH SUCCESS");
}
break;
case ESP_GAP_BLE_KEY_EVT: //shows the ble key info share with peer device to the user.
ESP_LOGI(TAG, "BLE GAP KEY type = %s", esp_ble_key_type_str(param->ble_security.ble_key.key_type));
break;
case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: // ESP_IO_CAP_OUT
// The app will receive this evt when the IO has Output capability and the peer device IO has Input capability.
// Show the passkey number to the user to input it in the peer device.
ESP_LOGI(TAG, "BLE GAP PASSKEY_NOTIF passkey:%d", param->ble_security.key_notif.passkey);
break;
case ESP_GAP_BLE_NC_REQ_EVT: // ESP_IO_CAP_IO
// The app will receive this event when the IO has DisplayYesNO capability and the peer device IO also has DisplayYesNo capability.
// show the passkey number to the user to confirm it with the number displayed by peer device.
ESP_LOGI(TAG, "BLE GAP NC_REQ passkey:%d", param->ble_security.key_notif.passkey);
esp_ble_confirm_reply(param->ble_security.key_notif.bd_addr, true);
break;
case ESP_GAP_BLE_PASSKEY_REQ_EVT: // ESP_IO_CAP_IN
// The app will receive this evt when the IO has Input capability and the peer device IO has Output capability.
// See the passkey number on the peer device and send it back.
ESP_LOGI(TAG, "BLE GAP PASSKEY_REQ");
//esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, 1234);
break;
case ESP_GAP_BLE_SEC_REQ_EVT:
ESP_LOGI(TAG, "BLE GAP SEC_REQ");
// Send the positive(true) security response to the peer device to accept the security request.
// If not accept the security request, should send the security response with negative(false) accept value.
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
break;
default:
ESP_LOGV(TAG, "BLE GAP EVENT %s", ble_gap_evt_str(event));
break;
}
}
static esp_err_t init_ble_gap(void)
{
esp_err_t ret;
if ((ret = esp_ble_gap_register_callback(ble_gap_event_handler)) != ESP_OK) {
ESP_LOGE(TAG, "esp_ble_gap_register_callback failed: %d", ret);
return ret;
}
return ret;
}
static esp_ble_scan_params_t hid_scan_params = {
.scan_type = BLE_SCAN_TYPE_ACTIVE,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
.scan_interval = 0x50,
.scan_window = 0x30,
.scan_duplicate = BLE_SCAN_DUPLICATE_ENABLE,
};
static esp_err_t start_ble_scan(uint32_t seconds)
{
esp_err_t ret = ESP_OK;
if ((ret = esp_ble_gap_set_scan_params(&hid_scan_params)) != ESP_OK) {
ESP_LOGE(TAG, "esp_ble_gap_set_scan_params failed: %d", ret);
return ret;
}
WAIT_BLE_CB();
if ((ret = esp_ble_gap_start_scanning(seconds)) != ESP_OK) {
ESP_LOGE(TAG, "esp_ble_gap_start_scanning failed: %d", ret);
return ret;
}
return ret;
}
/*
* CONTROLLER INIT
* */
static esp_err_t init_low_level(uint8_t mode)
{
esp_err_t ret;
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
{
ret = esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
if (ret) {
ESP_LOGE(TAG, "esp_bt_controller_mem_release failed: %d", ret);
return ret;
}
}
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
ESP_LOGE(TAG, "esp_bt_controller_init failed: %d", ret);
return ret;
}
ret = esp_bt_controller_enable(mode);
if (ret) {
ESP_LOGE(TAG, "esp_bt_controller_enable failed: %d", ret);
return ret;
}
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(TAG, "esp_bluedroid_init failed: %d", ret);
return ret;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(TAG, "esp_bluedroid_enable failed: %d", ret);
return ret;
}
if (mode & ESP_BT_MODE_BLE) {
ret = init_ble_gap();
if (ret) {
return ret;
}
}
return ret;
}
esp_err_t esp_hid_gap_init(uint8_t mode)
{
esp_err_t ret;
if (!mode || mode > ESP_BT_MODE_BTDM) {
ESP_LOGE(TAG, "Invalid mode given!");
return ESP_FAIL;
}
if (bt_hidh_cb_semaphore != NULL) {
ESP_LOGE(TAG, "Already initialised");
return ESP_FAIL;
}
bt_hidh_cb_semaphore = xSemaphoreCreateBinary();
if (bt_hidh_cb_semaphore == NULL) {
ESP_LOGE(TAG, "xSemaphoreCreateMutex failed!");
return ESP_FAIL;
}
ble_hidh_cb_semaphore = xSemaphoreCreateBinary();
if (ble_hidh_cb_semaphore == NULL) {
ESP_LOGE(TAG, "xSemaphoreCreateMutex failed!");
vSemaphoreDelete(bt_hidh_cb_semaphore);
bt_hidh_cb_semaphore = NULL;
return ESP_FAIL;
}
ret = init_low_level(mode);
if (ret != ESP_OK) {
vSemaphoreDelete(bt_hidh_cb_semaphore);
bt_hidh_cb_semaphore = NULL;
vSemaphoreDelete(ble_hidh_cb_semaphore);
ble_hidh_cb_semaphore = NULL;
return ret;
}
return ESP_OK;
}
esp_err_t esp_hid_scan(uint32_t seconds, size_t *num_results, esp_hid_scan_result_t **results)
{
if (num_bt_scan_results || bt_scan_results || num_ble_scan_results || ble_scan_results) {
ESP_LOGE(TAG, "There are old scan results. Free them first!");
return ESP_FAIL;
}
if (start_ble_scan(seconds) == ESP_OK) {
WAIT_BLE_CB();
} else {
return ESP_FAIL;
}
*num_results = num_bt_scan_results + num_ble_scan_results;
*results = bt_scan_results;
if (num_bt_scan_results) {
while (bt_scan_results->next != NULL) {
bt_scan_results = bt_scan_results->next;
}
bt_scan_results->next = ble_scan_results;
} else {
*results = ble_scan_results;
}
num_bt_scan_results = 0;
bt_scan_results = NULL;
num_ble_scan_results = 0;
ble_scan_results = NULL;
return ESP_OK;
}
#endif
@@ -0,0 +1,97 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#if CONFIG_BT_ENABLED && CONFIG_BT_BLE_42_FEATURES_SUPPORTED
#include "esp_err.h"
#include "esp_log.h"
#include "esp_bt.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_gattc_api.h"
#include "esp_gatt_defs.h"
#include "esp_gap_ble_api.h"
#include "esp_gap_bt_api.h"
#include "esp_hid_common.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct esp_hidh_scan_result_s {
struct esp_hidh_scan_result_s *next;
esp_bd_addr_t bda;
const char *name;
int8_t rssi;
esp_hid_usage_t usage;
esp_hid_transport_t transport; //BT, BLE or USB
union {
struct {
esp_bt_cod_t cod;
esp_bt_uuid_t uuid;
} bt;
struct {
esp_ble_addr_type_t addr_type;
uint16_t appearance;
} ble;
};
} esp_hid_scan_result_t;
/**
* @brief Init HID GAP
*
* @param mode See `esp_bt_mode_t`
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t esp_hid_gap_init(uint8_t mode);
/**
* @brief
*
* @param seconds Timeout in seconds
* @param num_results Total scaned result
* @param results Pointer to results
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t esp_hid_scan(uint32_t seconds, size_t *num_results, esp_hid_scan_result_t **results);
/**
* @brief Free HID scan result
*
* @param results Pointer to `esp_hid_scan_result_t`
*/
void esp_hid_scan_results_free(esp_hid_scan_result_t *results);
/**
* @brief Print UUID
*
* @param uuid UUID of device
*/
void print_uuid(esp_bt_uuid_t *uuid);
/**
* @brief Convert BLE addr type value to string
*
* @param ble_addr_type See `ble_addr_type`
* @return String of BLE addr type
*/
const char *ble_addr_type_str(esp_ble_addr_type_t ble_addr_type);
#ifdef __cplusplus
}
#endif
#endif /* CONFIG_BT_BLE_42_FEATURES_SUPPORTED */
+104
View File
@@ -0,0 +1,104 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <stdint.h>
#include "esp_log.h"
#include "bsp_board.h"
#include "bsp_btn.h"
#include "indev.h"
#include "indev_hid.h"
#include "indev_tp.h"
#include "esp_err.h"
static indev_type_t g_major_dev = BSP_INDEV_NONE;
static esp_err_t indev_init(indev_type_t indev)
{
switch (indev) {
case BSP_INDEV_TP:
return indev_tp_init();
break;
case BSP_INDEV_BTN:
return ESP_OK; // button should be initialized before here
break;
case BSP_INDEV_HID:
return indev_hid_init_default();
break;
default:
return ESP_ERR_INVALID_ARG;
break;
}
return ESP_ERR_INVALID_ARG;
}
esp_err_t indev_init_default(void)
{
esp_err_t ret = ESP_ERR_NOT_SUPPORTED;
const board_res_desc_t *brd = bsp_board_get_description();
if (brd->BSP_INDEV_IS_TP) {
ret = indev_init(BSP_INDEV_TP);
if (ESP_OK == ret) {
g_major_dev = BSP_INDEV_TP;
}
} else {
ret = indev_init(BSP_INDEV_BTN);
if (ESP_OK == ret) {
g_major_dev = BSP_INDEV_BTN;
}
}
return ret;
}
esp_err_t indev_get_major_value(indev_data_t *data)
{
uint16_t x, y;
uint8_t tp_num, btn_val;
indev_hid_state_t hid_indev_data;
switch (g_major_dev) {
case BSP_INDEV_TP:
if (ESP_OK == indev_tp_read(&tp_num, &x, &y, &btn_val)) {
data->x = x;
data->y = y;
data->btn_val = btn_val;
if (tp_num > 0) {
data->pressed = true;
} else {
data->pressed = false;
}
}
break;
case BSP_INDEV_HID:
if (ESP_OK == indev_hid_get_value(&hid_indev_data)) {
data->x = hid_indev_data.x;
data->y = hid_indev_data.y;
data->btn_val = hid_indev_data.btn_val;
if (data->btn_val) {
data->pressed = true;
} else {
data->pressed = false;
}
}
break;
case BSP_INDEV_BTN:
data->btn_val = bsp_btn_get_state(BOARD_BTN_ID_PREV) << 2 | bsp_btn_get_state(BOARD_BTN_ID_ENTER) << 1 | bsp_btn_get_state(BOARD_BTN_ID_NEXT);
if (data->btn_val) {
data->pressed = true;
} else {
data->pressed = false;
}
break;
default:
return ESP_ERR_INVALID_STATE;
}
return ESP_OK;
}
+55
View File
@@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
BSP_INDEV_NONE = 0,
BSP_INDEV_TP,
BSP_INDEV_BTN,
BSP_INDEV_HID,
BSP_INDEV_MAX,
} indev_type_t; /* Type of input device */
typedef struct {
int32_t x;
int32_t y;
int32_t z;
int32_t btn_val;
bool pressed;
} indev_data_t;
/**
* @brief Call default input device init code
*
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t indev_init_default(void);
/**
* @brief Get major indev data
*
* @param data Pointer to `indev_data_t`
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t indev_get_major_value(indev_data_t *data);
#ifdef __cplusplus
}
#endif
+246
View File
@@ -0,0 +1,246 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#if CONFIG_BT_BLE_42_FEATURES_SUPPORTED
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bsp_board.h"
#include "bsp_hid_indev.h"
#include "esp_bt.h"
#include "esp_bt_defs.h"
#include "esp_bt_device.h"
#include "esp_bt_main.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_hidh.h"
#include "esp_hid_gap.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_gatt_defs.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static const char *TAG = "hid_mouse";
static void *bsp_mouse_handle = NULL;
static indev_hid_state_t mouse_state = { .x = 0, .y = 0, .press = false };
static void bsp_mouse_default_task(void *pvParam);
static void hid_callback(void *handler_args, esp_event_base_t base, int32_t id, void *event_data);
esp_err_t indev_hid_init(indev_hid_conf_t *conf)
{
ESP_RETURN_ON_FALSE(NULL == bsp_mouse_handle, ESP_ERR_INVALID_STATE,
TAG, "Mouse device already initialized");
bsp_mouse_handle = malloc(sizeof(indev_hid_conf_t));
ESP_RETURN_ON_FALSE(NULL != bsp_mouse_handle, ESP_ERR_NO_MEM,
TAG, "Failed create mouse handle");
memcpy(bsp_mouse_handle, conf, sizeof(indev_hid_conf_t));
if (conf->init_ble_service) {
/* Initialize BLE */
ESP_ERROR_CHECK(esp_hid_gap_init(ESP_BT_MODE_BLE));
ESP_ERROR_CHECK(esp_ble_gattc_register_callback(esp_hidh_gattc_event_handler));
}
esp_hidh_config_t config = {
.callback = hid_callback,
.event_stack_size = 4096,
};
ESP_ERROR_CHECK(esp_hidh_init(&config));
/* Mouse device default task */
BaseType_t ret_val = xTaskCreatePinnedToCore(
(TaskFunction_t) bsp_mouse_default_task,
(const char * const) "Mouse Task",
(const uint32_t) 6 * 1024,
(void * const) NULL,
(UBaseType_t) 1,
(TaskHandle_t * const) NULL,
(const BaseType_t) 0);
if (pdPASS != ret_val) {
ESP_LOGE(TAG, "Failed create mouse task");
return ESP_ERR_NO_MEM;
}
return ESP_OK;
}
esp_err_t indev_hid_init_default(void)
{
indev_hid_conf_t conf = {
.init_ble_service = true,
};
return bsp_hid_indev_init(&conf);
}
esp_err_t indev_hid_get_value(indev_hid_state_t *state)
{
if (NULL == bsp_mouse_handle) {
return ESP_ERR_INVALID_STATE;
}
memcpy(state, &mouse_state, sizeof(indev_hid_state_t));
return ESP_OK;
}
/* **************** TASK, CALLBACK and EVENT HANDLER **************** */
static esp_err_t bsp_mouse_event_handler(uint8_t *data, uint16_t length, esp_hid_usage_t usage)
{
ESP_RETURN_ON_FALSE(ESP_HID_USAGE_MOUSE == usage, ESP_ERR_INVALID_ARG,
TAG, "Invalid usage : %s (%d)", esp_hid_usage_str(usage), usage);
ESP_RETURN_ON_FALSE(length >= 7, ESP_ERR_INVALID_SIZE,
TAG, "invalid data length : %u", length);
int dx = * ((int16_t *) &data[1]);
int dy = * ((int16_t *) &data[3]);
int dz = * ((int8_t *) &data[5]);
mouse_state.x += dx;
if (mouse_state.x < 0) mouse_state.x = 0;
if (mouse_state.x >= LCD_WIDTH) mouse_state.x = LCD_WIDTH - 1;
mouse_state.y += dy;
if (mouse_state.y >= LCD_HEIGHT) mouse_state.y = LCD_HEIGHT - 1;
if (mouse_state.y < 0) mouse_state.y = 0;
mouse_state.press = 0 != data[0];
ESP_LOGD(TAG, "Button : 0x%02X. Pos info : [%3d, %3d]{%3d, %3d}. Scroll : %d", data[0], mouse_state.x, mouse_state.y, dx, dy, dz);
return ESP_OK;
}
static void hid_callback(void *handler_args, esp_event_base_t base, int32_t id, void *event_data)
{
esp_hidh_event_t event = (esp_hidh_event_t) id;
esp_hidh_event_data_t *param = (esp_hidh_event_data_t *) event_data;
switch (event) {
case ESP_HIDH_OPEN_EVENT: {
const uint8_t *bda = esp_hidh_dev_bda_get(param->open.dev);
ESP_LOGI(TAG, ESP_BD_ADDR_STR " OPEN: %s", ESP_BD_ADDR_HEX(bda), esp_hidh_dev_name_get(param->open.dev));
esp_hidh_dev_dump(param->open.dev, stdout);
break;
}
case ESP_HIDH_BATTERY_EVENT: {
const uint8_t *bda = esp_hidh_dev_bda_get(param->battery.dev);
ESP_LOGI(TAG, ESP_BD_ADDR_STR " BATTERY: %d%%", ESP_BD_ADDR_HEX(bda), param->battery.level);
break;
}
case ESP_HIDH_INPUT_EVENT: {
// const uint8_t *bda = esp_hidh_dev_bda_get(param->input.dev);
bsp_mouse_event_handler(param->input.data, param->input.length, param->input.usage);
break;
}
case ESP_HIDH_FEATURE_EVENT: {
const uint8_t *bda = esp_hidh_dev_bda_get(param->feature.dev);
ESP_LOGI(TAG, ESP_BD_ADDR_STR " FEATURE: %8s, MAP: %2u, ID: %3u, Len: %d", ESP_BD_ADDR_HEX(bda), esp_hid_usage_str(param->feature.usage), param->feature.map_index, param->feature.report_id, param->feature.length);
ESP_LOG_BUFFER_HEX(TAG, param->feature.data, param->feature.length);
break;
}
case ESP_HIDH_CLOSE_EVENT: {
const uint8_t *bda = esp_hidh_dev_bda_get(param->close.dev);
ESP_LOGI(TAG, ESP_BD_ADDR_STR " CLOSE: '%s' %s", ESP_BD_ADDR_HEX(bda), esp_hidh_dev_name_get(param->close.dev), esp_hid_disconnect_reason_str(esp_hidh_dev_transport_get(param->close.dev), param->close.reason));
esp_hidh_dev_free(param->close.dev);
break;
}
default:
ESP_LOGI(TAG, "EVENT: %d", event);
break;
}
}
static void bsp_mouse_default_task(void *pvParam)
{
(void) pvParam;
size_t results_len = 0;
const uint32_t scan_duration_seconds = 5;
esp_hid_scan_result_t *results = NULL;
ESP_LOGI(TAG, "Scaning for HID devices...");
while (true) {
esp_hid_scan(scan_duration_seconds, &results_len, &results);
ESP_LOGI(TAG, "Scan complete. %u devices found", results_len);
if (results_len > 0) {
esp_hid_scan_result_t *device = results;
esp_hidh_dev_t *opened_dev = NULL;
/* Print device info and open avaliable device(s) */
while (device) {
if (device->transport == ESP_HID_TRANSPORT_BLE) {
printf("\n");
printf("Addr : " ESP_BD_ADDR_STR ", ", ESP_BD_ADDR_HEX(device->bda));
printf("Name : %s, ", device->name ? device->name : "");
printf("Usage: %s, ", esp_hid_usage_str(device->usage));
printf("RSSI : %d, ", device->rssi);
printf("APPEARANCE: 0x%04x, ", device->ble.appearance);
printf("ADDR_TYPE: '%s'\n", ble_addr_type_str(device->ble.addr_type));
opened_dev = esp_hidh_dev_open(device->bda, device->transport, device->ble.addr_type);
}
device = device->next;
if (NULL != opened_dev) {
goto task_over;
}
}
printf("\n");
/* Free scan results */
esp_hid_scan_results_free(results);
}
}
task_over:
/* Task never returns */
vTaskDelete(NULL);
}
#else
#include "esp_err.h"
#include "esp_log.h"
#include "indev_hid.h"
static const char *TAG = "hid_indev";
esp_err_t indev_hid_init(indev_hid_conf_t *conf)
{
(void) conf;
ESP_LOGE(TAG, "Please turn on \"Enable BLE 4.2 features\" option in menuconfig");
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t indev_hid_init_default(void)
{
ESP_LOGE(TAG, "Please turn on \"Enable BLE 4.2 features\" option in menuconfig");
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t indev_hid_get_value(indev_hid_state_t *state)
{
ESP_LOGE(TAG, "Please turn on \"Enable BLE 4.2 features\" option in menuconfig");
return ESP_ERR_NOT_SUPPORTED;
}
#endif
+58
View File
@@ -0,0 +1,58 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
bool init_ble_service;
} indev_hid_conf_t;
typedef struct {
int32_t x;
int32_t y;
uint32_t btn_val;
bool press;
} indev_hid_state_t;
/**
* @brief Initialize HID indev
*
* @param conf Config of indev
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t indev_hid_init(indev_hid_conf_t *conf);
/**
* @brief Call default HID indev init code
*
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t indev_hid_init_default(void);
/**
* @brief Get value of HID input device
*
* @param state Pointer to bsp_hid_indev_state_t
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t indev_hid_get_value(indev_hid_state_t *state);
#ifdef __cplusplus
}
#endif
@@ -1,34 +1,19 @@
/**
* @file bsp_tp.c
* @brief
* @version 0.1
* @date 2021-07-05
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Apache-2.0
*/
#include "bsp_i2c.h"
#include "bsp_board.h"
#include "bsp_tp.h"
#include "indev_tp.h"
#include "esp_log.h"
#include "esp_err.h"
#include "ft5x06.h"
#include "tt21100.h"
static const char *TAG = "bsp_tp";
static const char *TAG = "indev_tp";
typedef enum {
TP_VENDOR_NONE = -1,
TP_VENDOR_TT = 0,
@@ -49,13 +34,13 @@ static tp_dev_t tp_dev_list[] = {
static tp_vendor_t tp_vendor = TP_VENDOR_NONE;
static esp_err_t bsp_tp_prob(tp_vendor_t *p_tp_vendor)
static esp_err_t tp_prob(tp_vendor_t *p_tp_vendor)
{
for (size_t i = 0; i < sizeof(tp_dev_list) / sizeof(tp_dev_list[0]); i++) {
if (ESP_OK == bsp_i2c_probe_addr(tp_dev_list[i].dev_addr)) {
*p_tp_vendor = (tp_vendor_t) i;
ESP_LOGI(TAG, "Detected touch panel at 0x%02X. Vendor : %s",
tp_dev_list[i].dev_addr, tp_dev_list[i].dev_name);
tp_dev_list[i].dev_addr, tp_dev_list[i].dev_name);
return ESP_OK;
}
}
@@ -65,11 +50,11 @@ static esp_err_t bsp_tp_prob(tp_vendor_t *p_tp_vendor)
return ESP_ERR_NOT_FOUND;
}
esp_err_t bsp_tp_init(void)
esp_err_t indev_tp_init(void)
{
esp_err_t ret_val = ESP_OK;
ret_val |= bsp_tp_prob(&tp_vendor);
ret_val |= tp_prob(&tp_vendor);
switch (tp_vendor) {
case TP_VENDOR_TT:
@@ -85,7 +70,7 @@ esp_err_t bsp_tp_init(void)
return ret_val;
}
esp_err_t bsp_tp_read(uint8_t *tp_num, uint16_t *x, uint16_t *y, uint8_t *btn_val)
esp_err_t indev_tp_read(uint8_t *tp_num, uint16_t *x, uint16_t *y, uint8_t *btn_val)
{
esp_err_t ret_val = ESP_OK;
uint16_t btn_signal = 0;
@@ -107,19 +92,20 @@ esp_err_t bsp_tp_read(uint8_t *tp_num, uint16_t *x, uint16_t *y, uint8_t *btn_va
break;
}
#if TOUCH_PANEL_SWAP_XY
uint16_t swap = *x;
*x = *y;
*y = swap;
#endif
const board_res_desc_t *brd = bsp_board_get_description();
if (brd->TOUCH_PANEL_SWAP_XY) {
uint16_t swap = *x;
*x = *y;
*y = swap;
}
#if TOUCH_PANEL_INVERSE_X
*x = LCD_WIDTH - ( *x + 1);
#endif
if (brd->TOUCH_PANEL_INVERSE_X) {
*x = brd->LCD_WIDTH - ( *x + 1);
}
#if TOUCH_PANEL_INVERSE_Y
*y = LCD_HEIGHT - (*y + 1);
#endif
if (brd->TOUCH_PANEL_INVERSE_Y) {
*y = brd->LCD_HEIGHT - (*y + 1);
}
ESP_LOGD(TAG, "[%3u, %3u]", *x, *y);
+41
View File
@@ -0,0 +1,41 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Init touch panel
*
* @return
* - ESP_OK: Success
* - ESP_ERR_NOT_SUPPORTED: Unsupported touch panel
* - Others: Fail
*/
esp_err_t indev_tp_init(void);
/**
* @brief Read data from touch panel
*
* @param tp_num Touch point number
* @param x X coordinate
* @param y Y coordinate
* @param btn_val Button mask value
* @return
* - ESP_OK: Success
* - Others: Fail
*/
esp_err_t indev_tp_read(uint8_t *tp_num, uint16_t *x, uint16_t *y, uint8_t *btn_val);
#ifdef __cplusplus
}
#endif
+123 -84
View File
@@ -1,9 +1,9 @@
/**
* @file lv_port.c
* @brief
* @brief
* @version 0.1
* @date 2021-06-28
*
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,26 +19,31 @@
* limitations under the License.
*/
#include "bsp_board.h"
#include "bsp_lcd.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "bsp_board.h"
#include "bsp_lcd.h"
#include "indev/indev.h"
#include "lv_port.h"
#include "lvgl.h"
#include "sdkconfig.h"
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
static lv_disp_drv_t disp_drv;
static const char *TAG = "lv_port";
static bool lv_port_use_fixed_buffer = false;
static lv_indev_t *indev_touchpad;
static lv_indev_t *indev_button;
static uint8_t g_home_btn_val;
/**
* @brief Task to generate ticks for LVGL.
*
* @param pvParam Not used.
*
* @param pvParam Not used.
*/
static void lv_tick_inc_cb(void *data)
{
@@ -49,7 +54,7 @@ static void lv_tick_inc_cb(void *data)
/**
* @brief Tell LVGL that LCD flush done.
*
*
* @return true Call `portYIELD_FROM_ISR()` after esp-lcd ISR return.
* @return false Do nothing after esp-lcd ISR return.v
*/
@@ -62,70 +67,91 @@ static bool lv_port_flush_ready(void)
return false;
}
static void button_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
static void button_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
static uint8_t prev_btn_id = 0;
uint8_t tp_num = 0;
uint16_t x = 0, y = 0, btn_val = 0;
// static uint8_t prev_btn_id = 0;
static uint32_t last_key = 0;
/* Read touch point(s) via touch IC */
if (ESP_OK != bsp_tp_read(&tp_num, &x, &y, &btn_val)) {
// ESP_LOGE(TAG, "Failed read touch panel value");
indev_data_t indev_data;
if (ESP_OK != indev_get_major_value(&indev_data)) {
ESP_LOGE(TAG, "Failed read input device value");
return;
}
/*Get the pressed button's ID*/
if (btn_val) {
data->btn_id = btn_val;
if (indev_data.btn_val & 0x02) {
last_key = LV_KEY_ENTER;
data->state = LV_INDEV_STATE_PRESSED;
ESP_LOGD(TAG, "ok");
} else if (indev_data.btn_val & 0x04) {
data->state = LV_INDEV_STATE_PRESSED;
last_key = LV_KEY_PREV;
ESP_LOGD(TAG, "prev");
} else if (indev_data.btn_val & 0x01) {
data->state = LV_INDEV_STATE_PRESSED;
last_key = LV_KEY_NEXT;
ESP_LOGD(TAG, "next");
} else {
data->btn_id = 0;
data->state = LV_INDEV_STATE_RELEASED;
}
if (prev_btn_id != data->btn_id) {
lv_event_send(lv_scr_act(), LV_EVENT_HIT_TEST, (void *) btn_val);
}
prev_btn_id = btn_val;
data->key = last_key;
}
/**
* @brief Read touchpad data.
*
* @param indev_drv
* @param data
* @return IRAM_ATTR
* @brief Read touchpad data.
*
* @param indev_drv
* @param data
* @return IRAM_ATTR
*/
static IRAM_ATTR void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
static IRAM_ATTR void touchpad_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
uint8_t tp_num = 0;
uint16_t x = 0, y = 0, btn_val = 0;
/* Read touch point(s) via touch IC */
if (ESP_OK != bsp_tp_read(&tp_num, &x, &y, &btn_val)) {
// ESP_LOGE(TAG, "Failed read touch panel value");
indev_data_t indev_data;
if (ESP_OK != indev_get_major_value(&indev_data)) {
return;
}
ESP_LOGD(TAG, "Touch (%u) : [%3u, %3u]", tp_num, x, y);
ESP_LOGD(TAG, "Touch (%u) : [%3u, %3u] - 0x%02X", indev_data.pressed, indev_data.x, indev_data.y, indev_data.btn_val);
/* FT series touch IC might return 0xff before first touch. */
if ((0 == tp_num) || (5 < tp_num)) {
data->state = LV_INDEV_STATE_REL;
} else {
data->point.x = x;
data->point.y = y;
data->point.x = indev_data.x;
data->point.y = indev_data.y;
g_home_btn_val = indev_data.btn_val;
if (indev_data.pressed) {
data->state = LV_INDEV_STATE_PR;
} else {
data->state = LV_INDEV_STATE_REL;
}
}
static void home_button_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
static uint8_t last_btn = 0;
if (g_home_btn_val & 0x01) {
data->state = LV_INDEV_STATE_PRESSED;
last_btn = 0;
} else {
data->state = LV_INDEV_STATE_RELEASED;
}
/*Save the last pressed button's ID*/
data->btn_id = last_btn;
}
/**
* @brief LCD flush function callback for LVGL.
*
* @param disp_drv
* @param area
* @param color_p
*
* @param disp_drv
* @param area
* @param color_p
*/
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
static void disp_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
{
(void) disp_drv;
@@ -135,35 +161,36 @@ static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_colo
/**
* @brief Initialize display driver for LVGL.
*
*
*/
static void lv_port_disp_init(void)
{
static lv_disp_draw_buf_t draw_buf_dsc;
size_t disp_buf_height = 40;
size_t disp_buf_height = 20;
const board_res_desc_t *brd = bsp_board_get_description();
/* Option 1 : Allocate memories from heap */
// lv_color_t *p_disp_buf = NULL;
// uint32_t buf_alloc_caps = MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT;
// p_disp_buf = heap_caps_malloc(LCD_WIDTH * disp_buf_height * sizeof(lv_color_t), buf_alloc_caps);
// ESP_LOGD(TAG, "Try allocate %zu * %zu display buffer", LCD_WIDTH, disp_buf_height);
// if (NULL == p_disp_buf) {
// ESP_LOGE(TAG, "No memory for LVGL display buffer");
// esp_system_abort("Memory allocation failed");
// }
uint32_t buf_alloc_caps = MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT;
lv_color_t *p_disp_buf = heap_caps_malloc(brd->LCD_WIDTH * disp_buf_height * sizeof(lv_color_t) * 2, buf_alloc_caps);
lv_color_t *p_disp_buf1 = p_disp_buf;
lv_color_t *p_disp_buf2 = p_disp_buf + brd->LCD_WIDTH * disp_buf_height;
ESP_LOGI(TAG, "Try allocate two %u * %u display buffer, size:%u Byte", brd->LCD_WIDTH, disp_buf_height, brd->LCD_WIDTH * disp_buf_height * sizeof(lv_color_t) * 2);
if (NULL == p_disp_buf) {
ESP_LOGE(TAG, "No memory for LVGL display buffer");
esp_system_abort("Memory allocation failed");
}
/* Option 2 : Using static space for display buffer */
static lv_color_t p_disp_buf[LCD_WIDTH * 40];
/* Initialize display buffer */
lv_disp_draw_buf_init(&draw_buf_dsc, p_disp_buf, NULL, LCD_WIDTH * disp_buf_height);
lv_disp_draw_buf_init(&draw_buf_dsc, p_disp_buf1, p_disp_buf2, brd->LCD_WIDTH * disp_buf_height);
/* Register the display in LVGL */
lv_disp_drv_init(&disp_drv);
/*Set the resolution of the display*/
disp_drv.hor_res = LCD_WIDTH;
disp_drv.ver_res = LCD_HEIGHT;
disp_drv.hor_res = brd->LCD_WIDTH;
disp_drv.ver_res = brd->LCD_HEIGHT;
/* Used to copy the buffer's content to the display */
disp_drv.flush_cb = disp_flush;
@@ -175,7 +202,7 @@ static void lv_port_disp_init(void)
* @brief Fill a memory array with a color if you have GPU.
* Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL.
* But if you have a different GPU you can use with this callback.
*
*
*/
// disp_drv.gpu_fill_cb = gpu_fill;
@@ -188,8 +215,8 @@ static void lv_port_disp_init(void)
/**
* @brief Initialize input device for LVGL.
*
* @return esp_err_t
*
* @return esp_err_t
*/
static esp_err_t lv_port_indev_init(void)
{
@@ -206,43 +233,53 @@ static esp_err_t lv_port_indev_init(void)
*/
static lv_indev_drv_t indev_drv_tp;
static lv_indev_drv_t indev_drv_btn;
lv_indev_t *indev_touchpad;
lv_indev_t *indev_button;
/* Initialize your touchpad if you have */
const board_res_desc_t *brd = bsp_board_get_description();
if (brd->BSP_INDEV_IS_TP) {
ESP_LOGI(TAG, "Add TP input device to LVGL");
lv_indev_drv_init(&indev_drv_tp);
indev_drv_tp.type = LV_INDEV_TYPE_POINTER;
indev_drv_tp.read_cb = touchpad_read;
indev_touchpad = lv_indev_drv_register(&indev_drv_tp);
if (brd->TOUCH_WITH_HOME_BUTTON) {
ESP_LOGI(TAG, "Add HOME button input to LVGL");
lv_indev_drv_init(&indev_drv_btn);
indev_drv_btn.type = LV_INDEV_TYPE_BUTTON;
indev_drv_btn.read_cb = home_button_read;
indev_button = lv_indev_drv_register(&indev_drv_btn);
}
/* Register a touchpad input device */
lv_indev_drv_init(&indev_drv_tp);
indev_drv_tp.type = LV_INDEV_TYPE_POINTER;
indev_drv_tp.read_cb = touchpad_read;
indev_touchpad = lv_indev_drv_register(&indev_drv_tp);
} else {
ESP_LOGI(TAG, "Add KEYPAD input device to LVGL");
lv_indev_drv_init(&indev_drv_btn);
indev_drv_btn.type = LV_INDEV_TYPE_KEYPAD;
indev_drv_btn.read_cb = button_read;
indev_button = lv_indev_drv_register(&indev_drv_btn);
}
lv_indev_drv_init(&indev_drv_btn);
indev_drv_btn.type = LV_INDEV_TYPE_BUTTON;
indev_drv_btn.read_cb = button_read;
indev_button = lv_indev_drv_register(&indev_drv_btn);
/* Uncomment code below to display a mouse cursor on screen */
// LV_IMG_DECLARE(mouse_cursor_icon)
// lv_obj_t * cursor_obj = lv_img_create(lv_scr_act()); /*Create an image object for the cursor */
// lv_img_set_src(cursor_obj, &mouse_cursor_icon); /*Set the image source*/
// lv_indev_set_cursor(indev_touchpad, cursor_obj); /*Connect the image object to the driver*/
#if CONFIG_LV_PORT_SHOW_MOUSE_CURSOR
LV_IMG_DECLARE(mouse_cursor_icon)
lv_obj_t *cursor_obj = lv_img_create(lv_scr_act()); /*Create an image object for the cursor */
lv_img_set_src(cursor_obj, &mouse_cursor_icon); /*Set the image source*/
lv_indev_set_cursor(indev_touchpad, cursor_obj); /*Connect the image object to the driver*/
#endif
}
/**
* @brief Create tick task for LVGL.
*
* @return esp_err_t
*
* @return esp_err_t
*/
static esp_err_t lv_port_tick_init(void)
{
static const uint32_t tick_inc_period_ms = 5;
const esp_timer_create_args_t periodic_timer_args = {
.callback = lv_tick_inc_cb,
.name = "", /* name is optional, but may help identify the timer when debugging */
.arg = &tick_inc_period_ms,
.dispatch_method = ESP_TIMER_TASK,
.skip_unhandled_events = true,
.callback = lv_tick_inc_cb,
.name = "", /* name is optional, but may help identify the timer when debugging */
.arg = &tick_inc_period_ms,
.dispatch_method = ESP_TIMER_TASK,
.skip_unhandled_events = true,
};
esp_timer_handle_t periodic_timer;
@@ -260,9 +297,11 @@ esp_err_t lv_port_init(void)
lv_init();
/* Register display for LVGL */
ESP_ERROR_CHECK(bsp_lcd_init());
lv_port_disp_init();
/* Register input device for LVGL*/
ESP_ERROR_CHECK(indev_init_default());
lv_port_indev_init();
/* Initialize LVGL's tick source */
+40 -22
View File
@@ -7,9 +7,9 @@ The guide is suitable for the development boards that flashed the latest firmwar
The BOX series development boards based on ESP32-S3 SoC provides a platform for developing the control of home appliances using Voice Assistance + display with buttons controller, sensor, infrared controller, and intelligent Wi-Fi gateway. The BOX series development boards comes with pre-built firmware that allows you to experience voice wake-up and offline speech commands recognition in Chinese and English languages.
The ESP-BOX SDK includes a reconfigurable AI voice interaction that allows you to customize commands to control your smart home appliances. The content of this material is to give you a brief concept of how the latest firmware works, a basic idea for you to know where to begin. Once you go through the guide below, you may start developing the application yourself. So, lets begin the journey!
**The BOX Kit contains:**
| ESP32-S3-BOX | ESP32-S3-BOX-Lite |
| :-----: | :---------------------: |
| A main unit that can work on its own | A main unit that can work on its own|
@@ -17,9 +17,9 @@ The ESP-BOX SDK includes a reconfigurable AI voice interaction that allows you t
| Dock, an accessory that serves as a stand for the device. | N/A|
**Required Hardware:**
What do you need: An USB-C Cable (not included in the kit).
## Connect the RGB LED Module to your Device
@@ -37,11 +37,11 @@ Refer to the pin definition below, insert the RGB LED Module to the BOX. The RGB
</div>
2. Once power on, the interactive Espressif logo will display on the screen.
<div align="center">
<img src="./_static/_get_started_static/boot_animation.png" width="800px">
</div>
## Let's Play Around!
1. Initially, the two Guide Pages introduces the functions of buttons of your BOX series development boards. Press Next to enter next page after reading them.
@@ -50,7 +50,7 @@ Refer to the pin definition below, insert the RGB LED Module to the BOX. The RGB
| :-----: | :---------------------: |
| <img src="./_static/_get_started_static/0.png" width="300px"/> | <img src="./_static/_get_started_static/1.png" width="300px"/> |
| <img src="./_static/_get_started_static/2.png" width="280px"/> | <img src="./_static/_get_started_static/2.png" width="280px"/> |
2. Next, the Steps for Voice Assistant window gives you a hint of how to use the AI voice control. Press “OK Lets Go” to enter the Menu screen.
<div align="center">
<img src="./_static/_get_started_static/3_EN.png">
@@ -58,7 +58,7 @@ Refer to the pin definition below, insert the RGB LED Module to the BOX. The RGB
<div align="center">
<img src="./_static/_get_started_static/3.1_EN.png">
</div>
3. The Menu screen has five functions, they are Device Control, Media Player, Network, Help and About Us. You can navigate to different sections by switching the pages. For example, enter the Device Control user interface, tap the Light icon to turn on or turn off the LED light. Moreover, go back to the Menu page and go forward to the Media Player section, you can operate buttons to control the music playback or adjust the volume.
<div align="center">
@@ -75,7 +75,7 @@ Refer to the pin definition below, insert the RGB LED Module to the BOX. The RGB
</div>
**The following features are only supported by ESP32-S3-BOX**
4. Press the Mute button on the top of the ESP32-S3-BOX to disable the voice wake-up and speech recognition function. Press again to restore the function.
<div align="center">
<img src="_static/_get_started_static/hardware_mute_button.jpg" width="350px">
@@ -84,6 +84,7 @@ Refer to the pin definition below, insert the RGB LED Module to the BOX. The RGB
5. You can press the “Red Circle” on the device and return to the last page.
<div align="center">
<img src="./_static/_get_started_static/hardware_home.png" width="350px">
</div>
## Offline Voice Assistant with your Device
@@ -93,12 +94,12 @@ Refer to the pin definition below, insert the RGB LED Module to the BOX. The RGB
<img src="./_static/_get_started_static/17.png">
</div>
2. Utter a command phrase within 6 seconds after the beep, for example “turn on the light”. The command phrase will display on the screen and the RGB light of the LED Module will turn on. Around 1 second the voice user interface exits.
2. Utter a command phrase within 6 seconds after the beep, for example “turn on the light”. The command phrase will display on the screen and the RGB light of the LED Module will turn on, and there will be a voice feedback "OK". Around 6 seconds the voice user interface exits if no more commands.
<div align="center">
<img src="./_static/_get_started_static/21.png">
</div>
3. You can use voice commands to enjoy music. Please wake up the device first, then say the command phrase "Sing a song". The music player opens and start playing built-in music. You can also use voice commands to switch to the next song or pause playing (There are two build-in songs).
>**Tips:**
@@ -114,6 +115,23 @@ Refer to the pin definition below, insert the RGB LED Module to the BOX. The RGB
"**Turn on the light**", "**Switch off the light**", "**Turn Red**", "**Turn Green**", "**Turn Blue**", "**Sing a song**", "**Next Song**", "**Pause Playing**".
## Continuous Recognition
More interestingly, the device supports continuous recognition of multiple command words after wake-up. Continuous recognition means that the user can talk to the device continuously once it is woken up. The continuous recognition makes the voice interaction more natural and smooth, and brings a more humanized interactive experience.
**How to use**
- Say "Hi, E. S. P" to wake up the device, a prompt beep will be played.
- Say a command phrase after the prompt beep. If the device recognizes the command word, it will play the corresponding prompt tone "OK", and then it can continue to recognize.
- If nothing is recognized, the device will continue to wait. If there is no new command word within 6S, the device will automatically exit and you need to wake it up again.
**Attention**
- If it fails to recognize normally for many times, please wait for timeout and wake up the device again to enter the recognition mode.
- After the wake-up word is spoken, the command word shall be sent out at the same position. The device does not support recognition during movement.
- The length of the best English offline command word we recommend is 3-5 English characters.
- The current version does not support continuous recognition when the speaker plays a prompt tone.
## Voice Command Customization
The BOX series development boards are equipped with the Espressifs proprietary AI Speech Recognition system which allows you to customize command phrases through our ESP-BOX APP. We will take the LED module as an example to show how to customize the voice commands.
@@ -137,7 +155,7 @@ The BOX series development boards are equipped with the Espressifs proprietar
<img src="_static/_get_started_static/Picture1.png">
</div>
1.3. If you first download the APP, please click "User", "Register" to register a new account.
1.4. Sign in with your ESP-BOX account and turn on the Bluetooth of your phone. Then tap + on the bottom of the interface, find the code scanning icon and scan the network provisioning QR code on your device.
<div align="center">
@@ -159,16 +177,16 @@ The BOX series development boards are equipped with the Espressifs proprietar
<div align="center">
<img src="_static/_get_started_static/7.png">
</div>
>**Tips:**
>**Tips:**
>
>* Make sure the device is connected to 2.4GHz Wi-Fi channel not 5GHz, if the Wi-Fi password is incorrect, it will lead to Wi-Fi Authentication failed as the figure below shows.
>* Please stay on the device provisioning page during network provision.
>* Long press the Boot button for 5 seconds to clean the network information and restore to factory settings.
* Long press the Boot button for 5 seconds to clean the network information and restore to factory settings.
<div align="center">
<img src="_static/_get_started_static/7.jpeg"width="300" />
</div>
**2. Customize Voice Command**
2.1. Tap the ESP-BOX device and enter to the below interface. You can simply turn on or turn off the light by toggling the button on the user interface, as the figure below shows. (We left the Fan and Switch parts for you to configure and develop by yourself.)
@@ -187,13 +205,13 @@ The BOX series development boards are equipped with the Espressifs proprietar
<div align="center">
<img src="_static/_get_started_static/11.jpeg"width="300" />
</div>
2.3 The Control page allows you to adjust the color and brightness of the light, as well as the saturation of the color.
<div align="center">
<img src="_static/_get_started_static/12.jpeg"width="300" />
</div>
2.4 The Configure page allows you to define the preferred command phrase to control the on/off status and color of the light. For example, you can customize “Good morning” for action ON (as marked with “1” in the figure below). Click Save to return to the previous interface (as marked with “2” in the figure below). Then click Save again (as marked with “3” in the figure below).
<div align="center">
@@ -202,15 +220,15 @@ The BOX series development boards are equipped with the Espressifs proprietar
<div align="center">
<img src="_static/_get_started_static/13.1 EN.jpeg"width="300" />
</div>
2.5 Now, you can try out your new command! First, say “Hi E. S. P.” to wake up your device. Then say “Good morning” to turn on your light within 6 seconds. The new command phrase will display on the screen and the LED module will turn on.
<div align="center">
<img src="_static/_get_started_static/15.png">
</div>
>**How to Add Appropriate Command Phrases: Now AI model supports users to define command phrases. In order to obtain the best recognition experience, you need to pay attention to the following matters when defining command phrase:**
>**How to Add Appropriate Command Phrases: Now AI model supports users to define command phrases. In order to obtain the best recognition experience, you need to pay attention to the following matters when defining command phrase in the APP:**
>
>* Length of command word: The number of words in the command phrase must be greater than or equal to 2 and less than or equal to 8. When defining a series of command phrases, it is best to keep the length of different command phrases similar.
>* Avoid prefixes: Multiple command phrase should not be prefixed with each other. Short words will be not recognized, such as “Turn on” and “Turn on the light", “Turn on" will be not recognized.
+83 -21
View File
@@ -6,7 +6,6 @@
基于 ESP32-S3 的 BOX 系列开发板为用户提供了一个基于语音助手 + 屏幕控制、传感器、红外控制器和智能 Wi-Fi 网关等功能,开发和控制智能家居设备的平台。BOX 系列开发板出厂支持语音唤醒和离线中英文命令词识别。 其 SDK 包含可重构的 AI 语音交互功能,支持用户通过自定义命令词控制智能设备。本文的内容仅为您简要介绍最新固件能实现的参考功能,让您了解如何开始使用开发板。一旦您完成阅读下面的指南,您可以尝试自己开发应用。让我们开始旅程吧!
**BOX 套件包含:**
| ESP32-S3-BOX | ESP32-S3-BOX-Lite |
@@ -15,9 +14,9 @@
| 供测试的 RGB LED 模块和杜邦线 | 供测试的 RGB LED 模块和杜邦线 |
| Dock 配件, 辅助主机站在桌上 | N/A|
**所需硬件:**
您需要准备一根 USB-C 数据线 (不包含在套件内)。
## 插入 RGB LED 模块
@@ -29,12 +28,13 @@
## 给设备供电
1. 使用一根 USB-C 数据线(不包含在套件中)给 BOX 设备供电。
<div align="center">
<img src="./_static/_get_started_static/usb_power.png" width="800px">
</div>
2. 设备启动后,屏幕上将显示 Espressif logo 的开机动画。
<div align="center">
<img src="./_static/_get_started_static/boot_animation.png" width="800px">
</div>
@@ -49,13 +49,16 @@
| <img src="./_static/_get_started_static/2.png" width="280px"/> | <img src="./_static/_get_started_static/2.png" width="280px"/> |
2. 接下来是“语音助手使用说明”引导页 ,请仔细阅读,它会提示您如何使用 AI 语音功能。完成阅读后点击 “OK Let's Go” 进入菜单页。
<div align="center">
<img src="./_static/_get_started_static/3_CN.png" >
</div>
<div align="center">
<img src="./_static/_get_started_static/3.1_CN.png">
</div>
3. 菜单页有五大功能,分别是“设备控制”、“音乐播放器”、“网络”、“帮助”以及“关于”,左右切换可进入不同的功能。比如,进入“设备控制”用户界面,选中 “Light” 图标,点按确认可打开或关闭 LED 灯。然后回到菜单页,找到“音乐播放器”界面并进入,进行歌曲的播放或调节音量。
<div align="center">
<img src="./_static/_get_started_static/4.png">
</div>
@@ -72,27 +75,30 @@
**以下功能仅 ESP32-S3-BOX 支持**
4. 按下 ESP32-S3-BOX 顶部的静音按钮,按下后设备语音唤醒和识别功能被禁用,再次按下恢复语音功能。
<div align="center">
<img src="_static/_get_started_static/hardware_mute_button.jpg" width="350px">
</div>
5. 也可以轻触触摸屏下方的 “小红圈” 返回上一页。
<div align="center">
<img src="./_static/_get_started_static/hardware_home.png" width="350px">
</div>
## 体验离线语音识别
1. 在任意界面,您可以使用唤醒词去唤醒设备,中文唤醒词是“Hi 乐鑫”,英文唤醒词是 “Hi E. S. P.”(用字母发音)。设备唤醒成功后,唤醒词将显示在如下屏幕上并伴有提示音,如果唤醒词未出现,请再次尝试。如下展示的动画界面提示您的设备正在倾听。
1. 在任意界面,您可以使用唤醒词去唤醒设备,中文唤醒词是“Hi 乐鑫”,英文唤醒词是 “Hi E. S. P.”(用字母发音)。设备唤醒成功后,唤醒词将显示在如下屏幕上并伴有提示音 “我在”,如果唤醒词未出现,请再次尝试。如下展示的动画界面提示您的设备正在倾听。
<div align="center">
<img src="./_static/_get_started_static/16.png">
</div>
2. 请在提示音响起后的 6 秒左右时间内对设备说命令词,比如“打开电灯”,同时命令词将显示在屏幕上并且 LED 模块打开。约 1 秒后语音控制界面退出。
2. 请在提示音响起后的 6 秒左右时间内对设备说命令词,比如“打开电灯”,命令词将显示在屏幕上并且 LED 模块打开,同时会有语音反馈 “好的”,随后语音控制界面退出。
<div align="center">
<img src="./_static/_get_started_static/20.png">
</div>
3. 您也可以使用语音命令欣赏音乐,请先唤醒设备然后对设备说命令词“播放音乐”,设备会打开音乐播放器并开始播放内置音乐,您也可以用语音命令词切换下一首歌或者暂停播放。(最新固件默认自带两首歌)
>**注意:**
@@ -102,9 +108,62 @@
<div align="center">
<img src="_static/_get_started_static/19.png">
</div>
4. 默认命令词为:"**打开电灯**", "**关闭电灯**", "**调成红色**", "**调成绿色**", "**调成蓝色**", "**播放音乐**", "**切歌**", "**暂停播放**"
## 连续语音识别
更有意思的是,设备支持唤醒后连续识别多个命令词。连续识别,即用户可以在唤醒一次设备后,与其连续对话,连续对话让语音交互更自然流畅,带来更人性化的对话体验。
**使用方式**
- 使用“Hi,乐鑫”唤醒设备,唤醒后播放提示音 `我在`
- 唤醒后进行识别,设备识别到命令词,则会播放对应的提示音 `好的`,然后可以继续识别
- 未识别到则继续等待,6s 内未有新指令则自动退出,需要再次唤醒
**注意**
- 如多次未正常识别请再次唤醒进入识别
- 发出唤醒词后应在同样位置发出命令词,不支持在移动中识别
- 我们推荐的最佳中文离线命令词长度为 3-5 个汉字
- 目前版本不支持在喇叭播放提示音时继续识别
- 当唤醒后没有识别到用户的语音指令时,会等待 6s ,然后自动退出
**额外支持的命令词**
| command ID | 命令词 | command ID | 命令词 | command ID | 命令词 |
| :--------: | :----------: | :--------: | :----------: | :--------: | :------------: |
| 0 | 打开空调 | 24 | 二十六度 | 48 | 音量调到最小 |
| 1 | 关闭空调 | 25 | 二十七度 | 49 | 打开电灯 |
| 2 | 舒适模式 | 26 | 二十八度 | 50 | 关闭电灯 |
| 3 | 制冷模式 | 27 | 二十九度 | 51 | 打开卧室灯 |
| 4 | 制热模式 | 28 | 三十度 | 52 | 关闭卧室灯 |
| 5 | 加热模式 | 29 | 增大风速 | 53 | 打开客厅灯 |
| 6 | 除湿模式 | 30 | 减小风速 | 54 | 关闭客厅灯 |
| 7 | 送风模式 | 31 | 高速风 | 55 | 打开音箱 |
| 8 | 升高温度 | 32 | 中速风 | 56 | 关闭音箱 |
| 9 | 降低温度 | 33 | 低速风 | 57 | 拉开窗帘 |
| 10 | 温度调到最高 | 34 | 自动风 | 58 | 关闭窗帘 |
| 11 | 温度调到最低 | 35 | 打开左右摆风 | 59 | 打开风扇 |
| 12 | 太热了 | 36 | 打开上下摆风 | 60 | 关闭风扇 |
| 13 | 太冷了 | 37 | 关闭左右摆风 | 61 | 打开饮水机插座 |
| 14 | 十六度 | 38 | 关闭上下摆风 | 62 | 关闭饮水机插座 |
| 15 | 十七度 | 39 | 打开辅热 | 63 | 打开投影仪 |
| 16 | 十八度 | 40 | 关闭辅热 | 64 | 关闭投影仪 |
| 17 | 十九度 | 41 | 打开自清洁 | 65 | 灯光调暗 |
| 18 | 二十度 | 42 | 关闭自清洁 | 66 | 灯光调亮 |
| 19 | 二十一度 | 43 | 打开静音 | | |
| 20 | 二十二度 | 44 | 关闭静音 | | |
| 21 | 二十三度 | 45 | 音量大点 | | |
| 22 | 二十四度 | 46 | 音量小点 | | |
| 23 | 二十五度 | 47 | 音量调到最大 | | |
> 上述表格的命令仅供演示,没有实际动作产生。
## 语音命令词自定义
BOX 系列开发板配备乐鑫专有的 AI 语音识别系统,您可以通过 “ESP-BOX” APP 自定义用于指令的任意命令词,我们将以 LED 灯作为示例介绍如何自定义语音命令词。(有关算法工作原理的详细信息,请参阅开发指引里的技术架构说明。)
@@ -115,8 +174,7 @@ BOX 系列开发板配备乐鑫专有的 AI 语音识别系统,您可以通过
<div align="center">
<img src="_static/_get_started_static/6.png">
</div>
1.2. 扫描如下二维码下载并安装 ESP-BOX APP,您也可以直接在 Apple Store 和 Google Play 搜索“ESP-BOX”下载 APP。
1.2. 扫描如下二维码下载并安装 ESP-BOX APP,您也可以直接在 Apple Store 和 Google Play 搜索 “ESP-BOX” 下载 APP。
<div align="center">
<img src="_static/_get_started_static/8.png">
@@ -124,8 +182,9 @@ BOX 系列开发板配备乐鑫专有的 AI 语音识别系统,您可以通过
<div align="center">
<img src="_static/_get_started_static/Picture1.png">
</div>
1.3. 如您第一次下载使用,请点击 “User”,“Register”,注册一个新账户。
1.4. 登录您的 ESP-BOX 账号并打开手机蓝牙。然后找到界面下方的“+” ,点击扫码图标扫描设备上的配网二维码。
<div align="center">
@@ -137,8 +196,9 @@ BOX 系列开发板配备乐鑫专有的 AI 语音识别系统,您可以通过
<div align="center">
<img src="_static/_get_started_static/3.jpeg"width="300" />
</div>
1.5 请按 APP 内指引添加您的设备,设备添加完成后,您将看到如下界面:
<div align="center">
<img src="_static/_get_started_static/4.jpeg"width="300" />
</div>
@@ -148,16 +208,17 @@ BOX 系列开发板配备乐鑫专有的 AI 语音识别系统,您可以通过
<div align="center">
<img src="_static/_get_started_static/7.png">
</div>
>**注意:**
>**注意:**
>
>* 确保设备连接的网络是 2.4GHz Wi-Fi 而不是 5GHz,并且输入正确的 Wi-Fi 密码,如果 Wi-Fi 密码错误,会显示 “Wi-Fi Authentication failed”。
>* 在配网过程中不要退出设备配网界面。
>* 长按 Boot 按键 5 秒可清除配网信息恢复出厂设置。
<div align="center">
<img src="_static/_get_started_static/7.jpeg"width="300" />
</div>
**2. 自定义语音命令词:**
2.1. 点击你的 ESP-BOX 设备,进入如下页面,您可以简单地在这个用户界面开灯或者关灯。(我们预留了“开关”和“风扇”功能给您自行去配置和开发。)
@@ -168,6 +229,7 @@ BOX 系列开发板配备乐鑫专有的 AI 语音识别系统,您可以通过
<div align="center">
<img src="_static/_get_started_static/9.jpeg"width="300" />
</div>
2.2. 点按 “Light”,进入 “Configure” 页面查看当前默认的 pin 脚信息和命令词。您也可以根据需要修改 LED 模块的 “RED”、“GREEN” 和 “BLUE” pin 脚。
<div align="center">
@@ -176,13 +238,13 @@ BOX 系列开发板配备乐鑫专有的 AI 语音识别系统,您可以通过
<div align="center">
<img src="_static/_get_started_static/11.jpeg"width="300" />
</div>
2.3. “Control” 页面允许您对灯光进行颜色、亮度和饱和度的更改。
<div align="center">
<img src="_static/_get_started_static/12.jpeg"width="300" />
</div>
2.4. “Configure” 页面允许您针对设备的“开”、“关”、“颜色”定义您喜欢的命令词来控制设备。比如,您可以自定义“开”的命令词为“早上好”(如下图标注“1”步骤),点击保存,界面返回上一级(如下图标注“2”步骤),然后再点击保存(如下图标注“3”步骤)。
<div align="center">
@@ -191,14 +253,14 @@ BOX 系列开发板配备乐鑫专有的 AI 语音识别系统,您可以通过
<div align="center">
<img src="_static/_get_started_static/13.1 CN.jpeg"width="300" />
</div>
2.5. 现在,您可以体验您的新命令词了!请先使用 “Hi 乐鑫” 去唤醒设备,然后在六秒内说出打开电灯的新命令词“早上好”,新命令词会显示在屏幕上并且 LED 模块打开。
<div align="center">
<img src="_static/_get_started_static/14.png"width="300" />
</div>
>**如何添加合适的命令词:AI 模型支持自定义命令词,为了获得最优的识别体验,命令词定义时需要注意以下事项:**
>**如何添加合适的命令词:AI 模型支持自定义命令词,为了获得最优的识别体验,APP 上命令词定义时需要注意以下事项:**
>* 命令词的长度:命令词中单词数需要大于等于 2 个,小于等于 8 个。在定义一系列命令词时,最好可以保持不同命令词的长度相似。
>* 避免前缀:多个命令词,相互之间不要是对方的前缀,短的词会被屏蔽,比如 “打开”和“打开灯”,“打开”会被屏蔽。
+13 -5
View File
@@ -1,14 +1,22 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(PROJECT_VER "0.2.1")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
if(DEFINED ENV{RMAKER_PATH})
set(RMAKER_PATH $ENV{RMAKER_PATH})
else()
set(RMAKER_PATH ${CMAKE_CURRENT_LIST_DIR}/../../components/esp-rainmaker)
message("-- Not find RMAKER_PATH, default is ${RMAKER_PATH}")
endif(DEFINED ENV{RMAKER_PATH})
set(EXTRA_COMPONENT_DIRS
$ENV{IDF_PATH}/examples/common_components/protocol_examples_common
../../components
$ENV{IDF_PATH}/examples/common_components/led_strip
../../components)
${RMAKER_PATH}/components
)
add_compile_options(-fdiagnostics-color=always)
project(factory_demo)
project(lite_demo)
+117 -75
View File
@@ -1,71 +1,20 @@
# ESP32-S3-Box Factory Demo
# Factory Example
This is the factory demo for ESP32-S3-Box development board.
| Board | Support Status |
| ----------------- | -------------- |
| ESP32-S3-BOX | YES |
| ESP32-S3-BOX-Lite | YES |
## How to Compile
The factory_demo is a built-in firmware of ESP-BOX series products, which integrates LVGL, ESP-Rainmaker and ESP-SR.
Since some bug fixes of esp-idf may not be synced to GitHub, you need to manually apply some patches to build the example.
## How to use example
### Apply Patch
For Linux and macOS, you can apply the patch by entering the following command on the command line / terminal:
```shell
cd /path/to/esp-box/idf_patch
python3 apply_patch.py -d /path/to/esp-idf
. /path/to/esp-idf/export.sh
```
For Windows users, you may need to do the following manually:
- Change the working directory to the folder where esp-idf is located
- Run the following commands in cmd in sequence
- `git fetch origin`
- `git checkout 35b20cadce65ce79c14cf2018efc87c44d71ab21`
- `git apply X:\path\to/esp-box\idf_patch\idf_patch.patch`
- Copy the files in the `idf_patch\components\esp_phy` folder and replace them to the same location under esp-idf in turn
- Run `install.bat` in the esp-idf directory
- Run `export.bat` in the esp-idf directory
- Enter the esp-box repo to compile the project you want
### Compile Example
The project provides `sdkconfig.defaults.cn` and `sdkconfig.defaults.en`, which are the default configuration files corresponding to Chinese and English respectively. By replacing `sdkconfig.defaults` with the above file, deleting `sdkconfig`, rebuilding and burning, you can burn routines in the specified language to ESP-Box.
## How to Use
Please check the [User-Guide](../../docs/getting_started.md).
### Hardware Required
* A ESP32-S3-Box
* A ESP32-S3-Box or ESP32-S3-BOX-Lite
* An USB-C cable for power supply and programming
* An RGB LED used to transmit encoded IR signals
example connection:
| | ESP32-S3-Box |
| :---: | :-----------: |
| RED | IO 39 |
| GREEN | IO 40 |
| BLUE | IO 41 |
### Wake Up Device
Say "Hi esp" to wake up the device. Then say command word list is as follows after animate shows on screen:
- Turn On/Off The Light
- Turn Red / Green / Blue / White
- Custom Color
The detected command word will be displayed on the screen. If the LED is correctly connected to the device, its color will change according to the command word.
### Modify the command word
- Click the Wi-Fi button at the top.
- Scan the QR code to connect to the AP of the device.
- Scan the QR code again to enter the configuration page.
- Click on the device and enter the control page.
- Modify "Voice command" and click "Save".
- Try your new command word to turn on / off the light
### Build and Flash
@@ -75,23 +24,116 @@ Once a complete flash process has been performed, you can use `idf.py app-flash
(To exit the serial monitor, type `Ctrl-]`. Please reset the development board f you cannot exit the monitor.)
## Troubleshooting
## Example Output
* Program upload failure
Run this example, you will see the following output log:
* Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs.
* Try to put ESP32-S3 into download mode. To do this, keep GPIO0 low while toggling reset. On many development boards, the “Boot” button is connected to GPIO0, and you can press “Reset” button while holding “Boot”.
* LCD does not display properly or flickers
* Make sure that the MUTE button is not pressed, and the yellow indicator light on the top of the development board is not lit.
* No response after scanning the QR code
* Try to manually connect to the AP displayed on the screen and enter the URL in the browser
```
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fcd0108,len:0x17a4
load:0x403b6000,len:0xe0c
load:0x403ba000,len:0x3068
entry 0x403b626c
I (24) boot: ESP-IDF v4.4-129-g6934a0164a-dirty 2nd stage bootloader
I (25) boot: compile time 19:04:00
I (25) boot: chip revision: 0
I (28) qio_mode: Enabling default flash chip QIO
I (33) boot.esp32s3: Boot SPI Speed : 80MHz
I (38) boot.esp32s3: SPI Mode : QIO
I (43) boot.esp32s3: SPI Flash Size : 16MB
I (48) boot: Enabling RNG early entropy source...
I (53) boot: Partition Table:
I (57) boot: ## Label Usage Type ST Offset Length
I (64) boot: 0 sec_cert Unknown data 01 06 0000d000 00003000
I (71) boot: 1 nvs WiFi data 01 02 00010000 00006000
I (79) boot: 2 otadata OTA data 01 00 00016000 00002000
I (86) boot: 3 phy_init RF data 01 01 00018000 00001000
I (94) boot: 4 fctry WiFi data 01 02 00019000 00006000
I (101) boot: 5 ota_0 OTA app 00 10 00020000 0039d000
I (109) boot: 6 storage Unknown data 01 82 003bd000 0028a000
I (116) boot: 7 model Unknown data 01 82 00647000 007e9000
I (124) boot: End of partition table
I (128) esp_image: segment 0: paddr=00020020 vaddr=3c140020 size=1fc3d4h (2081748) map
I (452) esp_image: segment 1: paddr=0021c3fc vaddr=3fca5500 size=03c1ch ( 15388) load
I (455) esp_image: segment 2: paddr=00220020 vaddr=42000020 size=13d828h (1300520) map
I (655) esp_image: segment 3: paddr=0035d850 vaddr=3fca911c size=0163ch ( 5692) load
I (657) esp_image: segment 4: paddr=0035ee94 vaddr=40378000 size=1d4f8h (120056) load
I (684) esp_image: segment 5: paddr=0037c394 vaddr=50000000 size=00014h ( 20) load
I (696) boot: Loaded app from partition at offset 0x20000
I (696) boot: Disabling RNG early entropy source...
I (696) opi psram: vendor id : 0x0d (AP)
I (701) opi psram: dev id : 0x02 (generation 3)
I (706) opi psram: density : 0x03 (64 Mbit)
I (711) opi psram: good-die : 0x01 (Pass)
I (716) opi psram: Latency : 0x01 (Fixed)
I (721) opi psram: VCC : 0x01 (3V)
I (725) opi psram: SRF : 0x01 (Fast Refresh)
I (731) opi psram: BurstType : 0x01 (Hybrid Wrap)
I (736) opi psram: BurstLen : 0x01 (32 Byte)
I (741) opi psram: Readlatency : 0x02 (10 cycles@Fixed)
I (747) opi psram: DriveStrength: 0x00 (1/1)
W (752) PSRAM: DO NOT USE FOR MASS PRODUCTION! Timing parameters will be updated in future IDF version.
I (763) spiram: Found 64MBit SPI RAM device
I (767) spiram: SPI RAM mode: sram 80m
I (771) spiram: PSRAM initialized, cache is in normal (1-core) mode.
I (778) cpu_start: Pro cpu up.
I (782) cpu_start: Starting app cpu, entry point is 0x403794d8
0x403794d8: call_start_cpu1 at /home/zhouli/esp/esp-idf/master/components/esp_system/port/cpu_start.c:160
## Technical support and feedback
I (0) cpu_start: App cpu up.
I (1077) spiram: SPI SRAM memory test OK
I (1086) cpu_start: Pro cpu start user code
I (1086) cpu_start: cpu freq: 240000000
I (1086) cpu_start: Application information:
I (1087) cpu_start: Project name: lite_demo
I (1087) cpu_start: App version: 6d88257-dirty
I (1087) cpu_start: Compile time: Mar 2 2022 17:44:23
I (1087) cpu_start: ELF file SHA256: 500f0cf0f4dbfedd...
I (1087) cpu_start: ESP-IDF: v4.4-129-g6934a0164a-dirty
I (1088) heap_init: Initializing. RAM available for dynamic allocation:
I (1088) heap_init: At 3FCB1690 len 0002E970 (186 KiB): D/IRAM
I (1088) heap_init: At 3FCE0000 len 0000EE34 (59 KiB): STACK/DRAM
I (1089) heap_init: At 600FE000 len 00002000 (8 KiB): RTCRAM
I (1089) spiram: Adding pool of 8192K of external SPI memory to heap allocator
I (1089) spi_flash: detected chip: gd
I (1090) spi_flash: flash io: qio
I (1090) sleep: Configure to isolate all GPIO pins in sleep state
I (1091) sleep: Enable automatic switching of GPIO sleep configuration
I (1091) coexist: coexist rom version e7ae62f
I (1091) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (1092) spiram: Reserving pool of 8K of internal memory for DMA/internal allocations
I (1119) main: System Info Trace
Description Internal SPIRAM
Current Free Memory 220191 8386191
Largest Free Block 151552 8257536
Min. Ever Free Size 219423 8386191
I (1119) codec: Detected codec at 0x08. Name : ES7243
I (1119) codec: Detected codec at 0x10. Name : ES8156
I (1121) bsp boards: Detected board: [S3_BOX_LITE]
I (1121) gpio: GPIO[0]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (1121) adc button: Characterized using Default Vref
I (1122) I2S: DMA Malloc info, datalen=blocksize=640, dma_buf_count=6
I (1123) I2S: DMA Malloc info, datalen=blocksize=640, dma_buf_count=6
I (1123) I2S: I2S0, MCLK output by GPIO2
I (1124) codec: Detected codec at 0x08. Name : ES7243
I (1124) codec: Detected codec at 0x10. Name : ES8156
I (1130) codec: init ES7243
I (1131) codec: init ES8156
I (1131) gpio: GPIO[46]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (1132) gpio: GPIO[4]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (1132) gpio: GPIO[48]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (1252) gpio: GPIO[45]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (1252) lv_port: Try allocate two 320 * 20 display buffer, size:25600 Byte
I (1254) lv_port: Add KAYPAD input device to LVGL
I (1876) bsp_spiffs: Partition size: total: 7616846, used: 7341248
I (2040) bsp_spiffs: Partition size: total: 2439971, used: 1367197
I (2057) ui_main: Input device type is keypad
Traverse directory /spiffs/mp3
I (2095) SR_AFE: Initial auido front-end, total channel: 3, mic num: 2, ref num: 1
Please use the following feedback channels:
* For technical queries, go to the [esp32.com](https://esp32.com/) forum
* For a feature request or bug report, create a [GitHub issue](https://github.com/espressif/esp-box/issues)
We will get back to you as soon as possible.
I (2097) SR_AFE: aec_init: 0, se_init: 1, vad_init: 1
I (2098) SR_AFE: wakenet_init: 1, voice_communication_init: 0
```
+14 -12
View File
@@ -1,17 +1,19 @@
file(GLOB_RECURSE APP_SRCS app/*.c)
file(GLOB_RECURSE FONT_SRCS font/*.c)
file(GLOB_RECURSE IMG_SRCS image/*.c)
file(GLOB_RECURSE UI_SRCS ui/*.c)
idf_component_register(
SRCS
"demo_main.c"
"sr_handler.c"
${APP_SRCS}
${FONT_SRCS}
${IMG_SRCS}
${UI_SRCS}
SRC_DIRS
"."
"app"
"gui"
"gui/font"
"gui/image"
"rmaker"
INCLUDE_DIRS
"include")
"."
"gui"
"app"
"rmaker")
target_compile_definitions(${COMPONENT_TARGET} PRIVATE "-D RMAKER_DEMO_PROJECT_NAME=\"${CMAKE_PROJECT_NAME}\"")
spiffs_create_partition_image(storage ../spiffs FLASH_IN_PROJECT)
-147
View File
@@ -1,147 +0,0 @@
/**
* @file app_audio.c
* @brief
* @version 0.1
* @date 2021-09-22
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdbool.h>
#include <stdio.h>
#include "driver/i2s.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
static const char *TAG = "app_audio";
static bool b_audio_playing = false;
static SemaphoreHandle_t audio_sem = NULL;
static void audio_task(void *pvParam);
esp_err_t app_audio_start(void)
{
FILE *fp = fopen("/spiffs/audio/wake.pcm", "rb");
if (NULL == fp) {
ESP_LOGE(TAG, "Audio file does't exist");
return ESP_ERR_NOT_FOUND;
}
fseek(fp, 0, SEEK_END);
size_t file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
void *audio_buffer = heap_caps_malloc(file_size, MALLOC_CAP_SPIRAM);
if (NULL == audio_buffer) {
ESP_LOGE(TAG, "No mem for audio buffer");
return ESP_ERR_NO_MEM;
}
fread(audio_buffer, 1, file_size, fp);
fclose(fp);
audio_sem = xSemaphoreCreateBinary();
if (NULL == audio_sem) {
ESP_LOGE(TAG, "Failed create audio semaphore");
return ESP_FAIL;
}
BaseType_t ret_val = xTaskCreatePinnedToCore(
(TaskFunction_t) audio_task,
(const char * const) "Audio Task",
(const uint32_t) 2 * 1024,
(void * const) audio_buffer,
(UBaseType_t) 1,
(TaskHandle_t * const) NULL,
(const BaseType_t) 0);
if (pdPASS != ret_val) {
ESP_LOGE(TAG, "Failed create audio task");
return ESP_FAIL;
}
return ESP_OK;
}
void audio_play_start(void)
{
if (NULL == audio_sem) {
return;
}
xSemaphoreGive(audio_sem);
}
static void audio_task(void *pvParam)
{
void *audio_buffer = pvParam;
size_t bytes_written = 0;
size_t bytes_to_write = heap_caps_get_allocated_size(audio_buffer);
while (true) {
xSemaphoreTake(audio_sem, portMAX_DELAY);
b_audio_playing = true;
i2s_write(I2S_NUM_0, audio_buffer, bytes_to_write, &bytes_written, portMAX_DELAY);
b_audio_playing = false;
/* It's useful if wake audio didn't finish playing when next wake word detetced */
// xSemaphoreTake(audio_sem, 0);
}
}
bool audio_is_playing(void)
{
return b_audio_playing;
}
/* **************** AUDIO DEBUG TOOL **************** */
esp_err_t audio_record_to_file(size_t time_ms, const char *file_name)
{
size_t audio_channel = 4;
size_t audio_sample_rate = 16000;
size_t bytes_per_sample = sizeof(int16_t);
size_t file_size = audio_sample_rate * time_ms / 1000 * bytes_per_sample * audio_channel;
/* Create file on storage device */
FILE *fp = fopen(file_name, "w+");
if (NULL == file_name) {
ESP_LOGE(TAG, "Failed create file");
return ESP_FAIL;
}
/* Alocate memory for audio data */
void *audio_buffer = heap_caps_malloc(file_size, MALLOC_CAP_SPIRAM);
if (NULL == audio_buffer) {
ESP_LOGE(TAG, "Failed to allocate audio buffer");
fclose(fp);
return ESP_ERR_NO_MEM;
}
/* Read audio data to RAM from I2S */
size_t bytes_read;
ESP_LOGI(TAG, "Record start");
esp_err_t ret_val = i2s_read(I2S_NUM_0, audio_buffer, file_size, &bytes_read, portMAX_DELAY);
ESP_LOGI(TAG, "Record stop");
/* Write audio data to storage device */
fwrite(audio_buffer, 1, file_size, fp);
fclose(fp);
ESP_LOGI(TAG, "File saved to %s", file_name);
return ret_val;
}
@@ -1,320 +0,0 @@
/**
* @file app_data_parse.c
* @brief
* @version 0.1
* @date 2021-09-27
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "app_led.h"
#include "app_sr.h"
#include "cJSON.h"
#include "esp_err.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "lvgl.h"
#include "ui_main.h"
static const char *TAG = "data_parse";
/* String length is limited on web, but still not safe here */
static char cmd_on[64] = STR_LIGHT_ON;
static char cmd_off[64] = STR_LIGHT_OFF;
static char cmd_color[64] = STR_LIGHT_COLOR;
static char voice_on[64] = VOICE_LIGHT_ON;
static char voice_off[64] = VOICE_LIGHT_OFF;
static char voice_color[64] = VOICE_LIGHT_COLOR;
static led_state_t led_state_default = {
.on = true,
.h = 30,
.s = 30,
.v = 30,
.gpio = -1,
};
char *get_cmd_string(int id)
{
switch (id) {
case SR_CMD_LIGHT_ON:
return cmd_on;
break;
case SR_CMD_LIGHT_OFF:
return cmd_off;
break;
case SR_CMD_CUSTOM_COLOR:
return cmd_color;
break;
}
return NULL;
}
led_state_t *get_default_led_config(void)
{
return &led_state_default;
}
static void parse_config(cJSON *root_obj)
{
cJSON *item_obj = NULL;
item_obj = cJSON_GetObjectItem(root_obj, "type");
if (NULL != item_obj) {
printf("%s : %s\n", item_obj->string, item_obj->valuestring);
}
item_obj = cJSON_GetObjectItem(root_obj, "node_id");
if (NULL != item_obj) {
printf("%s : %d\n", item_obj->string, (int) item_obj->valuedouble);
}
cJSON *param_array = cJSON_GetObjectItem(root_obj, "params");
if (NULL != param_array) {
int param_array_num = cJSON_GetArraySize(param_array);
printf("Array %s has %d object(s)\n", param_array->string, param_array_num);
for (int i = 0; i < param_array_num; i++) {
cJSON *param_item = cJSON_GetArrayItem(param_array, i);
if (strcmp("config", param_item->string)) {
printf("%s : %d\n", param_item->string, (int) param_item->valuedouble);
} else {
cJSON *item_led_obj = cJSON_GetObjectItem(param_item, "gpio");
if (NULL != item_led_obj) {
printf("%s : %d\n", item_led_obj->string, (int) item_led_obj->valuedouble);
}
cJSON *voice_item_array = cJSON_GetObjectItem(param_item, "params");
if (NULL == voice_item_array) {
return;
}
int voice_item_size = cJSON_GetArraySize(voice_item_array);
printf("Voice item size : %d\n", voice_item_size);
for (size_t i = 0; i < voice_item_size; i++) {
cJSON *voice_item = cJSON_GetArrayItem(voice_item_array, i);
cJSON *sw_item = cJSON_GetObjectItem(voice_item, "status");
if (NULL == sw_item) {
led_state_default.h = (uint16_t) cJSON_GetObjectItem(voice_item, "hue")->valuedouble;
led_state_default.s = (uint8_t) cJSON_GetObjectItem(voice_item, "saturation")->valuedouble;
led_state_default.v = (uint8_t) cJSON_GetObjectItem(voice_item, "value")->valuedouble;
if (led_state_default.v < 8) {
led_state_default.v = 8;
}
printf("Voice for [%u, %u, %u] : (%s)[%s]\n",
led_state_default.h, led_state_default.s, led_state_default.v,
strcpy(cmd_color, cJSON_GetObjectItem(voice_item, "zh")->valuestring),
strcpy(voice_color, cJSON_GetObjectItem(voice_item, "voice")->valuestring));
} else {
if (cJSON_GetObjectItem(voice_item, "status")->valuedouble == 1) {
printf("Voice to turn on : (%s)[%s]\n",
cJSON_GetObjectItem(voice_item, "zh")->valuestring,
cJSON_GetObjectItem(voice_item, "voice")->valuestring);
strcpy(cmd_on, cJSON_GetObjectItem(voice_item, "zh")->valuestring);
strcpy(voice_on, cJSON_GetObjectItem(voice_item, "voice")->valuestring);
} else {
printf("Voice to turn on : (%s)[%s]\n",
cJSON_GetObjectItem(voice_item, "zh")->valuestring,
cJSON_GetObjectItem(voice_item, "voice")->valuestring);
strcpy(cmd_off, cJSON_GetObjectItem(voice_item, "zh")->valuestring);
strcpy(voice_off, cJSON_GetObjectItem(voice_item, "voice")->valuestring);
}
}
}
/* Reset command list */
char *cmd = (char *) heap_caps_malloc(512, MALLOC_CAP_SPIRAM);
if (NULL != cmd) {
cmd[0] = '\0'; /* Make cmd a valid string */
/* Command should match `sdkconfig` */
strcat(cmd, VOICE_LIGHT_RED STR_DELIMITER); /*!< Red */
strcat(cmd, VOICE_LIGHT_GREEN STR_DELIMITER); /*!< Green */
strcat(cmd, VOICE_LIGHT_BLUE STR_DELIMITER); /*!< Blue */
strcat(cmd, VOICE_LIGHT_WHITE STR_DELIMITER); /*!< White */
strcat(strcat(cmd, voice_on), STR_DELIMITER); /*!< On */
strcat(strcat(cmd, voice_off), STR_DELIMITER); /*!< Off */
strcat(strcat(cmd, voice_color), STR_DELIMITER); /*!< Custom color */
/* Print new command list */
ESP_LOGI(TAG, "New command set to :\n" "%s", cmd);
/* Reset command list */
app_sr_reset_command_list(cmd);
free(cmd);
} else { /* NULL == cmd */
ESP_LOGE(TAG, "No memory for new command list");
return;
}
}
}
} else { /* (NULL == param_array) */
return;
}
}
static void parse_control(cJSON *root_obj)
{
led_state_t led_state;
cJSON *item_obj = NULL;
app_led_get_state(&led_state);
item_obj = cJSON_GetObjectItem(root_obj, "type");
printf("%s : %s\n", item_obj->string, item_obj->valuestring);
item_obj = cJSON_GetObjectItem(root_obj, "node_id");
printf("%s : %d\n", item_obj->string, (int) item_obj->valuedouble);
cJSON *param_array = cJSON_GetObjectItem(root_obj, "params");
int param_array_num = cJSON_GetArraySize(param_array);
printf("Array %s has %d object(s)\n",
param_array->string, param_array_num);
item_obj = cJSON_GetObjectItem(param_array, "status");
if (NULL != item_obj) {
printf("Light status : %d\n", (int) item_obj->valuedouble);
led_state.on = (int) item_obj->valuedouble;
}
item_obj = cJSON_GetObjectItem(param_array, "hue");
if (NULL != item_obj) {
printf("Light hue : %d\n", (int) item_obj->valuedouble);
led_state.h = (int) item_obj->valuedouble;
}
item_obj = cJSON_GetObjectItem(param_array, "saturation");
if (NULL != item_obj) {
printf("Light saturation : %d\n", (int) item_obj->valuedouble);
led_state.s = (int) item_obj->valuedouble;
}
item_obj = cJSON_GetObjectItem(param_array, "value");
if (NULL != item_obj) {
printf("Light value : %d\n", (int) item_obj->valuedouble);
led_state.v = (int) item_obj->valuedouble;
}
if (led_state.on) {
if (led_state.v < 8) {
led_state.v = 8;
}
app_pwm_led_set_all_hsv(led_state.h, led_state.s, led_state.v);
} else {
app_pwm_led_set_all(0, 0, 0);
}
ui_dev_ctrl_update_state();
}
esp_err_t app_wifi_parse_json_string(char *text)
{
cJSON *root_obj = NULL;
cJSON *method_obj = NULL;
if (NULL == text) {
return ESP_ERR_INVALID_ARG;
}
root_obj = cJSON_Parse(text);
method_obj = cJSON_GetObjectItem(root_obj, "method");
if (0 == strcmp(method_obj->valuestring, "contrl")) {
printf("Control CMD : \n");
parse_control(root_obj);
} else if (0 == strcmp(method_obj->valuestring, "config")) {
printf("Config CMD : \n");
parse_config(root_obj);
} else {
printf("Invalid CMD : %s\n", method_obj->valuestring);
}
cJSON_Delete(root_obj);
return ESP_OK;
}
esp_err_t app_wifi_build_json_string(led_state_t *led_state, char **json_string)
{
if (NULL == led_state) {
return ESP_ERR_INVALID_ARG;
}
cJSON *root_obj = NULL;
cJSON *node_list_obj = NULL;
cJSON *led_obj = NULL;
cJSON *led_param_obj = NULL;
cJSON *led_config_obj = NULL;
cJSON *led_param_array = NULL;
cJSON *led_param_on = NULL;
cJSON *led_param_off = NULL;
cJSON *led_param_color = NULL;
/* Create root object */
root_obj = cJSON_CreateObject();
/* Add object(s) to root */
cJSON_AddStringToObject(root_obj, "method", "info");
node_list_obj = cJSON_AddArrayToObject(root_obj, "node_list");
led_obj = cJSON_CreateObject();
cJSON_AddItemToArray(node_list_obj, led_obj);
cJSON_AddStringToObject(led_obj, "type", "light");
cJSON_AddNumberToObject(led_obj, "node_id", 1);
led_param_obj = cJSON_AddObjectToObject(led_obj, "params");
cJSON_AddNumberToObject(led_param_obj, "status", led_state->on);
cJSON_AddNumberToObject(led_param_obj, "hue", led_state->h);
cJSON_AddNumberToObject(led_param_obj, "saturation", led_state->s);
cJSON_AddNumberToObject(led_param_obj, "value", led_state->v);
led_config_obj = cJSON_AddObjectToObject(led_param_obj, "config");
cJSON_AddNumberToObject(led_config_obj, "gpio", led_state->gpio);
led_param_array = cJSON_AddArrayToObject(led_config_obj, "params");
led_param_on = cJSON_CreateObject();
led_param_off = cJSON_CreateObject();
led_param_color = cJSON_CreateObject();
cJSON_AddItemToArray(led_param_array, led_param_on);
cJSON_AddNumberToObject(led_param_on, "status", 1);
cJSON_AddStringToObject(led_param_on, "voice", voice_on);
cJSON_AddStringToObject(led_param_on, "zh", cmd_on);
cJSON_AddItemToArray(led_param_array, led_param_off);
cJSON_AddNumberToObject(led_param_off, "status", 0);
cJSON_AddStringToObject(led_param_off, "voice", voice_off);
cJSON_AddStringToObject(led_param_off, "zh", cmd_off);
cJSON_AddItemToArray(led_param_array, led_param_color);
cJSON_AddNumberToObject(led_param_color, "hue", led_state_default.h);
cJSON_AddNumberToObject(led_param_color, "saturation", led_state_default.s);
cJSON_AddNumberToObject(led_param_color, "value", led_state_default.v);
cJSON_AddStringToObject(led_param_color, "voice", voice_color);
cJSON_AddStringToObject(led_param_color, "zh", cmd_color);
/* Print serialized object */
*json_string = cJSON_PrintUnformatted(root_obj);
/* Delete object after used */
cJSON_Delete(root_obj);
return ESP_OK;
}
+46
View File
@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "app_led.h"
#include "bsp_board.h"
#include "driver/gpio.h"
#include "ui_main.h"
#include "ui_device_ctrl.h"
static const char *TAG = "app_fan";
static bool g_fan_on = 0;
esp_err_t app_fan_change_io(gpio_num_t gpio, bool act_level)
{
ESP_LOGW(TAG, "change io not be supported");
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t app_fan_set_power(bool power)
{
esp_err_t ret_val = ESP_OK;
if (power) {
g_fan_on = true;
} else {
g_fan_on = false;
}
ui_dev_ctrl_set_state(UI_DEV_FAN, g_fan_on);
return ret_val;
}
bool app_fan_get_state(void)
{
return g_fan_on;
}
+22
View File
@@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#pragma once
#include "driver/gpio.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
esp_err_t app_fan_change_io(gpio_num_t gpio, bool act_level);
esp_err_t app_fan_set_power(bool power);
bool app_fan_get_state(void);
#ifdef __cplusplus
}
#endif
+221 -149
View File
@@ -1,123 +1,155 @@
/**
* @file app_led.c
* @brief
* @version 0.1
* @date 2021-09-27
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <string.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "app_led.h"
#include "bsp_board.h"
#include "driver/gpio.h"
#include "driver/ledc.h"
#include "driver/rmt.h"
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "led_strip.h"
#include "lvgl.h"
#define CONFIG_EXAMPLE_STRIP_LED_NUMBER (8)
#include "ui_main.h"
#include "ui_device_ctrl.h"
static const char *TAG = "app_led";
static led_strip_t *strip = NULL;
static led_state_t s_led_state = {
typedef struct {
uint16_t h;
uint8_t s;
uint8_t v;
} hsv_t;
typedef struct {
uint8_t r;
uint8_t g;
uint8_t b;
bool on;
} led_state_t;
static led_state_t g_led_state = {
.on = false,
.h = 170,
.s = 100,
.v = 30,
.gpio = GPIO_RMT_LED,
.r = 180,
.g = 180,
.b = 180,
};
esp_err_t app_led_get_state(led_state_t *state)
#define LEDPWM_CNT_TOP 256
static uint8_t g_gamma_table[LEDPWM_CNT_TOP + 1];
static hsv_t g_customize_color = {0};
static gpio_num_t g_last_led_io[3] = {GPIO_NUM_NC};
static bool g_initialized = 0;
/**
* @brief Simple helper function, converting HSV color space to RGB color space
*
* Wiki: https://en.wikipedia.org/wiki/HSL_and_HSV
*
*/
static void led_hsv2rgb(uint32_t h, uint32_t s, uint32_t v, uint8_t *r, uint8_t *g, uint8_t *b)
{
if (NULL == state) {
return ESP_ERR_INVALID_ARG;
h %= 360; /**< h -> [0,360] */
uint32_t rgb_max = v * 2.55f;
uint32_t rgb_min = rgb_max * (100 - s) / 100.0f;
uint32_t i = h / 60;
uint32_t diff = h % 60;
/**< RGB adjustment amount by hue */
uint32_t rgb_adj = (rgb_max - rgb_min) * diff / 60;
switch (i) {
case 0:
*r = rgb_max;
*g = rgb_min + rgb_adj;
*b = rgb_min;
break;
case 1:
*r = rgb_max - rgb_adj;
*g = rgb_max;
*b = rgb_min;
break;
case 2:
*r = rgb_min;
*g = rgb_max;
*b = rgb_min + rgb_adj;
break;
case 3:
*r = rgb_min;
*g = rgb_max - rgb_adj;
*b = rgb_max;
break;
case 4:
*r = rgb_min + rgb_adj;
*g = rgb_min;
*b = rgb_max;
break;
default:
*r = rgb_max;
*g = rgb_min;
*b = rgb_max - rgb_adj;
break;
}
memcpy(state, &s_led_state, sizeof(led_state_t));
return ESP_OK;
}
esp_err_t app_led_init(gpio_num_t io_num)
void led_rgb2hsv(uint8_t r, uint8_t g, uint8_t b, uint16_t *h, uint8_t *s, uint8_t *v)
{
rmt_config_t config = RMT_DEFAULT_CONFIG_TX(io_num, RMT_CHANNEL_0);
config.clk_div = 2;
ESP_ERROR_CHECK(rmt_config(&config));
ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
int32_t R = r;
int32_t G = g;
int32_t B = b;
int32_t min, max, delta, tmp;
tmp = R > G ? G : R;
min = tmp > B ? B : tmp;
tmp = R > G ? R : G;
max = tmp > B ? tmp : B;
*v = 100 * max / 255; /**< v */
delta = max - min;
led_strip_config_t strip_config =
LED_STRIP_DEFAULT_CONFIG(CONFIG_EXAMPLE_STRIP_LED_NUMBER, (led_strip_dev_t)config.channel);
strip = led_strip_new_rmt_ws2812(&strip_config);
if (!strip) {
ESP_LOGE(TAG, "install WS2812 driver failed");
return ESP_FAIL;
}
ESP_ERROR_CHECK(strip->clear(strip, 100));
return ESP_OK;
}
esp_err_t app_led_deinit(void)
{
if (NULL == strip) {
ESP_LOGE(TAG, "LED not initialized");
return ESP_ERR_INVALID_STATE;
}
esp_err_t ret_val = led_strip_denit(strip);
strip = NULL;
return ret_val;
}
esp_err_t app_led_set_all(uint8_t red, uint8_t green, uint8_t blue)
{
esp_err_t ret_val = ESP_OK;
if (NULL == strip) {
ESP_LOGE(TAG, "LED not initialized");
return ESP_ERR_INVALID_STATE;
}
for (size_t i = 0; i < CONFIG_EXAMPLE_STRIP_LED_NUMBER; i++) {
ret_val |= strip->set_pixel(strip, i, red, green, blue);
}
if ((red == 0) && (green == 0) && (blue == 0)) {
s_led_state.on = false;
if (max != 0) {
*s = 100 * delta / max; /**< s */
} else {
lv_color_hsv_t color_hsv = lv_color_rgb_to_hsv(red, green, blue);
s_led_state.on = true;
s_led_state.h = color_hsv.h;
s_led_state.s = color_hsv.s;
s_led_state.v = color_hsv.v;
/**< r = g = b = 0 */
*s = 0;
*h = 0;
return;
}
ret_val |= strip->refresh(strip, 0);
float h_temp = 0;
return ret_val;
if (delta == 0) {
*h = 0;
return;
} else if (R == max) {
h_temp = ((float)(G - B) / (float)delta); /**< between yellow & magenta */
} else if (G == max) {
h_temp = 2.0f + ((float)(B - R) / (float)delta); /**< between cyan & yellow */
} else if (B == max) {
h_temp = 4.0f + ((float)(R - G) / (float)delta); /**< between magenta & cyan */
}
h_temp *= 60.0f;
if (h_temp < 0.0f) {
h_temp += 360;
}
*h = (uint32_t)h_temp; /**< degrees */
}
esp_err_t app_pwm_led_init(void)
esp_err_t app_pwm_led_init(gpio_num_t gpio_r, gpio_num_t gpio_g, gpio_num_t gpio_b)
{
esp_err_t ret_val = ESP_OK;
@@ -135,7 +167,7 @@ esp_err_t app_pwm_led_init(void)
.channel = LEDC_CHANNEL_0,
.timer_sel = LEDC_TIMER_0,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = GPIO_NUM_39,
.gpio_num = gpio_r,
.duty = 0,
.hpoint = 0
};
@@ -146,7 +178,7 @@ esp_err_t app_pwm_led_init(void)
.channel = LEDC_CHANNEL_1,
.timer_sel = LEDC_TIMER_0,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = GPIO_NUM_40,
.gpio_num = gpio_g,
.duty = 0,
.hpoint = 0
};
@@ -157,49 +189,68 @@ esp_err_t app_pwm_led_init(void)
.channel = LEDC_CHANNEL_2,
.timer_sel = LEDC_TIMER_0,
.intr_type = LEDC_INTR_DISABLE,
.gpio_num = GPIO_NUM_41,
.gpio_num = gpio_b,
.duty = 0,
.hpoint = 0
};
ret_val |= ledc_channel_config(&ledc_channel_blue);
g_initialized = 1;
// Generate gamma correction table
for (int i = 0; i < (LEDPWM_CNT_TOP + 1); i++) {
g_gamma_table[i] = (int)roundf(powf((float)i / (float)LEDPWM_CNT_TOP, 1.0 / 0.45) * (float)LEDPWM_CNT_TOP);
}
g_customize_color.h = 0;
g_customize_color.s = 100;
g_customize_color.v = 100;
g_last_led_io[0] = gpio_r;
g_last_led_io[1] = gpio_g;
g_last_led_io[2] = gpio_b;
return ESP_OK;
}
esp_err_t app_pwm_led_change_io(gpio_num_t gpio_r, gpio_num_t gpio_g, gpio_num_t gpio_b)
{
ESP_RETURN_ON_FALSE(g_initialized, ESP_ERR_INVALID_STATE, TAG, "pwm led is not running");
if (g_initialized) {
ESP_LOGI(TAG, "io set to %d,%d,%d; before: %d,%d,%d",
gpio_r, gpio_g, gpio_b,
g_last_led_io[0],
g_last_led_io[1],
g_last_led_io[2]);
gpio_set_direction(g_last_led_io[0], GPIO_MODE_INPUT);
gpio_set_direction(g_last_led_io[1], GPIO_MODE_INPUT);
gpio_set_direction(g_last_led_io[2], GPIO_MODE_INPUT);
}
app_pwm_led_init(gpio_r, gpio_g, gpio_b);
return ESP_OK;
}
esp_err_t app_pwm_led_deinit(void)
{
ESP_LOGW(TAG, "app_pwm_led_deinit() ESP_ERR_NOT_SUPPORTED");
return ESP_ERR_NOT_SUPPORTED;
}
static void update_pwm_led(uint8_t r, uint8_t g, uint8_t b)
{
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, r);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, g);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, b);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2);
}
esp_err_t app_pwm_led_set_all(uint8_t red, uint8_t green, uint8_t blue)
{
esp_err_t ret_val = ESP_OK;
if ((red == 0) && (green == 0) && (blue == 0)) {
s_led_state.on = false;
} else {
lv_color_hsv_t color_hsv = lv_color_rgb_to_hsv(red, green, blue);
s_led_state.on = true;
s_led_state.h = color_hsv.h;
s_led_state.s = color_hsv.s;
s_led_state.v = color_hsv.v;
}
if (s_led_state.on) {
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, red);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, green);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, blue);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2);
} else {
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 0);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2);
}
g_led_state.r = red;
g_led_state.g = green;
g_led_state.b = blue;
app_pwm_led_set_power(true);
return ret_val;
}
@@ -211,35 +262,56 @@ esp_err_t app_pwm_led_set_all_hsv(uint16_t h, uint8_t s, uint8_t v)
uint8_t red = 0;
uint8_t green = 0;
uint8_t blue = 0;
if (v == 0) {
s_led_state.on = false;
} else {
s_led_state.h = h;
s_led_state.s = s;
s_led_state.v = v;
s_led_state.on = true;
lv_color_t color_rgb = lv_color_hsv_to_rgb(h, s, v);
red = color_rgb.ch.red << 3;
green = (color_rgb.ch.green_h << 5) + (color_rgb.ch.green_l << 2);
blue = color_rgb.ch.blue << 3;
}
if (s_led_state.on) {
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, red);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, green);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, blue);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2);
} else {
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1, 0);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 0);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_1);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2);
}
led_hsv2rgb(h, s, v, &red, &green, &blue);
g_led_state.r = red;
g_led_state.g = green;
g_led_state.b = blue;
app_pwm_led_set_power(true);
return ret_val;
}
esp_err_t app_pwm_led_set_power(bool power)
{
esp_err_t ret_val = ESP_OK;
uint8_t red = 0;
uint8_t green = 0;
uint8_t blue = 0;
if (power) {
g_led_state.on = true;
ui_dev_ctrl_set_state(UI_DEV_LIGHT, 1);
} else {
g_led_state.on = false;
update_pwm_led(0, 0, 0);
ui_dev_ctrl_set_state(UI_DEV_LIGHT, 0);
return ret_val;
}
red = g_gamma_table[g_led_state.r];
green = g_gamma_table[g_led_state.g];
blue = g_gamma_table[g_led_state.b];
update_pwm_led(red, green, blue);
return ret_val;
}
bool app_pwm_led_get_state(void)
{
return g_led_state.on;
}
esp_err_t app_pwm_led_set_customize_color(uint16_t h, uint8_t s, uint8_t v)
{
ESP_LOGI(TAG, "customize_color: hsv=[%d,%d,%d]", h, s, v);
g_customize_color.h = h;
g_customize_color.s = s;
g_customize_color.v = v;
return ESP_OK;
}
esp_err_t app_pwm_led_get_customize_color(uint16_t *h, uint8_t *s, uint8_t *v)
{
*h = g_customize_color.h;
*s = g_customize_color.s;
*v = g_customize_color.v;
return ESP_OK;
}
+28
View File
@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#pragma once
#include "driver/gpio.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
esp_err_t app_pwm_led_init(int gpio_r, int gpio_g, int gpio_b);
esp_err_t app_pwm_led_change_io(gpio_num_t gpio_r, gpio_num_t gpio_g, gpio_num_t gpio_b);
esp_err_t app_pwm_led_deinit(void);
esp_err_t app_pwm_led_set_all(uint8_t red, uint8_t green, uint8_t blue);
esp_err_t app_pwm_led_set_all_hsv(uint16_t h, uint8_t s, uint8_t v);
esp_err_t app_pwm_led_set_power(bool power);
bool app_pwm_led_get_state(void);
esp_err_t app_pwm_led_set_customize_color(uint16_t h, uint8_t s, uint8_t v);
esp_err_t app_pwm_led_get_customize_color(uint16_t *h, uint8_t *s, uint8_t *v);
#ifdef __cplusplus
}
#endif
@@ -1,140 +0,0 @@
/**
* @file app_network.c
* @brief
* @version 0.1
* @date 2021-09-26
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include "app_server.h"
#include "app_network.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_spiffs.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "lwip/apps/netbiosns.h"
#include "mdns.h"
#include "nvs_flash.h"
#include "protocol_examples_common.h"
#include "ui_main.h"
static const char *TAG = "app_network";
static void initialise_mdns(const char *file_name)
{
mdns_init();
mdns_hostname_set("esp-box");
mdns_instance_name_set("esp-box");
mdns_txt_item_t serviceTxtData[] = {
{"board", "ESP32-S3-Box"},
{"path", "/"}
};
ESP_ERROR_CHECK(
mdns_service_add("ESP32-WebServer", "_http", "_tcp", 80, serviceTxtData,
sizeof(serviceTxtData) / sizeof(serviceTxtData[0])));
}
static void soft_ap_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
if (WIFI_EVENT_AP_STACONNECTED == event_id) {
ui_network_set_state(true);
}
if (WIFI_EVENT_AP_STADISCONNECTED == event_id) {
ui_network_set_state(false);
}
}
static void start_soft_ap(void)
{
esp_netif_create_default_wifi_ap();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&soft_ap_event_handler,
NULL,
NULL));
wifi_config_t wifi_config = {
.ap = {
.ssid = EXAMPLE_ESP_WIFI_SSID,
.channel = EXAMPLE_ESP_WIFI_CHANNEL,
.password = EXAMPLE_ESP_WIFI_PASS,
.max_connection = EXAMPLE_MAX_STA_CONN,
.authmode = WIFI_AUTH_WPA2_PSK,
.pairwise_cipher = WIFI_CIPHER_TYPE_CCMP,
},
};
if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
}
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}
static void network_task(void *pvParam)
{
char *host_name = (char *) pvParam;
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
initialise_mdns(host_name);
netbiosns_init();
netbiosns_set_name(host_name);
/* Start soft-AP */
start_soft_ap();
/* Start example connection if you want to make ESP32-S3 as station */
// ESP_ERROR_CHECK(example_connect());
start_rest_server("/spiffs/web");
vTaskDelete(NULL);
}
esp_err_t app_network_start(const char *host_name)
{
BaseType_t ret_val = xTaskCreatePinnedToCore(
(TaskFunction_t) network_task,
(const char * const) "Network Task",
(const uint32_t) 4 * 1024,
(void * const) host_name,
(UBaseType_t) 1,
(TaskHandle_t * const) NULL,
(const BaseType_t) 0);
if (pdPASS != ret_val) {
ESP_LOGE(TAG, "Failed create Network task");
return ESP_FAIL;
}
return ESP_OK;
}
+354
View File
@@ -0,0 +1,354 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <dirent.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "driver/i2s.h"
#include "esp_check.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "app_player.h"
#include "bsp_i2s.h"
#include "bsp_codec.h"
#include "mp3dec.h"
#include "file_manager.h"
static const char *TAG = "player";
/* **************** AUDIO CALLBACK **************** */
static audio_cb_t s_audio_cb = NULL;
static void *audio_cb_usrt_ctx = NULL;
static QueueHandle_t audio_event_queue = NULL;
player_state_t g_player_state;
static uint16_t g_file_num = 0;
static uint16_t audio_index = 0;
static char **g_file_list = NULL;
esp_err_t app_player_callback_register(audio_cb_t call_back, void *user_ctx)
{
s_audio_cb = call_back;
audio_cb_usrt_ctx = user_ctx;
return ESP_OK;
}
size_t app_player_get_index(void)
{
return audio_index;
}
const char *app_player_get_name_from_index(size_t index)
{
ESP_RETURN_ON_FALSE(index < g_file_num, NULL, TAG, "File index out of range");
ESP_RETURN_ON_FALSE(NULL != g_file_list, NULL, TAG, "Audio file not found");
ESP_RETURN_ON_FALSE(NULL != g_file_list[index], NULL, TAG, "Audio file not found");
return g_file_list[index];
}
static esp_err_t play_mp3(const char *path)
{
ESP_LOGI(TAG, "start to decode %s", path);
FILE *fp = NULL;
int sample_rate = 0;
uint32_t bits_cfg = 0;
uint32_t nChans = 0;
esp_err_t ret = ESP_OK;
uint8_t *output = NULL;
uint8_t *read_buf = NULL;
MP3FrameInfo frame_info;
HMP3Decoder mp3_decoder = MP3InitDecoder();
player_event_t audio_event = AUDIO_EVENT_NONE;
ESP_RETURN_ON_FALSE(NULL != mp3_decoder, ESP_ERR_NO_MEM, TAG, "Failed create MP3 decoder");
read_buf = malloc(MAINBUF_SIZE);
ESP_GOTO_ON_FALSE(NULL != read_buf, ESP_ERR_NO_MEM, clean_up, TAG, "Failed allocate read buffer");
output = malloc(1152 * sizeof(int16_t) * 2);
ESP_GOTO_ON_FALSE(NULL != output, ESP_ERR_NO_MEM, clean_up, TAG, "Failed allocate output buffer");
/* Read audio file from given path */
fp = fopen(path, "rb");
ESP_GOTO_ON_FALSE(NULL != fp, ESP_ERR_NOT_FOUND, clean_up, TAG, "File \"%s\" does not exist", path);
typedef struct {
char header[3]; /*!< Always "ID3" */
char ver; /*!< Version, equals to3 if ID3V2.3 */
char revision; /*!< Revision, should be 0 */
char flag; /*!< Flag byte, use Bit[7..5] only */
char size[4]; /*!< TAG size */
} __attribute__((packed)) mp3_id3_header_v2_t;
/* Get ID3 head */
mp3_id3_header_v2_t tag;
if (sizeof(mp3_id3_header_v2_t) == fread(&tag, 1, sizeof(mp3_id3_header_v2_t), fp)) {
if (memcmp("ID3", (const void *) &tag, sizeof(tag.header)) == 0) {
int tag_len =
((tag.size[0] & 0x7F) << 21) +
((tag.size[1] & 0x7F) << 14) +
((tag.size[2] & 0x7F) << 7) +
((tag.size[3] & 0x7F) << 0);
fseek(fp, tag_len - sizeof(mp3_id3_header_v2_t), SEEK_SET);
} else {
/* Not ID3 header */
fseek(fp, 0, SEEK_SET);
}
}
/* Start MP3 decoding */
int bytes_left = 0;
unsigned char *read_ptr = read_buf;
do {
/* Process audio event sent from other task */
if (pdPASS == xQueueReceive(audio_event_queue, &audio_event, 0)) {
if (AUDIO_EVENT_PAUSE == audio_event) {
g_player_state = PLAYER_STATE_PAUSE;
i2s_zero_dma_buffer(I2S_NUM_0);
xQueuePeek(audio_event_queue, &audio_event, portMAX_DELAY);
continue;
}
if (AUDIO_EVENT_CHANGE == audio_event ||
AUDIO_EVENT_NEXT == audio_event ||
AUDIO_EVENT_PREV == audio_event) {
i2s_zero_dma_buffer(I2S_NUM_0);
ret = ESP_FAIL;
goto clean_up;
}
}
g_player_state = PLAYER_STATE_PLAYING;
/* Read `mainDataBegin` size to RAM */
if (bytes_left < MAINBUF_SIZE) {
memmove(read_buf, read_ptr, bytes_left);
size_t bytes_read = fread(read_buf + bytes_left, 1, MAINBUF_SIZE - bytes_left, fp);
ESP_GOTO_ON_FALSE(bytes_read > 0, ESP_OK, clean_up, TAG, "No data read from strorage device");
bytes_left = bytes_left + bytes_read;
read_ptr = read_buf;
}
/* Find MP3 sync word from read buffer */
int offset = MP3FindSyncWord(read_buf, MAINBUF_SIZE);
if (offset >= 0) {
read_ptr += offset; /*!< Data start point */
bytes_left -= offset; /*!< In buffer */
int mp3_dec_err = MP3Decode(mp3_decoder, &read_ptr, &bytes_left, (int16_t *) output, 0);
ESP_GOTO_ON_FALSE(ERR_MP3_NONE == mp3_dec_err, ESP_FAIL, clean_up, TAG, "Can't decode MP3 frame");
/* Get MP3 frame info and configure I2S clock */
MP3GetLastFrameInfo(mp3_decoder, &frame_info);
/* Configure I2S clock if sample rate changed. Always reconfigure at first frame */
if (sample_rate != frame_info.samprate ||
nChans != frame_info.nChans ||
bits_cfg != frame_info.bitsPerSample) {
sample_rate = frame_info.samprate;
bits_cfg = frame_info.bitsPerSample;
nChans = frame_info.nChans;
ESP_LOGI(TAG, "audio info: sr=%d, bit=%d, ch=%d", sample_rate, bits_cfg, nChans);
i2s_channel_t channel = (nChans == 1) ? I2S_CHANNEL_MONO : I2S_CHANNEL_STEREO;
i2s_set_clk(I2S_NUM_0, sample_rate, bits_cfg, channel);
// bsp_codec_set_fmt((nChans == 1) ? AUDIO_HAL_I2S_LEFT : AUDIO_HAL_I2S_NORMAL);
}
/* Write decoded data to audio decoder */
size_t i2s_bytes_written = 0;
size_t output_size = frame_info.outputSamps * nChans;
i2s_write(I2S_NUM_0, output, output_size, &i2s_bytes_written, portMAX_DELAY);
} else {
/* Sync word not found in frame. Try to read next frame */
ESP_LOGE(TAG, "MP3 sync word not found");
bytes_left = 0;
continue;
}
} while (true);
clean_up:
/* This will prevent from sending dumy data to audio decoder */
i2s_zero_dma_buffer(I2S_NUM_0);
/* Clean up resources */
if (NULL != mp3_decoder) {
MP3FreeDecoder(mp3_decoder);
}
if (NULL != fp) {
fclose(fp);
}
if (NULL != read_buf) {
free(read_buf);
}
if (NULL != output) {
free(output);
}
return ret;
}
static void audio_task(void *pvParam)
{
char *base_path = (char *) pvParam;
fm_init(base_path);
/* Scan audio file */
fm_print_dir(base_path, 2);
fm_file_table_create(&g_file_list, &g_file_num, ".mp3");
for (size_t i = 0; i < g_file_num; i++) {
ESP_LOGI(TAG, "have file [%d:%s]", i, g_file_list[i]);
}
if (0 == g_file_num) {
ESP_LOGW(TAG, "Can't found any mp3 file!");
vTaskDelete(NULL);
}
if (esp_ptr_executable(s_audio_cb)) {
player_cb_ctx_t ctx = {
.audio_event = AUDIO_EVENT_FILE_SCAN_DONE,
.user_ctx = audio_cb_usrt_ctx,
};
s_audio_cb(&ctx);
}
/* Audio control event queue */
audio_event_queue = xQueueCreate(4, sizeof(player_event_t));
if (NULL == audio_event_queue) {
vTaskDelete(NULL);
}
/* Get name of first song to play */
char full_name[256];
memset(full_name, '\0', sizeof(full_name));
strcpy(full_name, base_path);
strcat(full_name, "/");
strcat(full_name, app_player_get_name_from_index(audio_index));
/* Default state is pause */
app_player_pause();
/* Start play music */
while (1) {
esp_err_t ret_val = play_mp3(full_name);
/* Get next audio's name if audio played without error */
if (ESP_OK == ret_val) {
audio_index ++;
if (audio_index >= g_file_num) {
audio_index = 0;
}
}
/* Callback for audio index change */
if (esp_ptr_executable(s_audio_cb)) {
player_cb_ctx_t ctx = {
.audio_event = AUDIO_EVENT_CHANGE,
.user_ctx = audio_cb_usrt_ctx,
};
s_audio_cb(&ctx);
}
/* Get next song's file name */
memset(full_name, '\0', sizeof(full_name));
strcpy(full_name, base_path);
strcat(full_name, "/");
strcat(full_name, app_player_get_name_from_index(audio_index));
}
/* Task never returns */
vTaskDelete(NULL);
}
/* **************** AUDIO PLAY CONTROL **************** */
esp_err_t app_player_play(void)
{
ESP_RETURN_ON_FALSE(NULL != audio_event_queue, ESP_ERR_INVALID_STATE, TAG, "Audio task not started yet");
player_event_t event = AUDIO_EVENT_PLAY;
BaseType_t ret_val = xQueueSend(audio_event_queue, &event, 0);
ESP_RETURN_ON_FALSE(pdPASS == ret_val, ESP_ERR_INVALID_STATE, TAG, "The last event has not been processed yet");
return ESP_OK;
}
esp_err_t app_player_pause(void)
{
ESP_RETURN_ON_FALSE(NULL != audio_event_queue, ESP_ERR_INVALID_STATE, TAG, "Audio task not started yet");
player_event_t event = AUDIO_EVENT_PAUSE;
BaseType_t ret_val = xQueueSend(audio_event_queue, &event, 0);
ESP_RETURN_ON_FALSE(pdPASS == ret_val, ESP_ERR_INVALID_STATE, TAG, "The last event has not been processed yet");
return ESP_OK;
}
esp_err_t app_player_play_next(void)
{
ESP_RETURN_ON_FALSE(NULL != audio_event_queue, ESP_ERR_INVALID_STATE, TAG, "Audio task not started yet");
audio_index ++;
if (audio_index >= g_file_num) {
audio_index = 0;
}
player_event_t event = AUDIO_EVENT_NEXT;
BaseType_t ret_val = xQueueSend(audio_event_queue, &event, 0);
ESP_RETURN_ON_FALSE(pdPASS == ret_val, ESP_ERR_INVALID_STATE, TAG, "The last event has not been processed yet");
return ESP_OK;
}
esp_err_t app_player_play_prev(void)
{
ESP_RETURN_ON_FALSE(NULL != audio_event_queue, ESP_ERR_INVALID_STATE, TAG, "Audio task not started yet");
if (audio_index == 0) {
audio_index = g_file_num;
}
audio_index--;
player_event_t event = AUDIO_EVENT_PREV;
BaseType_t ret_val = xQueueSend(audio_event_queue, &event, 0);
ESP_RETURN_ON_FALSE(pdPASS == ret_val, ESP_ERR_INVALID_STATE, TAG, "The last event has not been processed yet");
return ESP_OK;
}
esp_err_t app_player_play_index(size_t index)
{
ESP_RETURN_ON_FALSE(NULL != audio_event_queue, ESP_ERR_INVALID_STATE, TAG, "Audio task not started yet");
ESP_RETURN_ON_FALSE(index < g_file_num, ESP_ERR_INVALID_ARG, TAG, "File index out of range");
audio_index = index;
player_event_t event = AUDIO_EVENT_CHANGE;
BaseType_t ret_val = xQueueSend(audio_event_queue, &event, 0);
ESP_RETURN_ON_FALSE(pdPASS == ret_val, ESP_ERR_INVALID_STATE, TAG, "The last event has not been processed yet");
return ESP_OK;
}
/* **************** START AUDIO PLAYER **************** */
esp_err_t app_player_start(char *file_path)
{
ESP_RETURN_ON_FALSE(NULL != file_path, ESP_ERR_INVALID_ARG, TAG, "Invalid base path");
BaseType_t ret_val = xTaskCreatePinnedToCore(audio_task, "Audio Task", 4 * 1024, file_path, configMAX_PRIORITIES - 5, NULL, 1);
ESP_RETURN_ON_FALSE(pdPASS == ret_val, ESP_FAIL, TAG, "Failed create audio task");
return ESP_OK;
}
player_state_t app_player_get_state(void)
{
return g_player_state;
}
@@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#pragma once
#include <stddef.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
AUDIO_EVENT_NONE = 0,
AUDIO_EVENT_PAUSE,
AUDIO_EVENT_PLAY,
AUDIO_EVENT_NEXT,
AUDIO_EVENT_PREV,
AUDIO_EVENT_CHANGE,
AUDIO_EVENT_FILE_SCAN_DONE,
AUDIO_EVENT_MAX,
} player_event_t;
typedef enum {
PLAYER_STATE_IDLE,
PLAYER_STATE_PLAYING,
PLAYER_STATE_PAUSE,
} player_state_t;
typedef struct {
player_event_t audio_event;
void *user_ctx;
} player_cb_ctx_t;
/* Audio callback function type */
typedef void (*audio_cb_t)(player_cb_ctx_t *);
esp_err_t app_player_start(char *file_path);
esp_err_t app_player_play(void);
esp_err_t app_player_pause(void);
player_state_t app_player_get_state(void);
esp_err_t app_player_play_next(void);
esp_err_t app_player_play_prev(void);
esp_err_t app_player_play_index(size_t index);
size_t app_player_get_index(void);
const char *app_player_get_name_from_index(size_t index);
esp_err_t app_player_callback_register(audio_cb_t call_back, void *user_ctx);
#ifdef __cplusplus
}
#endif
-259
View File
@@ -1,259 +0,0 @@
/**
* @file app_server.c
* @brief
* @version 0.1
* @date 2021-09-26
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include "app_led.h"
#include "app_data_parse.h"
#include "cJSON.h"
#include "esp_err.h"
#include "esp_http_server.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_vfs.h"
#include "cJSON.h"
#include "ui_lang.h"
static const char *TAG = "esp-rest";
#define REST_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
#define FILE_PATH_MAX (128)
#define SCRATCH_BUFSIZE (4096)
typedef struct rest_server_context {
char base_path[ESP_VFS_PATH_MAX];
char scratch[SCRATCH_BUFSIZE];
} rest_server_context_t;
#define CHECK_FILE_EXTENSION(filename, ext) (strcasecmp(&filename[strlen(filename) - strlen(ext)], ext) == 0)
/* Set HTTP response content type according to file extension */
static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filepath)
{
const char *type = "text/plain";
if (CHECK_FILE_EXTENSION(filepath, ".html")) {
type = "text/html";
} else if (CHECK_FILE_EXTENSION(filepath, ".js")) {
type = "application/javascript";
} else if (CHECK_FILE_EXTENSION(filepath, ".css")) {
type = "text/css";
} else if (CHECK_FILE_EXTENSION(filepath, ".png")) {
type = "image/png";
} else if (CHECK_FILE_EXTENSION(filepath, ".ico")) {
type = "image/x-icon";
} else if (CHECK_FILE_EXTENSION(filepath, ".svg")) {
type = "text/xml";
}
return httpd_resp_set_type(req, type);
}
/* Send HTTP response with the contents of the requested file */
static esp_err_t rest_common_get_handler(httpd_req_t *req)
{
ESP_LOGW(TAG, "%s", __func__);
ESP_LOGI(TAG, "%s", req->uri);
char filepath[128];
rest_server_context_t *rest_context = (rest_server_context_t *)req->user_ctx;
strlcpy(filepath, rest_context->base_path, sizeof(filepath));
if (req->uri[strlen(req->uri) - 1] == '/') {
strlcat(filepath, INDEX_NAME, sizeof(filepath));
} else {
strlcat(filepath, req->uri, sizeof(filepath));
}
int fd = open(filepath, O_RDONLY, 0);
if (fd == -1) {
ESP_LOGE(TAG, "Failed to open file : %s", filepath);
/* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to read existing file");
return ESP_FAIL;
}
set_content_type_from_file(req, filepath);
char *chunk = rest_context->scratch;
int read_bytes;
do {
/* Read file in chunks into the scratch buffer */
read_bytes = read(fd, chunk, SCRATCH_BUFSIZE);
if (read_bytes == -1) {
ESP_LOGE(TAG, "Failed to read file : %s", filepath);
} else if (read_bytes > 0) {
/* Send the buffer contents as HTTP response chunk */
if (httpd_resp_send_chunk(req, chunk, read_bytes) != ESP_OK) {
close(fd);
ESP_LOGE(TAG, "File sending failed!");
/* Abort sending file */
httpd_resp_sendstr_chunk(req, NULL);
/* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to send file");
return ESP_FAIL;
}
}
} while (read_bytes > 0);
/* Close file after sending complete */
close(fd);
ESP_LOGI(TAG, "File sending complete");
/* Respond with an empty chunk to signal HTTP response completion */
httpd_resp_send_chunk(req, NULL, 0);
return ESP_OK;
}
static esp_err_t put_nodes_params(httpd_req_t *req)
{
ESP_LOGW(TAG, "%s", __func__);
int total_len = req->content_len;
int cur_len = 0;
char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch;
int received = 0;
static const char *resp_data =
"{"
"\"status\":\"success\","
"\"description\":\"Success description\""
"}";
if (total_len >= SCRATCH_BUFSIZE) {
/* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long");
return ESP_FAIL;
}
while (cur_len < total_len) {
received = httpd_req_recv(req, buf + cur_len, total_len);
if (received <= 0) {
/* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to post control value");
return ESP_FAIL;
}
cur_len += received;
}
buf[total_len] = '\0';
ESP_LOGI(TAG, "Server -> Client (%d) : %s", strlen(buf), buf);
app_wifi_parse_json_string((char *) buf);
httpd_resp_sendstr(req, resp_data);
return ESP_OK;
}
static esp_err_t put_nodes_get(httpd_req_t *req)
{
ESP_LOGW(TAG, "%s", __func__);
char *json_string = NULL;
led_state_t led_state;
app_led_get_state(&led_state);
app_wifi_build_json_string(&led_state, &json_string);
ESP_LOGI(TAG, "Client -> Server (%d) : %s", strlen(json_string), json_string);
httpd_resp_sendstr(req, json_string);
free(json_string);
return ESP_OK;
}
static esp_err_t get_nodes_params(httpd_req_t *req)
{
ESP_LOGW(TAG, "%s", __func__);
return ESP_OK;
}
esp_err_t start_rest_server(const char *base_path)
{
REST_CHECK(base_path, "wrong base path", err);
rest_server_context_t *rest_context = heap_caps_calloc(1, sizeof(rest_server_context_t), MALLOC_CAP_INTERNAL);
REST_CHECK(rest_context, "No memory for rest context", err);
strlcpy(rest_context->base_path, base_path, sizeof(rest_context->base_path));
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.recv_wait_timeout = 30;
config.uri_match_fn = httpd_uri_match_wildcard;
ESP_LOGI(TAG, "Starting HTTP Server");
REST_CHECK(httpd_start(&server, &config) == ESP_OK, "Start server failed", err_start);
/* URI handler for fetching system info */
httpd_uri_t put_params_uri = {
.uri = "/v1/user/nodes/params",
.method = HTTP_PUT,
.handler = put_nodes_params,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &put_params_uri);
/* URI handler for fetching system info */
httpd_uri_t get_params_uri = {
.uri = "/v1/user/nodes/info",
.method = HTTP_GET,
.handler = put_nodes_get,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &get_params_uri);
static const httpd_uri_t debug_recv_uri = {
.uri = "/v1/user/nodes/params",
.method = HTTP_GET,
.handler = get_nodes_params,
.user_ctx = NULL,
.is_websocket = true
};
httpd_register_uri_handler(server, &debug_recv_uri);
httpd_uri_t common_get_uri = {
.uri = "/*",
.method = HTTP_GET,
.handler = rest_common_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &common_get_uri);
return ESP_OK;
err_start:
free(rest_context);
err:
return ESP_FAIL;
}
+135
View File
@@ -0,0 +1,135 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_attr.h"
#include "esp_sleep.h"
#include "nvs_flash.h"
#include "esp_sntp.h"
static const char *TAG = "sntp";
/* Variable holding number of times ESP32 restarted since first boot.
* It is placed into RTC memory using RTC_DATA_ATTR and
* maintains its value when ESP32 wakes from deep sleep.
*/
RTC_DATA_ATTR static int boot_count = 0;
static void obtain_time(void);
static void initialize_sntp(void);
#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_CUSTOM
void sntp_sync_time(struct timeval *tv)
{
settimeofday(tv, NULL);
ESP_LOGI(TAG, "Time is synchronized from custom code");
sntp_set_sync_status(SNTP_SYNC_STATUS_COMPLETED);
}
#endif
static void time_sync_notification_cb(struct timeval *tv)
{
ESP_LOGI(TAG, "Notification of a time synchronization event, sec=%lu", tv->tv_sec);
settimeofday(tv, NULL);
}
void app_sntp_init(void)
{
++boot_count;
ESP_LOGI(TAG, "Boot count: %d", boot_count);
time_t now;
struct tm timeinfo;
time(&now);
localtime_r(&now, &timeinfo);
// Set timezone to China Standard Time
setenv("TZ", "CST-8", 1);
tzset();
// Is time set? If not, tm_year will be (1970 - 1900).
if (timeinfo.tm_year < (2016 - 1900)) {
ESP_LOGI(TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP.");
obtain_time();
// update 'now' variable with current time
time(&now);
}
#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH
else {
// add 500 ms error to the current system time.
// Only to demonstrate a work of adjusting method!
{
ESP_LOGI(TAG, "Add a error for test adjtime");
struct timeval tv_now;
gettimeofday(&tv_now, NULL);
int64_t cpu_time = (int64_t)tv_now.tv_sec * 1000000L + (int64_t)tv_now.tv_usec;
int64_t error_time = cpu_time + 500 * 1000L;
struct timeval tv_error = {.tv_sec = error_time / 1000000L, .tv_usec = error_time % 1000000L};
settimeofday(&tv_error, NULL);
}
ESP_LOGI(TAG, "Time was set, now just adjusting it. Use SMOOTH SYNC method.");
obtain_time();
// update 'now' variable with current time
time(&now);
}
#endif
char strftime_buf[64];
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
ESP_LOGI(TAG, "The current date/time in Shanghai is: %s", strftime_buf);
if (sntp_get_sync_mode() == SNTP_SYNC_MODE_SMOOTH) {
struct timeval outdelta;
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_IN_PROGRESS) {
adjtime(NULL, &outdelta);
ESP_LOGI(TAG, "Waiting for adjusting time ... outdelta = %li sec: %li ms: %li us",
(long)outdelta.tv_sec,
outdelta.tv_usec / 1000,
outdelta.tv_usec % 1000);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
}
static void obtain_time(void)
{
initialize_sntp();
// wait for time to be set
time_t now = 0;
struct tm timeinfo = {0};
int retry = 0;
const int retry_count = 10;
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) {
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
time(&now);
localtime_r(&now, &timeinfo);
}
static void initialize_sntp(void)
{
ESP_LOGI(TAG, "Initializing SNTP");
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "ntp.aliyun.com");
sntp_setservername(1, "time.asia.apple.com");
sntp_setservername(2, "pool.ntp.org");
sntp_set_time_sync_notification_cb(time_sync_notification_cb);
#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH
sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH);
#endif
sntp_init();
}
+21
View File
@@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#ifndef _APP_SNTP_H_
#define _APP_SNTP_H_
#ifdef __cplusplus
extern "C" {
#endif
void app_sntp_init(void);
#ifdef __cplusplus
}
#endif
#endif
+534 -191
View File
@@ -1,22 +1,7 @@
/**
* @file app_sr.c
* @brief
* @version 0.1
* @date 2021-09-19
*
* @copyright Copyright 2021 Espressif Systems (Shanghai) Co. Ltd.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdbool.h>
@@ -24,71 +9,210 @@
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include "app_audio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#include "driver/i2s.h"
#include "esp_task_wdt.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_log.h"
#include "app_sr.h"
#include "bsp_codec.h"
#include "bsp_i2s.h"
#include "driver/i2s.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_afe_sr_models.h"
#include "esp_mn_models.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#define SR_CMD_TIME_OUT (-2)
#define SR_CMD_NOT_DETECTED (-1)
#define SR_CMD_ID_BASE (0)
#define I2S_CHANNEL_NUM (2)
#include "app_sr_handler.h"
#include "bsp_board.h"
#include "bsp_btn.h"
#include "settings.h"
static const char *TAG = "app_sr";
static afe_config_t afe_config = {
.aec_init = false,
.se_init = true,
.vad_init = false,
.wakenet_init = true,
.vad_mode = 3,
.wakenet_model = (esp_wn_iface_t *) &WAKENET_MODEL,
.wakenet_coeff = (model_coeff_getter_t *) &WAKENET_COEFF,
.wakenet_mode = DET_MODE_2CH_90,
.afe_mode = SR_MODE_LOW_COST,
.afe_perferred_core = 0,
.afe_perferred_priority = 8,
.afe_ringbuf_size = 50,
.alloc_from_psram = 1,
.agc_mode = 2, /* 1 : -5dB 2: -4dB ... */
typedef struct {
sr_language_t lang;
model_iface_data_t *model_data;
const esp_mn_iface_t *multinet;
const esp_afe_sr_iface_t *afe_handle;
esp_afe_sr_data_t *afe_data;
int16_t *afe_in_buffer;
int16_t *afe_out_buffer;
SLIST_HEAD(sr_cmd_list_t, sr_cmd_t) cmd_list;
uint8_t cmd_num;
TaskHandle_t feed_task;
TaskHandle_t detect_task;
TaskHandle_t handle_task;
QueueHandle_t result_que;
EventGroupHandle_t event_group;
FILE *fp;
bool b_record_en;
} sr_data_t;
static sr_data_t *g_sr_data = NULL;
#define I2S_CHANNEL_NUM (2)
#define NEED_DELETE BIT0
#define FEED_DELETED BIT1
#define DETECT_DELETED BIT2
/**
* @brief all default commands
*/
static const sr_cmd_t g_default_cmd_info[] = {
// English
{SR_CMD_LIGHT_ON, SR_LANG_EN, 0, "Turn On the Light", "TkN nN jc LiT", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_EN, 0, "Switch On the Light", "SWgp nN jc LiT", {NULL}},
{SR_CMD_LIGHT_OFF, SR_LANG_EN, 0, "Switch Off the Light", "SWgp eF jc LiT", {NULL}},
{SR_CMD_LIGHT_OFF, SR_LANG_EN, 0, "Turn Off the Light", "TkN eF jc LiT", {NULL}},
{SR_CMD_SET_RED, SR_LANG_EN, 0, "Turn Red", "TkN RfD", {NULL}},
{SR_CMD_SET_GREEN, SR_LANG_EN, 0, "Turn Green", "TkN GRmN", {NULL}},
{SR_CMD_SET_BLUE, SR_LANG_EN, 0, "Turn Blue", "TkN BLo", {NULL}},
{SR_CMD_CUSTOMIZE_COLOR, SR_LANG_EN, 0, "Customize Color", "KcSTcMiZ KcLk", {NULL}},
{SR_CMD_PLAY, SR_LANG_EN, 0, "Sing a song", "Sgl c Sel", {NULL}},
{SR_CMD_PLAY, SR_LANG_EN, 0, "Play Music", "PLd MYoZgK", {NULL}},
{SR_CMD_NEXT, SR_LANG_EN, 0, "Next Song", "NfKST Sel", {NULL}},
{SR_CMD_PAUSE, SR_LANG_EN, 0, "Pause Playing", "PeZ PLdgl", {NULL}},
// Chinese
#if SR_RUN_TEST
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_cha ba ji kai ji", "cha ba ji kai ji", {NULL}},
{SR_CMD_LIGHT_OFF, SR_LANG_CN, 0, "T_cha ba ji guan ji", "cha ba ji guan ji", {NULL}},
{SR_CMD_CUSTOMIZE_COLOR, SR_LANG_CN, 0, "T_you bian jia shui", "you bian jia shui", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_you bian qu shui", "you bian qu shui", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_ting zhi qu shui", "ting zhi qu shui", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_shui hu jia re", "shui hu jia re", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_ting zhi jia re", "ting zhi jia re", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_zuo bian jia shui", "zuo bian jia shui", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_zuo bian qu shui", "zuo bian qu shui", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_kai shi bao wen", "kai shi bao wen", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_bao wen mo shi", "bao wen mo shi", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_kai shi zhi leng", "kai shi zhi leng", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_zhi leng mo shi", "zhi leng mo shi", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_kai si zi leng", "kai si zi leng", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_zi leng mo shi", "zi leng mo shi", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_ting zhi bao wen", "ting zhi bao wen", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_guan bi bao wen", "guan bi bao wen", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_ting zhi zhi leng", "ting zhi zhi leng", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_guan bi zhi leng", "guan bi zhi leng", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_zui da yin liang", "zui da yin liang", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_zui xiao yin liang", "zui xiao yin liang", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_hua cha mo shi", "hua cha mo shi", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_guo cha mo shi", "guo cha mo shi", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_hong cha mo shi", "hong cha mo shi", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_lv cha mo shi", "lv cha mo shi", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_tui chu zhu cha mo shi", "tui chu zhu cha mo shi", {NULL}},
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "T_ting zhi zhu cha", "ting zhi zhu cha", {NULL}},
#else
{SR_CMD_LIGHT_ON, SR_LANG_CN, 0, "打开电灯", "da kai dian deng", {NULL}},
{SR_CMD_LIGHT_OFF, SR_LANG_CN, 0, "关闭电灯", "guan bi dian deng", {NULL}},
{SR_CMD_SET_RED, SR_LANG_CN, 0, "调成红色", "tiao cheng hong se", {NULL}},
{SR_CMD_SET_GREEN, SR_LANG_CN, 0, "调成绿色", "tiao cheng lv se", {NULL}},
{SR_CMD_SET_BLUE, SR_LANG_CN, 0, "调成蓝色", "tiao cheng lan se", {NULL}},
{SR_CMD_CUSTOMIZE_COLOR, SR_LANG_CN, 0, "自定义颜色", "zi ding yi yan se", {NULL}},
{SR_CMD_PLAY, SR_LANG_CN, 0, "播放音乐", "bo fang yin yue", {NULL}},
{SR_CMD_NEXT, SR_LANG_CN, 0, "切歌", "qie ge", {NULL}},
{SR_CMD_NEXT, SR_LANG_CN, 0, "下一曲", "xia yi qv", {NULL}},
{SR_CMD_PAUSE, SR_LANG_CN, 0, "暂停", "zan ting", {NULL}},
{SR_CMD_PAUSE, SR_LANG_CN, 0, "暂停播放", "zan ting bo fang", {NULL}},
{SR_CMD_PAUSE, SR_LANG_CN, 0, "停止播放", "ting zhi bo fang", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "打开空调", "da kai kong tiao", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "关闭空调", "guan bi kong tiao", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "舒适模式", "shu shi mo shi", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "制冷模式", "zhi leng mo shi", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "制热模式", "zhi re mo shi", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "加热模式", "jia re mo shi", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "除湿模式", "chu shi mo shi", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "送风模式", "song feng mo shi", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "升高温度", "sheng gao wen du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "降低温度", "jiang di wen du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "温度调到最高", "wen du tiao dao zui gao", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "温度调到最低", "wen du tiao dao zui di", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "太热了", "tai re le", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "太冷了", "tai leng le", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "十六度", "shi liu du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "十七度", "shi qi du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "十八度", "shi ba du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "十九度", "shi jiu du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "二十度", "er shi du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "二十一度", "er shi yi du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "二十二度", "er shi er du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "二十三度", "er shi san du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "二十四度", "er shi si du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "二十五度", "er shi wu du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "二十六度", "er shi liu du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "二十七度", "er shi qi du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "二十八度", "er shi ba du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "二十九度", "er shi jiu du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "三十度", "san shi du", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "增大风速", "zeng da feng su", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "减小风速", "jian xiao feng su", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "高速风", "gao su feng", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "中速风", "zhong su feng", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "低速风", "di su feng", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "自动风", "zi dong feng", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "打开左右摆风", "da kai zuo you bai feng", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "打开上下摆风", "da kai shang xia bai feng", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "关闭左右摆风", "guan bi zuo you bai feng", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "关闭上下摆风", "guan bi shang xia bai feng", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "打开辅热", "da kai fu re", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "关闭辅热", "guan bi fu re", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "打开自清洁", "da kai zi qing jie", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "关闭自清洁", "guan bi zi qing jie", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "打开静音", "da kai jing yin", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "关闭静音", "guan bi jing yin", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "音量大点", "yin liang da dian", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "音量小点", "yin liang xiao dian", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "音量调到最大", "yin liang diao dao zui da", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "音量调到最小", "yin liang diao dao zui xiao", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "打开卧室灯", "da kai wo shi deng", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "关闭卧室灯", "guan bi wo shi deng", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "打开客厅灯", "da kai ke ting deng", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "关闭客厅灯", "guan bi ke ting deng", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "打开音箱", "da kai yin xiang", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "关闭音箱", "guan bi yin xiang", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "拉开窗帘", "la kai chuang lian", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "关闭窗帘", "guan bi chuang lian", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "打开风扇", "da kai feng shan", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "关闭风扇", "guan bi feng shan", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "打开饮水机插座", "da kai yin shui ji cha zuo", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "关闭饮水机插座", "guan bi yin shui ji cha zuo", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "打开投影仪", "da kai tou ying yi", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "关闭投影仪", "guan bi tou ying yi", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "灯光调暗", "deng guang diao an", {NULL}},
{SR_CMD_MAX, SR_LANG_CN, 0, "灯光调亮", "deng guang diao liang", {NULL}},
#endif
};
static model_iface_data_t *model_data = NULL;
static const esp_mn_iface_t *multinet = &MULTINET_MODEL;
static const esp_afe_sr_iface_t *afe_handle = &esp_afe_sr_2mic;
static FILE *fp = NULL;
static bool b_record_en = false;
static volatile int32_t sr_command_id = -1;
static EventGroupHandle_t sr_event_group_handle = NULL;
static void audio_feed_task(void *pvParam)
{
size_t bytes_read = 0;
const esp_afe_sr_iface_t *afe_handle = g_sr_data->afe_handle;
esp_afe_sr_data_t *afe_data = (esp_afe_sr_data_t *) pvParam;
int audio_chunksize = afe_handle->get_feed_chunksize(afe_data);
int feed_channel = 3;
ESP_LOGI(TAG, "audio_chunksize=%d, feed_channel=%d", audio_chunksize, feed_channel);
/* Allocate audio buffer and check for result */
int16_t *audio_buffer = heap_caps_malloc(audio_chunksize * sizeof(int16_t) * 3, MALLOC_CAP_INTERNAL);
int16_t *audio_buffer = heap_caps_malloc(audio_chunksize * sizeof(int16_t) * feed_channel, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (NULL == audio_buffer) {
esp_system_abort("No mem for audio buffer");
}
g_sr_data->afe_in_buffer = audio_buffer;
while (true) {
if (NEED_DELETE && xEventGroupGetBits(g_sr_data->event_group)) {
xEventGroupSetBits(g_sr_data->event_group, FEED_DELETED);
vTaskDelete(NULL);
}
/* Read audio data from I2S bus */
i2s_read(I2S_NUM_0, audio_buffer, audio_chunksize * I2S_CHANNEL_NUM * sizeof(int16_t), &bytes_read, portMAX_DELAY);
/* Save audio data to file if record enabled */
if (b_record_en && (NULL != fp)) {
fwrite(audio_buffer, 1, audio_chunksize * I2S_CHANNEL_NUM * sizeof(int16_t), fp);
if (g_sr_data->b_record_en && (NULL != g_sr_data->fp)) {
fwrite(audio_buffer, 1, audio_chunksize * I2S_CHANNEL_NUM * sizeof(int16_t), g_sr_data->fp);
}
/* Channel Adjust */
@@ -101,12 +225,6 @@ static void audio_feed_task(void *pvParam)
/* Feed samples of an audio stream to the AFE_SR */
afe_handle->feed(afe_data, audio_buffer);
}
/* Clean up if audio feed ends */
afe_handle->destroy(afe_data);
/* Task never returns */
vTaskDelete(NULL);
}
static void audio_detect_task(void *pvParam)
@@ -115,68 +233,99 @@ static void audio_detect_task(void *pvParam)
esp_afe_sr_data_t *afe_data = (esp_afe_sr_data_t *) pvParam;
/* Allocate buffer for detection */
size_t afe_chunk_size = afe_handle->get_fetch_chunksize(afe_data);
int16_t *detect_buff = heap_caps_malloc(afe_chunk_size * sizeof(int16_t), MALLOC_CAP_INTERNAL);
if (NULL == detect_buff) {
size_t afe_chunk_size = g_sr_data->afe_handle->get_fetch_chunksize(afe_data);
g_sr_data->afe_out_buffer = heap_caps_malloc(afe_chunk_size * sizeof(int16_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (NULL == g_sr_data->afe_out_buffer) {
ESP_LOGE(TAG, "Expect : %zu, avaliable : %zu",
afe_chunk_size * sizeof(int16_t),
heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
afe_chunk_size * sizeof(int16_t),
heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
esp_system_abort("No mem for detect buffer");
}
/* Check for chunk size */
if (afe_chunk_size != multinet->get_samp_chunksize(model_data)) {
if (afe_chunk_size != g_sr_data->multinet->get_samp_chunksize(g_sr_data->model_data)) {
esp_system_abort("Invalid chunk size");
}
while (true) {
int ret_val = afe_handle->fetch(afe_data, detect_buff);
if (NEED_DELETE && xEventGroupGetBits(g_sr_data->event_group)) {
xEventGroupSetBits(g_sr_data->event_group, DETECT_DELETED);
vTaskDelete(g_sr_data->handle_task);
vTaskDelete(NULL);
}
afe_fetch_mode_t ret_val = g_sr_data->afe_handle->fetch(afe_data, g_sr_data->afe_out_buffer);
if (AFE_FETCH_WWE_DETECTED == ret_val) {
ESP_LOGI(TAG, LOG_BOLD(LOG_COLOR_GREEN) "Wakeword detected");
xEventGroupSetBits(sr_event_group_handle, SR_EVENT_WAKE_UP);
ESP_LOGI(TAG, LOG_BOLD(LOG_COLOR_GREEN) "wakeword detected");
sr_result_t result = {
.fetch_mode = ret_val,
.state = ESP_MN_STATE_DETECTING,
.command_id = 0,
};
xQueueSend(g_sr_data->result_que, &result, 0);
}
if (AFE_FETCH_CHANNEL_VERIFIED == ret_val) {
ESP_LOGI(TAG, LOG_BOLD(LOG_COLOR_GREEN) "Channel verified");
detect_flag = true;
afe_handle->disable_wakenet(afe_data);
g_sr_data->afe_handle->disable_wakenet(afe_data);
}
if (true == detect_flag) {
/* Save audio data to file if record enabled */
if (b_record_en && (NULL != fp)) {
fwrite(detect_buff, 1, afe_chunk_size * sizeof(int16_t), fp);
if (g_sr_data->b_record_en && (NULL != g_sr_data->fp)) {
fwrite(g_sr_data->afe_out_buffer, 1, afe_chunk_size * sizeof(int16_t), g_sr_data->fp);
}
if (false == audio_is_playing()) {
sr_command_id = multinet->detect(model_data, detect_buff);
esp_mn_state_t mn_state = ESP_MN_STATE_DETECTING;
if (false == sr_echo_is_playing()) {
mn_state = g_sr_data->multinet->detect(g_sr_data->model_data, g_sr_data->afe_out_buffer);
} else {
continue;
}
if (SR_CMD_NOT_DETECTED == sr_command_id) {
if (ESP_MN_STATE_DETECTING == mn_state) {
continue;
}
if (SR_CMD_TIME_OUT == sr_command_id) {
ESP_LOGW(TAG, LOG_BOLD(LOG_COLOR_BROWN) "Time out");
xEventGroupSetBits(sr_event_group_handle, SR_EVENT_TIMEOUT);
afe_handle->enable_wakenet(afe_data);
if (ESP_MN_STATE_TIMEOUT == mn_state) {
ESP_LOGW(TAG, "Time out");
sr_result_t result = {
.fetch_mode = ret_val,
.state = mn_state,
.command_id = 0,
};
xQueueSend(g_sr_data->result_que, &result, 0);
g_sr_data->afe_handle->enable_wakenet(afe_data);
detect_flag = false;
continue;
}
if (SR_CMD_ID_BASE <= sr_command_id) {
ESP_LOGI(TAG, LOG_BOLD(LOG_COLOR_GREEN) "Deteted command : %d", sr_command_id);
xEventGroupSetBits(sr_event_group_handle, SR_EVENT_WORD_DETECT);
afe_handle->enable_wakenet(afe_data);
detect_flag = 0;
if (ESP_MN_STATE_DETECTED <= mn_state) {
esp_mn_results_t *mn_result = g_sr_data->multinet->get_results(g_sr_data->model_data);
for (int i = 0; i < mn_result->num; i++) {
ESP_LOGI(TAG, "TOP %d, command_id: %d, phrase_id: %d, prob: %f",
i + 1, mn_result->command_id[i], mn_result->phrase_id[i], mn_result->prob[i]);
}
if (b_record_en && (NULL != fp)) {
int sr_command_id = mn_result->command_id[0];
ESP_LOGI(TAG, "Deteted command : %d", sr_command_id);
sr_result_t result = {
.fetch_mode = ret_val,
.state = mn_state,
.command_id = sr_command_id,
};
xQueueSend(g_sr_data->result_que, &result, 0);
#if !SR_CONTINUE_DET
g_sr_data->afe_handle->enable_wakenet(afe_data);
detect_flag = 0;
#endif
if (g_sr_data->b_record_en && (NULL != g_sr_data->fp)) {
ESP_LOGI(TAG, "File saved");
fclose(fp);
fp = NULL;
fclose(g_sr_data->fp);
g_sr_data->fp = NULL;
}
continue;
}
@@ -185,140 +334,334 @@ static void audio_detect_task(void *pvParam)
}
}
/* Clean up if audio feed ends */
afe_handle->destroy(afe_data);
/* Task never returns */
vTaskDelete(NULL);
}
static void sr_init_task(void *pvParam)
esp_err_t app_sr_set_language(sr_language_t new_lang)
{
(void) pvParam;
ESP_RETURN_ON_FALSE(NULL != g_sr_data, ESP_ERR_INVALID_STATE, TAG, "SR is not running");
ESP_ERROR_CHECK(bsp_i2s_init(I2S_NUM_0, 16000));
ESP_ERROR_CHECK(bsp_codec_init(AUDIO_HAL_16K_SAMPLES));
vTaskDelay(pdMS_TO_TICKS(4000));
esp_afe_sr_data_t *afe_data = afe_handle->create_from_config(&afe_config);
/* Continuously reading flash will call task watchdog */
vTaskDelay(pdMS_TO_TICKS(100));
model_data = multinet->create((const model_coeff_getter_t *) &MULTINET_COEFF, 5760);
/* Create audio feed task. Acquire data from I2S bus */
BaseType_t ret_val = xTaskCreatePinnedToCore(
(TaskFunction_t) audio_feed_task,
(const char * const) "Feed Task",
(const uint32_t) 2 * 1024,
(void * const) afe_data,
(UBaseType_t) 5,
(TaskHandle_t * const) NULL,
(const BaseType_t) 1);
if (pdPASS != ret_val) {
ESP_LOGE(TAG, "Failed create audio feed task");
return;
if (new_lang == g_sr_data->lang) {
ESP_LOGW(TAG, "nothing to do");
return ESP_OK;
} else {
g_sr_data->lang = new_lang;
}
/* Create audio detect task. Detect data fetch from buffer */
ret_val = xTaskCreatePinnedToCore(
(TaskFunction_t) audio_detect_task,
(const char * const) "Detect Task",
(const uint32_t) 5 * 1024,
(void * const) afe_data,
(UBaseType_t) 5,
(TaskHandle_t * const) NULL,
(const BaseType_t) 1);
if (pdPASS != ret_val) {
ESP_LOGE(TAG, "Failed create audio detect task");
return;
ESP_LOGW(TAG, "Set language to %s", SR_LANG_EN == g_sr_data->lang ? "EN" : "CN");
if (g_sr_data->model_data) {
g_sr_data->multinet->destroy(g_sr_data->model_data);
}
switch (g_sr_data->lang) {
case SR_LANG_EN:
g_sr_data->afe_handle->set_wakenet(g_sr_data->afe_data, FIRST_WAKE_WORD);
g_sr_data->multinet = &MULTINET_MODEL_EN;
g_sr_data->model_data = g_sr_data->multinet->create((const model_coeff_getter_t *) &MULTINET_COEFF_EN, 5760);
break;
case SR_LANG_CN:
g_sr_data->afe_handle->set_wakenet(g_sr_data->afe_data, SECOND_WAKE_WORD);
g_sr_data->multinet = &MULTINET_MODEL_CN;
g_sr_data->model_data = g_sr_data->multinet->create((const model_coeff_getter_t *) &MULTINET_COEFF_CN, 5760);
break;
default:
break;
}
/* Create audio detect task. Detect data fetch from buffer */
extern void sr_handler_task(void *pvParam);
ret_val = xTaskCreatePinnedToCore(
(TaskFunction_t) sr_handler_task,
(const char * const) "SR Handler Task",
(const uint32_t) 5 * 1024,
(void * const) sr_event_group_handle,
(UBaseType_t) 1,
(TaskHandle_t * const) NULL,
(const BaseType_t) 0);
if (pdPASS != ret_val) {
ESP_LOGE(TAG, "Failed create audio detect task");
return;
// remove all command
sr_cmd_t *it;
while (!SLIST_EMPTY(&g_sr_data->cmd_list)) {
it = SLIST_FIRST(&g_sr_data->cmd_list);
SLIST_REMOVE_HEAD(&g_sr_data->cmd_list, next);
heap_caps_free(it);
}
vTaskDelete(NULL);
uint8_t cmd_number = 0;
// count command number
for (size_t i = 0; i < sizeof(g_default_cmd_info) / sizeof(sr_cmd_t); i++) {
if (g_default_cmd_info[i].lang == g_sr_data->lang) {
cmd_number++;
app_sr_add_cmd(&g_default_cmd_info[i]);
}
}
ESP_LOGI(TAG, "cmd_number=%d", cmd_number);
return app_sr_update_cmds();/* Reset command list */
}
esp_err_t app_sr_start(bool record_en)
{
sr_event_group_handle = xEventGroupCreate();
if (NULL == sr_event_group_handle) {
ESP_LOGE(TAG, "Failed create event group");
return ESP_ERR_NO_MEM;
}
esp_err_t ret = ESP_OK;
ESP_RETURN_ON_FALSE(NULL == g_sr_data, ESP_ERR_INVALID_STATE, TAG, "SR already running");
g_sr_data = heap_caps_calloc(1, sizeof(sr_data_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
ESP_RETURN_ON_FALSE(NULL != g_sr_data, ESP_ERR_NO_MEM, TAG, "Failed create sr data");
g_sr_data->result_que = xQueueCreate(3, sizeof(sr_result_t));
ESP_GOTO_ON_FALSE(NULL != g_sr_data->result_que, ESP_ERR_NO_MEM, err, TAG, "Failed create result queue");
g_sr_data->event_group = xEventGroupCreate();
ESP_GOTO_ON_FALSE(NULL != g_sr_data->event_group, ESP_ERR_NO_MEM, err, TAG, "Failed create event_group");
SLIST_INIT(&g_sr_data->cmd_list);
/* Create file if record to SD card enabled*/
g_sr_data->b_record_en = record_en;
if (record_en) {
char file_name[32];
b_record_en = true;
for (size_t i = 0; i < 100; i++) {
sprintf(file_name, "/sdcard/Record_%02d.pcm", i);
fp = fopen(file_name, "r");
fclose(fp);
if (NULL == fp) {
g_sr_data->fp = fopen(file_name, "r");
fclose(g_sr_data->fp);
if (NULL == g_sr_data->fp) {
break;
}
}
fp = fopen(file_name, "w");
if (NULL == fp) {
ESP_LOGE(TAG, "Failed create file");
return ESP_FAIL;
} else {
ESP_LOGI(TAG, "File created : %s", file_name);
}
g_sr_data->fp = fopen(file_name, "w");
ESP_GOTO_ON_FALSE(NULL != g_sr_data->fp, ESP_FAIL, err, TAG, "Failed create record file");
ESP_LOGI(TAG, "File created at %s", file_name);
}
/* Create audio detect task. Detect data fetch from buffer */
BaseType_t ret_val = xTaskCreatePinnedToCore(
(TaskFunction_t) sr_init_task,
(const char * const) "SR Init Task",
(const uint32_t) 4 * 1024,
(void * const) NULL,
(UBaseType_t) 1,
(TaskHandle_t * const) NULL,
(const BaseType_t) 1);
if (pdPASS != ret_val) {
ESP_LOGE(TAG, "Failed create sr initialize task");
return ESP_FAIL;
esp_task_wdt_reset();
g_sr_data->afe_handle = &ESP_AFE_HANDLE;
afe_config_t afe_config = AFE_CONFIG_DEFAULT();
afe_config.aec_init = false;
// afe_config.vad_init = false;
g_sr_data->afe_data = g_sr_data->afe_handle->create_from_config(&afe_config);
const sys_param_t *param = settings_get_parameter();
g_sr_data->lang = SR_LANG_MAX;
ret = app_sr_set_language(param->sr_lang);
ESP_GOTO_ON_FALSE(ESP_OK == ret, ESP_FAIL, err, TAG, "Failed to set language");
BaseType_t ret_val = xTaskCreatePinnedToCore(audio_feed_task, "Feed Task", 4 * 1024, g_sr_data->afe_data, 5, &g_sr_data->feed_task, 1);
ESP_GOTO_ON_FALSE(pdPASS == ret_val, ESP_FAIL, err, TAG, "Failed create audio feed task");
ret_val = xTaskCreatePinnedToCore(audio_detect_task, "Detect Task", 6 * 1024, g_sr_data->afe_data, 5, &g_sr_data->detect_task, 1);
ESP_GOTO_ON_FALSE(pdPASS == ret_val, ESP_FAIL, err, TAG, "Failed create audio detect task");
ret_val = xTaskCreatePinnedToCore(sr_handler_task, "SR Handler Task", 4 * 1024, NULL, configMAX_PRIORITIES - 3, &g_sr_data->handle_task, 0);
ESP_GOTO_ON_FALSE(pdPASS == ret_val, ESP_FAIL, err, TAG, "Failed create audio handler task");
return ESP_OK;
err:
app_sr_stop();
return ret;
}
esp_err_t app_sr_stop(void)
{
ESP_RETURN_ON_FALSE(NULL != g_sr_data, ESP_ERR_INVALID_STATE, TAG, "SR is not running");
/**
* Waiting for all task stoped
* TODO: A task creation failure cannot be handled correctly now
* */
xEventGroupSetBits(g_sr_data->event_group, NEED_DELETE);
xEventGroupWaitBits(g_sr_data->event_group, NEED_DELETE | FEED_DELETED | DETECT_DELETED, 1, 1, portMAX_DELAY);
if (g_sr_data->result_que) {
vQueueDelete(g_sr_data->result_que);
g_sr_data->result_que = NULL;
}
if (g_sr_data->event_group) {
vEventGroupDelete(g_sr_data->event_group);
g_sr_data->event_group = NULL;
}
if (g_sr_data->fp) {
fclose(g_sr_data->fp);
g_sr_data->fp = NULL;
}
if (g_sr_data->model_data) {
g_sr_data->multinet->destroy(g_sr_data->model_data);
}
if (g_sr_data->afe_data) {
g_sr_data->afe_handle->destroy(g_sr_data->afe_data);
}
sr_cmd_t *it;
while (!SLIST_EMPTY(&g_sr_data->cmd_list)) {
it = SLIST_FIRST(&g_sr_data->cmd_list);
SLIST_REMOVE_HEAD(&g_sr_data->cmd_list, next);
heap_caps_free(it);
}
if (g_sr_data->afe_in_buffer) {
heap_caps_free(g_sr_data->afe_in_buffer);
}
if (g_sr_data->afe_out_buffer) {
heap_caps_free(g_sr_data->afe_out_buffer);
}
heap_caps_free(g_sr_data);
g_sr_data = NULL;
return ESP_OK;
}
int32_t app_sr_get_last_cmd_id(void)
esp_err_t app_sr_get_result(sr_result_t *result, TickType_t xTicksToWait)
{
return sr_command_id;
}
esp_err_t app_sr_reset_command_list(char *command_list)
{
char *err_id = heap_caps_malloc(1024, MALLOC_CAP_SPIRAM);
if (NULL == err_id) {
return ESP_ERR_NO_MEM;
}
multinet->reset(model_data, command_list, err_id);
free(err_id);
ESP_RETURN_ON_FALSE(NULL != g_sr_data, ESP_ERR_INVALID_STATE, TAG, "SR is not running");
xQueueReceive(g_sr_data->result_que, result, xTicksToWait);
return ESP_OK;
}
esp_err_t app_sr_add_cmd(const sr_cmd_t *cmd)
{
ESP_RETURN_ON_FALSE(NULL != g_sr_data, ESP_ERR_INVALID_STATE, TAG, "SR is not running");
ESP_RETURN_ON_FALSE(NULL != cmd, ESP_ERR_INVALID_ARG, TAG, "pointer of cmd is invaild");
ESP_RETURN_ON_FALSE(cmd->lang == g_sr_data->lang, ESP_ERR_INVALID_ARG, TAG, "cmd lang error");
ESP_RETURN_ON_FALSE(200 >= g_sr_data->cmd_num, ESP_ERR_INVALID_STATE, TAG, "cmd is full");
sr_cmd_t *item = (sr_cmd_t *)heap_caps_calloc(1, sizeof(sr_cmd_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
ESP_RETURN_ON_FALSE(NULL != item, ESP_ERR_NO_MEM, TAG, "memory for sr cmd is not enough");
memcpy(item, cmd, sizeof(sr_cmd_t));
item->next.sle_next = NULL;
#if 1 // insert after
sr_cmd_t *last = SLIST_FIRST(&g_sr_data->cmd_list);
if (last == NULL) {
SLIST_INSERT_HEAD(&g_sr_data->cmd_list, item, next);
} else {
sr_cmd_t *it;
while ((it = SLIST_NEXT(last, next)) != NULL) {
last = it;
}
SLIST_INSERT_AFTER(last, item, next);
}
#else // insert head
SLIST_INSERT_HEAD(&g_sr_data->cmd_list, it, next);
#endif
g_sr_data->cmd_num++;
return ESP_OK;
}
esp_err_t app_sr_modify_cmd(uint32_t id, const sr_cmd_t *cmd)
{
ESP_RETURN_ON_FALSE(NULL != g_sr_data, ESP_ERR_INVALID_STATE, TAG, "SR is not running");
ESP_RETURN_ON_FALSE(NULL != cmd, ESP_ERR_INVALID_ARG, TAG, "pointer of cmd is invaild");
ESP_RETURN_ON_FALSE(id < g_sr_data->cmd_num, ESP_ERR_INVALID_ARG, TAG, "cmd id out of range");
ESP_RETURN_ON_FALSE(cmd->lang == g_sr_data->lang, ESP_ERR_INVALID_ARG, TAG, "cmd lang error");
sr_cmd_t *it;
SLIST_FOREACH(it, &g_sr_data->cmd_list, next) {
if (it->id == id) {
ESP_LOGI(TAG, "modify cmd [%d] from %s to %s", id, it->str, cmd->str);
memcpy(it, cmd, sizeof(sr_cmd_t));
break;
}
}
ESP_RETURN_ON_FALSE(NULL != it, ESP_ERR_NOT_FOUND, TAG, "can't find cmd id:%d", cmd->id);
return ESP_OK;
}
esp_err_t app_sr_remove_cmd(uint32_t id)
{
ESP_RETURN_ON_FALSE(NULL != g_sr_data, ESP_ERR_INVALID_STATE, TAG, "SR is not running");
ESP_RETURN_ON_FALSE(id < g_sr_data->cmd_num, ESP_ERR_INVALID_ARG, TAG, "cmd id out of range");
sr_cmd_t *it;
SLIST_FOREACH(it, &g_sr_data->cmd_list, next) {
if (it->id == id) {
ESP_LOGI(TAG, "remove cmd id [%d]", it->id);
SLIST_REMOVE(&g_sr_data->cmd_list, it, sr_cmd_t, next);
heap_caps_free(it);
g_sr_data->cmd_num--;
break;
}
}
ESP_RETURN_ON_FALSE(NULL != it, ESP_ERR_NOT_FOUND, TAG, "can't find cmd id:%d", id);
return ESP_OK;
}
esp_err_t app_sr_remove_all_cmd(void)
{
ESP_RETURN_ON_FALSE(NULL != g_sr_data, ESP_ERR_INVALID_STATE, TAG, "SR is not running");
sr_cmd_t *it;
while (!SLIST_EMPTY(&g_sr_data->cmd_list)) {
it = SLIST_FIRST(&g_sr_data->cmd_list);
SLIST_REMOVE_HEAD(&g_sr_data->cmd_list, next);
heap_caps_free(it);
}
SLIST_INIT(&g_sr_data->cmd_list);
return ESP_OK;
}
esp_err_t app_sr_update_cmds(void)
{
ESP_RETURN_ON_FALSE(NULL != g_sr_data, ESP_ERR_INVALID_STATE, TAG, "SR is not running");
char *cmd_str = heap_caps_calloc(g_sr_data->cmd_num, SR_CMD_PHONEME_LEN_MAX, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
ESP_RETURN_ON_FALSE(NULL != cmd_str, ESP_ERR_NO_MEM, TAG, "memory for sr cmd str is not enough");
uint32_t count = 0;
sr_cmd_t *it;
SLIST_FOREACH(it, &g_sr_data->cmd_list, next) {
it->id = count++;
strcat(cmd_str, it->phoneme);
strcat(cmd_str, ";");
}
ESP_LOGI(TAG, "New %d command set to :[%s]", count, cmd_str);
esp_mn_phrase_err_id_t *err_id = g_sr_data->multinet->reset(g_sr_data->model_data, cmd_str, -1);
for (int i = 0; i < err_id->err_id_num; i++) {
ESP_LOGE(TAG, "err cmd id:%d", err_id->err_id[i]);
}
heap_caps_free(cmd_str);
return ESP_OK;
}
uint8_t app_sr_search_cmd_from_user_cmd(sr_user_cmd_t user_cmd, uint8_t *id_list, uint16_t max_len)
{
ESP_RETURN_ON_FALSE(NULL != g_sr_data, 0, TAG, "SR is not running");
uint8_t cmd_num = 0;
sr_cmd_t *it;
SLIST_FOREACH(it, &g_sr_data->cmd_list, next) {
if (user_cmd == it->cmd) {
if (id_list) {
id_list[cmd_num] = it->id;
}
if (++cmd_num >= max_len) {
break;
}
}
}
return cmd_num;
}
uint8_t app_sr_search_cmd_from_phoneme(const char *phoneme, uint8_t *id_list, uint16_t max_len)
{
ESP_RETURN_ON_FALSE(NULL != g_sr_data, 0, TAG, "SR is not running");
uint8_t cmd_num = 0;
sr_cmd_t *it;
SLIST_FOREACH(it, &g_sr_data->cmd_list, next) {
if (0 == strcmp(phoneme, it->phoneme)) {
if (id_list) {
id_list[cmd_num] = it->id;
}
if (++cmd_num >= max_len) {
break;
}
}
}
return cmd_num;
}
const sr_cmd_t *app_sr_get_cmd_from_id(uint32_t id)
{
ESP_RETURN_ON_FALSE(NULL != g_sr_data, NULL, TAG, "SR is not running");
ESP_RETURN_ON_FALSE(id < g_sr_data->cmd_num, NULL, TAG, "cmd id out of range");
sr_cmd_t *it;
SLIST_FOREACH(it, &g_sr_data->cmd_list, next) {
if (id == it->id) {
return it;
}
}
ESP_RETURN_ON_FALSE(NULL != it, NULL, TAG, "can't find cmd id:%d", id);
return NULL;
}
+86
View File
@@ -0,0 +1,86 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#pragma once
#include <stdbool.h>
#include <sys/queue.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_err.h"
#include "esp_afe_sr_models.h"
#include "esp_mn_models.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SR_CONTINUE_DET 1
#define SR_RUN_TEST 0 /**< Just for sr experiment in laboratory >*/
#if SR_RUN_TEST
#ifdef SR_CONTINUE_DET
#undef SR_CONTINUE_DET
#define SR_CONTINUE_DET 0
#endif
#endif
#define SR_CMD_STR_LEN_MAX 64
#define SR_CMD_PHONEME_LEN_MAX 64
typedef struct {
afe_fetch_mode_t fetch_mode;
esp_mn_state_t state;
int command_id;
} sr_result_t;
/**
* @brief User defined command list
*
*/
typedef enum {
SR_CMD_SET_RED = 0,
SR_CMD_SET_GREEN,
SR_CMD_SET_BLUE,
SR_CMD_LIGHT_ON,
SR_CMD_LIGHT_OFF,
SR_CMD_CUSTOMIZE_COLOR,
SR_CMD_NEXT,
SR_CMD_PLAY,
SR_CMD_PAUSE,
SR_CMD_MAX,
} sr_user_cmd_t;
typedef enum {
SR_LANG_EN,
SR_LANG_CN,
SR_LANG_MAX,
} sr_language_t;
typedef struct sr_cmd_t {
sr_user_cmd_t cmd;
sr_language_t lang;
uint32_t id;
char str[SR_CMD_STR_LEN_MAX];
char phoneme[SR_CMD_PHONEME_LEN_MAX];
SLIST_ENTRY(sr_cmd_t) next;
} sr_cmd_t;
esp_err_t app_sr_start(bool record_en);
esp_err_t app_sr_stop(void);
esp_err_t app_sr_get_result(sr_result_t *result, TickType_t xTicksToWait);
esp_err_t app_sr_set_language(sr_language_t new_lang);
esp_err_t app_sr_add_cmd(const sr_cmd_t *cmd);
esp_err_t app_sr_modify_cmd(uint32_t id, const sr_cmd_t *cmd);
esp_err_t app_sr_remove_cmd(uint32_t id);
esp_err_t app_sr_remove_all_cmd(void);
const sr_cmd_t *app_sr_get_cmd_from_id(uint32_t id);
uint8_t app_sr_search_cmd_from_user_cmd(sr_user_cmd_t user_cmd, uint8_t *id_list, uint16_t max_len);
uint8_t app_sr_search_cmd_from_phoneme(const char *phoneme, uint8_t *id_list, uint16_t max_len);
esp_err_t app_sr_update_cmds(void);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,160 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_check.h"
#include "app_led.h"
#include "app_sr.h"
#include "file_manager.h"
#include "app_player.h"
#include "driver/i2s.h"
#include "bsp_codec.h"
#include "ui_sr.h"
#include "app_sr_handler.h"
#include "settings.h"
static const char *TAG = "sr_handler";
static bool b_audio_playing = false;
static esp_err_t sr_echo_play(const char *filename)
{
esp_err_t ret = ESP_OK;
FILE *fp = fopen(filename, "rb");
ESP_RETURN_ON_FALSE(NULL != fp, ESP_ERR_NOT_FOUND, TAG, "Open file %s failed", filename);
size_t file_size = fm_get_file_size(filename);
uint8_t *audio_buffer = heap_caps_calloc(1, file_size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
ESP_GOTO_ON_FALSE(NULL != audio_buffer, ESP_ERR_NO_MEM, err, TAG, "No mem for sr echo buffer");
fread(audio_buffer, 1, file_size, fp);
fclose(fp);
i2s_zero_dma_buffer(I2S_NUM_0);
size_t bytes_written = 0;
b_audio_playing = true;
i2s_write(I2S_NUM_0, audio_buffer, file_size, &bytes_written, portMAX_DELAY);
i2s_zero_dma_buffer(I2S_NUM_0);
b_audio_playing = false;
heap_caps_free(audio_buffer);
return ESP_OK;
err:
fclose(fp);
return ret;
}
bool sr_echo_is_playing(void)
{
return b_audio_playing;
}
void sr_handler_task(void *pvParam)
{
const sys_param_t *param = settings_get_parameter();
player_state_t last_player_state = PLAYER_STATE_IDLE;
while (true) {
sr_result_t result;
app_sr_get_result(&result, portMAX_DELAY);
char audio_file[48] = {0};
if (ESP_MN_STATE_TIMEOUT == result.state) {
if (SR_LANG_EN == param->sr_lang) {
sr_anim_set_text("Timeout");
strncpy(audio_file, "/spiffs/echo_en_end.wav", sizeof(audio_file));
} else {
sr_anim_set_text("超时");
strncpy(audio_file, "/spiffs/echo_cn_end.wav", sizeof(audio_file));
}
#if !SR_RUN_TEST
sr_echo_play(audio_file);
#endif
sr_anim_stop();
if (PLAYER_STATE_PLAYING == last_player_state) {
app_player_play();
}
continue;
}
if (AFE_FETCH_WWE_DETECTED == result.fetch_mode) {
sr_anim_start();
last_player_state = app_player_get_state();
app_player_pause();
if (SR_LANG_EN == param->sr_lang) {
sr_anim_set_text("Say command");
strncpy(audio_file, "/spiffs/echo_en_wake.wav", sizeof(audio_file));
} else {
sr_anim_set_text("请说");
strncpy(audio_file, "/spiffs/echo_cn_wake.wav", sizeof(audio_file));
}
#if !SR_RUN_TEST
sr_echo_play(audio_file);
#endif
continue;
}
if (ESP_MN_STATE_DETECTED & result.state) {
const sr_cmd_t *cmd = app_sr_get_cmd_from_id(result.command_id);
ESP_LOGI(TAG, "command:%s, act:%d", cmd->str, cmd->cmd);
sr_anim_set_text((char *) cmd->str);
#if !SR_CONTINUE_DET
sr_anim_stop();
if (PLAYER_STATE_PLAYING == last_player_state) {
app_player_play();
}
#endif
switch (cmd->cmd) {
case SR_CMD_SET_RED:
app_pwm_led_set_all(128, 0, 0);
break;
case SR_CMD_SET_GREEN:
app_pwm_led_set_all(0, 128, 0);
break;
case SR_CMD_SET_BLUE:
app_pwm_led_set_all(0, 0, 128);
break;
case SR_CMD_LIGHT_ON:
app_pwm_led_set_power(1);
break;
case SR_CMD_LIGHT_OFF:
app_pwm_led_set_power(0);
break;
case SR_CMD_CUSTOMIZE_COLOR: {
uint16_t h;
uint8_t s, v;
app_pwm_led_get_customize_color(&h, &s, &v);
app_pwm_led_set_all_hsv(h, s, v);
} break;
case SR_CMD_NEXT:
app_player_play_next();
break;
case SR_CMD_PLAY:
app_player_play();
last_player_state = PLAYER_STATE_PLAYING;
break;
case SR_CMD_PAUSE:
app_player_pause();
last_player_state = PLAYER_STATE_PAUSE;
break;
default:
ESP_LOGE(TAG, "Unknow cmd");
break;
}
#if !SR_RUN_TEST
if (SR_LANG_EN == param->sr_lang) {
strncpy(audio_file, "/spiffs/echo_en_ok.wav", sizeof(audio_file));
} else {
strncpy(audio_file, "/spiffs/echo_cn_ok.wav", sizeof(audio_file));
}
sr_echo_play(audio_file);
#endif
}
}
vTaskDelete(NULL);
}
@@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#pragma once
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
bool sr_echo_is_playing(void);
void sr_handler_task(void *pvParam);
#ifdef __cplusplus
}
#endif

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