update box3 component and doc

This commit is contained in:
Xu Xin
2023-11-24 15:10:22 +08:00
parent cfb4a005ae
commit ffd5b181e6
127 changed files with 2332 additions and 5956 deletions
+8 -5
View File
@@ -23,9 +23,9 @@
**Important Note:**
> Upon receiving the ESP32-S3-BOX-3, we advise updating the built-in factory firmware to ensure you have the latest bugfixes via Espressif's online firmware flashing tool ESP Launchpad. Up till now, the latest version is **ESP-BOX-3_Demo_V1.2.3**. To verify the software version, please go to the 'About Us' Page.
> Upon receiving the ESP32-S3-BOX-3, we advise updating the built-in factory firmware to ensure you have the latest bugfixes via Espressif's online firmware flashing tool ESP Launchpad. Up till now, the latest version is **ESP-BOX-3_Demo_V1.2.4**. To verify the software version, please go to the 'About Us' Page.
The ESP-BOX is an advanced AIoT, Edge AI, and IIoT applications development platform released by Espressif Systems. The ESP32-S3-BOX, ESP32-S3-BOX-Lite, and ESP32-S3-BOX-3 are a series of development boards designed for this platform, they are built on Espressifs powerful ESP32-S3 Wi-Fi + Bluetooth 5 (LE) SoC and feature compact and beautiful enclosures. Leveraging the multi-functional accessories and reliable examples from the repos, these development boards cater to both prototyping new projects and building complex IoT systems, providing a perfect balance of form and function.
The ESP-BOX is an advanced AIoT, Edge AI, and IIoT applications development platform released by Espressif Systems. The ESP32-S3-BOX, ESP32-S3-BOX-Lite, and ESP32-S3-BOX-3 are a series of development boards designed for this platform, they are built on Espressifs powerful ESP32-S3 Wi-Fi + Bluetooth 5 (LE) SoC and feature compact and beautiful enclosures. Leveraging the multi-functional accessories and reliable examples from the repos, these development boards cater to both prototyping new projects and building complex IoT systems, providing a perfect balance of form and function.
ESP-BOX provides a platform for developing applications in various domains, including Offline Voice Assistants, Online AI Chatbots (developed using OpenAI and other large language model platforms), Matter Device/Controller, Robot Controller, USB Device/Host, Wireless Sensor Application and a wide range of Human Machine Interaction (HMI) applications. Experience the possibilities—add one to your toolkit and explore the limitless potential!
@@ -66,7 +66,7 @@ ESP-BOX provides a platform for developing applications in various domains, incl
* [Built-in Firmware Source Code](./examples/factory_demo)
* [Other Examples](./examples)
> Based on [Apache 2.0](https://github.com/espressif/esp-box/blob/master/LICENSE) open source license, you can modify, develop, or distribute the contents freely.
> Based on [Apache 2.0](https://github.com/espressif/esp-box/blob/master/LICENSE) open source license, you can modify, develop, or distribute the contents freely.
## Built-in Firmware User Guide
@@ -83,7 +83,7 @@ ESP-BOX provides a platform for developing applications in various domains, incl
## Developer Guide
ESP-BOX integrates ESP-IDF components commonly used in AIoT development from [ESP Registry](https://components.espressif.com/components?q=lcd) that you can leverage to build your own applications.
ESP-BOX integrates ESP-IDF components commonly used in AIoT development from [ESP Registry](https://components.espressif.com/components?q=lcd) that you can leverage to build your own applications.
### Quick Start
@@ -104,6 +104,9 @@ For developer, we offer [ESP RainMaker](https://rainmaker.espressif.com/) soluti
### NuttX
The ESP32-S3-BOX-3 also supports integration with [NuttX](https://github.com/apache/nuttx/tree/master/boards/xtensa/esp32s3/esp32s3-box), offering further flexibility and functionality. Nuttx is a real-time operating system (RTOS) known for its compact size, efficiency, and real-time performance, making it an excellent choice for embedded systems.
### Great Projects from Developers
We actively collect [outstanding projects](./docs/great_projects.md) based on ESP-BOX to inspire more developers to innovate. We thank the enthusiasts promoting thriving community culture and welcome more developers to contribute to the vibrant ESP32 community.
## 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.
@@ -111,5 +114,5 @@ The ESP32-S3-BOX-3 also supports integration with [NuttX](https://github.com/apa
## 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.
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.
+6 -3
View File
@@ -23,7 +23,7 @@
</a>
**重要提醒:**
> 在收到 ESP32-S3-BOX-3 后,我们建议您更新内置的出厂固件,以确保拥有最新的 bug 修复。您可以使用乐鑫在线固件烧录工具 ESP Launchpad 进行此操作。截止目前,最新版本为 **ESP-BOX-3_Demo_V1.2.3**。请前往“About Us”页面验证设备出厂固件版本。
> 在收到 ESP32-S3-BOX-3 后,我们建议您更新内置的出厂固件,以确保拥有最新的 bug 修复。您可以使用乐鑫在线固件烧录工具 ESP Launchpad 进行此操作。截止目前,最新版本为 **ESP-BOX-3_Demo_V1.2.4**。请前往 “About Us” 页面验证设备出厂固件版本。
ESP-BOX 是乐鑫科技推出的面向 AIoT、边缘 AI 和 IIoT 应用的开发平台。ESP32-S3-BOX、ESP32-S3-BOX-Lite 和 ESP32-S3-BOX-3 是为该平台设计的系列开发板,它们基于乐鑫强大的 ESP32-S3 Wi-Fi + Bluetooth 5LE SoC 构建,并拥有紧凑美观的外壳结构。借助多功能配件和 ESP-BOX 项目内的可靠例程,这些开发板既适用于构建新项目原型,也适用于打造复杂的物联网系统,提供了形式上和功能上的完美平衡。
@@ -99,7 +99,7 @@ ESP-BOX 调用乐鑫 ESP-IDF 的包管理器 [ESP Registry](https://components.e
ESP BOX APP 基于商业版 Nova Home 应用 APP 构建,拥有精美的用户界面和更好的用户体验,但由于 Nova Home App 有限开放,客户如需项目资源,可通过 sales@espressif.com 邮件与我们联系。
对于个人开发者,我们提供 [ESP RainMaker](https://rainmaker.espressif.com/zh-hans/) 解决方案,其中包括公开可用的开发文档和 API 指南。以下是开发资源访问路径:
- [ESP RainMaker 快速入门](https://rainmaker.espressif.com/docs/get-started.html)
- [ESP RainMaker 快速入门](https://rainmaker.espressif.com/docs/get-started.html)
- [RainMaker App API 定义](https://swaggerapis.rainmaker.espressif.com)
- [ESP RainMaker 编程指南](https://docs.espressif.com/projects/esp-rainmaker/en/latest/index.html#)
@@ -107,11 +107,14 @@ ESP BOX APP 基于商业版 Nova Home 应用 APP 构建,拥有精美的用户
### NuttX
ESP32-S3-BOX-3 支持与 [NuttX](https://github.com/apache/nuttx/tree/master/boards/xtensa/esp32s3/esp32s3-box) 集成,提供了更多的灵活性和功能。Nuttx 是一款以其小巧、高效和实时性能而闻名的实时操作系统(RTOS),使其成为嵌入式系统的绝佳选择。
### 优秀开源社区项目
我们积极搜集基于 ESP-BOX 的[优秀项目](./docs/great_projects.md),以激发更多 makers 的创新思维。我们对推动社区文化繁荣的倡导者表示由衷的感谢,并欢迎更多的开发人员为充满活力的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)交流想法。
## 贡献示例
## 贡献示例
我们欢迎任何软件或硬件相关的开源贡献,如果您有任何要与我们分享的示例,请参考[贡献指南](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/contribute/index.html)后提交 [Pull Requests](https://github.com/espressif/esp-box/pulls) 贡献代码。
+1 -1
View File
@@ -4,7 +4,7 @@ dependencies:
espressif/esp-box:
version: "3.*"
require: "no"
espressif/esp-box-lite:
version: "2.*"
require: "no"
+1 -1
View File
@@ -133,7 +133,7 @@ typedef bottom_id_t (*bsp_sys_get_bottom_id)();
* - ESP_OK: read successfully
* - ESP_FAIL: read failed
*/
typedef esp_err_t (*bsp_bottom_get_humiture)(float *temperature, uint8_t *humidity);
typedef esp_err_t (*bsp_bottom_get_humiture)(float *temperature, float *humidity);
/**
* @brief Player set mute.
@@ -30,7 +30,7 @@ static void bsp_sensor_set_radar_enable(bool enable)
return;
}
static esp_err_t bsp_sensor_get_humiture(float *temperature, uint8_t *humidity)
static esp_err_t bsp_sensor_get_humiture(float *temperature, float *humidity)
{
return ESP_FAIL;
}
+21 -37
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -21,8 +21,8 @@
static bool sys_sleep_entered = false;
static bottom_id_t sys_bottom_id;
static float sys_temperature_value;
static uint8_t sys_humidity_value;
static float sys_temp_result;
static float sys_RH_result;
static uint16_t power_off_delay;
static aht20_dev_handle_t aht20 = NULL;
@@ -66,11 +66,11 @@ static void bsp_sensor_set_radar_onoff(bool enable)
}
}
static esp_err_t bsp_sensor_get_humiture(float *temperature, uint8_t *humidity)
static esp_err_t bsp_sensor_get_humiture(float *temperature, float *humidity)
{
if (BOTTOM_ID_SENSOR == sys_bottom_id) {
*temperature = sys_temperature_value;
*humidity = sys_humidity_value;
*temperature = sys_temp_result;
*humidity = sys_RH_result;
return ESP_OK;
} else {
return ESP_FAIL;
@@ -80,7 +80,7 @@ static esp_err_t bsp_sensor_get_humiture(float *temperature, uint8_t *humidity)
static void low_power_monitor_task(void *arg)
{
static uint8_t gpio_level_prev = 1;
uint32_t temperature_raw, humidity_raw;
uint32_t temp_raw, RH_raw;
uint8_t gpio_level;
gpio_config_t io_conf = {};
@@ -95,21 +95,15 @@ static void low_power_monitor_task(void *arg)
vTaskDelay(pdMS_TO_TICKS(1000));
if (sys_bottom_id != BOTTOM_ID_UNKNOW) {
if (bsp_i2c_device_probe(BSP_I2C_EXPAND_NUM, AT581X_ADDRRES_0)) {
if (sys_bottom_id == BOTTOM_ID_LOST) {
ESP_LOGE(TAG, "Sensor bottom connected");
sys_bottom_id = BOTTOM_ID_SENSOR;
}
} else {
if (sys_bottom_id == BOTTOM_ID_SENSOR) {
ESP_LOGE(TAG, "Sensor bottom lost");
sys_bottom_id = BOTTOM_ID_LOST;
}
}
sys_bottom_id = (bsp_i2c_device_probe(BSP_I2C_EXPAND_NUM, AT581X_ADDRRES_0)) ? BOTTOM_ID_SENSOR : BOTTOM_ID_LOST;
}
if (BOTTOM_ID_SENSOR == sys_bottom_id) {
gpio_level = gpio_get_level(BSP_RADAR_OUT_IO);
if ((RADAE_FUNC_STOP != power_off_delay) && power_off_delay) {
power_off_delay--;
}
aht20_read_temperature_humidity(aht20, &temp_raw, &sys_temp_result, &RH_raw, &sys_RH_result);
} else {
gpio_level = 1;
}
@@ -118,14 +112,14 @@ static void low_power_monitor_task(void *arg)
gpio_level_prev = gpio_level;
if (gpio_level && (RADAE_FUNC_STOP != power_off_delay)) {
power_off_delay = RADAE_POWER_DELAY;
ESP_LOGI(TAG, "Radar: %s", "active");
ESP_LOGD(TAG, "Radar: %s", "active");
}
}
if ((gpio_level) && (true == sys_sleep_entered)) {
bsp_pm_exit_sleep();
ESP_LOGI(TAG, "power on");
ESP_LOGD(TAG, "power on");
bsp_display_exit_sleep();
lvgl_port_resume();
@@ -133,7 +127,7 @@ static void low_power_monitor_task(void *arg)
bsp_codec_dev_resume();
sys_sleep_entered = false;
} else if ((1 == power_off_delay) && (BOTTOM_ID_SENSOR == sys_bottom_id)) {
ESP_LOGI(TAG, "power off");
ESP_LOGD(TAG, "power off");
sys_sleep_entered = true;
bsp_display_enter_sleep();
@@ -142,17 +136,6 @@ static void low_power_monitor_task(void *arg)
bsp_codec_dev_stop();
bsp_pm_enter_sleep();
}
if ((RADAE_FUNC_STOP != power_off_delay) && power_off_delay \
&& (BOTTOM_ID_SENSOR == sys_bottom_id)) {
power_off_delay--;
}
if (BOTTOM_ID_SENSOR == sys_bottom_id) {
aht20_read_temperature_humidity(aht20, \
&temperature_raw, &sys_temperature_value, \
&humidity_raw, &sys_humidity_value);
}
}
}
@@ -166,7 +149,6 @@ static esp_err_t bsp_init_temp_humudity()
};
ret |= aht20_new_sensor(&i2c_conf, &aht20);
ret |= aht20_init_sensor(aht20);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "Temp & humidity init ok");
}
@@ -176,17 +158,19 @@ static esp_err_t bsp_init_temp_humudity()
static esp_err_t bsp_init_radar()
{
esp_err_t ret = ESP_OK;
at581x_dev_handle_t at581x;
at581x_dev_handle_t at581x = NULL;
at581x_default_cfg_t def_cfg = ATH581X_INITIALIZATION_CONFIG();
at581x_i2c_config_t i2c_conf = {
.i2c_port = BSP_I2C_EXPAND_NUM,
.i2c_addr = AT581X_ADDRRES_0,
.def_conf = &def_cfg,
};
ret |= at581x_new_sensor(&i2c_conf, &at581x);
ret |= at581x_init_sensor(at581x);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "Rader init ok");
ESP_LOGI(TAG, "Radar init ok");
}
return ret;
}
@@ -222,7 +206,7 @@ static esp_err_t bsp_pm_init()
.light_sleep_enable = true
#endif
};
ESP_ERROR_CHECK( esp_pm_configure(&pm_config));
ESP_ERROR_CHECK(esp_pm_configure(&pm_config));
#endif
if (g_pm_apb_lock == NULL) {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

+10 -10
View File
@@ -19,7 +19,7 @@ This guide provides a comprehensive overview of the built-in firmware's capabili
The target group for this product includes individuals and organizations engaged in making, prototyping, and development activities. It is designed to cater to a wide range of users, such as hobbyists, makers, engineers, educators, and professionals seeking versatile and expandable solutions for their projects.
# Target Application
* How to call these things, use one trem: Smart Home
* Smart Home
* Smart Agriculture
* Smart City
* Energy Management
@@ -38,7 +38,7 @@ The target group for this product includes individuals and organizations engaged
<img src="./_static/_get_started_static/ESP32_S3_BOX_3_KitFigure.png" width="700px">
</div>
- ESP32-S3-BOX-3, a main unit that can work on its own
- ESP32-S3-BOX-3, a main unit that can work on its own
- ESP32-S3-BOX-3-DOCK, a functional accessory serving as a stand for the main box
- ESP32-S3-BOX-3-SENSOR, a functional accessory showcasing sensor applications
- ESP32-S3-BOX-3-BRACKET, an adapter accessory for mounting the main box to other devices
@@ -53,7 +53,7 @@ The target group for this product includes individuals and organizations engaged
<img src="./_static/_get_started_static/usb_power_box.png" width="800px">
</div>
2. Once the device is powered on, the screen will play the Espressif logo boot animation.
2. Once the device is powered on, the screen will play the Espressif logo boot animation.
<div align="center">
<img src="./_static/_get_started_static/boot_animation.png" width="500px">
@@ -154,7 +154,7 @@ Firstly, connect the RGB LED module to your device. Refer to the pin definitions
<img src="./_static/_get_started_static/LED_pin_defination.png">
</div>
1. You may say `"Hi E. S. P." (pronounce in alphabet)` at any screen to wake up your device. When it wakes up, the screen will display the wake word you just used. If the wake word isn't displayed, give it another try. The screen below indicates your device is listening.
1. You may say `"Hi E. S. P." (pronounce in alphabet)` at any screen to wake up your device. When it wakes up, the screen will display the wake word you just used. If the wake word isn't displayed, give it another try. The screen below indicates your device is listening.
<div align="center">
<img src="./_static/_get_started_static/17.png">
@@ -167,9 +167,9 @@ Firstly, connect the RGB LED module to your device. Refer to the pin definitions
</div>
3. You can use voice commands to enjoy music. First, wake up the device, then say `"Sing a song"`. This will launch the music player and start playing built-in music. You can also use voice commands to pause or skip songs. There are two built-in songs.
>**Tips:**
>* If the LED light fails to turn on, check whether the module pins are inserted into the right ports.
>* If the BOX doesn't recognize any command within the designated timeframe, a `Timeout` message will appear, and the screen will exit in approximately 1 second.
@@ -180,7 +180,7 @@ Firstly, connect the RGB LED module to your device. Refer to the pin definitions
4. The default commands are: **turn on the light**, **turn off the light**, **turn red**, **turn green**, **turn blue**, **sing a song**, **next song**, **pause playing**.
## Continuous Speech Recognition
## Continuous Speech Recognition
More interestingly, the device supports continuous speech recognition after waking up. This feature adds a natural and seamless quality to voice interaction, enhancing the interactive experience with a human touch.
@@ -211,7 +211,7 @@ The ESP32-S3-BOX-3 is also equipped with Espressif proprietary AI Speech Recogni
<div align="center">
<img src="_static/_get_started_static/Picture1.png" width="100 px">
</div>
1.2. If you are new to this app, please register an account first.
1.3. Sign in with your ESP BOX account and turn on the Bluetooth on your phone. Tap `+` at the bottom of the screen, and scan the QR code on your device to set up the network.
@@ -237,11 +237,11 @@ The ESP32-S3-BOX-3 is also equipped with Espressif proprietary AI Speech Recogni
</div>
>**Tips:**
>* Please do not exit the QR code page during the network provisioning.
>* Make sure you connect the device to 2.4 GHz Wi-Fi instead of 5 GHz, and enter the correct Wi-Fi password. If the Wi-Fi password is incorrect, the prompt "Wi-Fi Authentication failed" will pop up.
>* Long press the `Boot` button (i.e. `Funtion` button) for 5 seconds to clear the network information and restore the device to factory settings. After the device is reset, if the QR code or Bluetooth is not working, please restart your device by pressing the `Reset` button.
<div align="center">
<img src="_static/_get_started_static/7.jpeg"width="300" />
</div>
+18 -18
View File
@@ -98,7 +98,7 @@ ESP32-S3-BOX-3 出厂固件支持中文和英文离线语音唤醒和命令词
</div>
5. 轻触屏幕下方的红色圆圈以返回上一页。红圈是一块可自定义的触摸区域,允许用户根据自己的喜好配置额外的触摸功能。
<div align="center">
<img src="./_static/_get_started_static/hardware_home.png" width="250px">
</div>
@@ -130,7 +130,7 @@ ESP32-S3-BOX-3 出厂固件支持中文和英文离线语音唤醒和命令词
</tr>
<tr>
<td><img src="./_static/_get_started_static/29.png"></td>
<td><img src="./_static/_get_started_static/30.png"></td>
<td><img src="./_static/_get_started_static/26.png"></td>
</tr>
</table>
@@ -164,12 +164,12 @@ ESP32-S3-BOX-3 出厂固件支持中文和英文离线语音唤醒和命令词
</div>
3. 您还可以使用语音命令词欣赏音乐。请先唤醒设备,然后说出命令词`“播放音乐”`,设备将打开音乐播放器并开始播放内置音乐。您也可以用语音命令词切换歌曲或者暂停播放。出厂固件默认自带两首歌曲。
>**注意:**
>
>* 如果模块上的 LED 灯没有亮起,请检查模块管脚是否插错。
>* 若在规定时间内未识别到命令词,则会显示 `超时`,约 1 秒后界面关闭。
<div align="center">
<img src="_static/_get_started_static/18.png">
</div>
@@ -195,18 +195,18 @@ ESP32-S3-BOX-3 出厂固件支持中文和英文离线语音唤醒和命令词
**中文模型额外支持的命令词**
| command ID | 命令词 |
| :--------: | :----------:|
| 0 | 打开空调 |
| 1 | 关闭空调 |
| 2 | 舒适模式 |
| 3 | 制冷模式 |
| 4 | 制热模式 |
| 5 | 加热模式 |
| 6 | 除湿模式 |
| 7 | 送风模式 |
| 8 | 升高温度 |
| 9 | 降低温度 |
| command ID | 命令词 |
| :--------: | :----------:|
| 0 | 打开空调 |
| 1 | 关闭空调 |
| 2 | 舒适模式 |
| 3 | 制冷模式 |
| 4 | 制热模式 |
| 5 | 加热模式 |
| 6 | 除湿模式 |
| 7 | 送风模式 |
| 8 | 升高温度 |
| 9 | 降低温度 |
>**注意:**
>
@@ -220,14 +220,14 @@ ESP32-S3-BOX-3 还配备了乐鑫专有的 AI 语音识别系统,通过我们
1.1. 进入 `Network` 界面,点按右上角 `To install APP`。扫描二维码下载并安装 ESP BOX 应用程序,或者直接在 App Store 或 Google Play 中搜索 "ESP BOX" 下载应用程序。
<div align="center">
<img src="_static/_get_started_static/8.png">
</div>
<div align="center">
<img src="_static/_get_started_static/Picture1.png" width="100 px">
</div>
1.2. 如您第一次使用此应用程序,请先注册账号。
1.3. 登录您的 ESP BOX 账号并打开手机蓝牙。点按界面下方 `+`,扫描设备上的二维码配置网络。
+63
View File
@@ -0,0 +1,63 @@
# Great projects using ESP-BOX serials
## Willow - A Practical, Open Source, Privacy-focused Platform for Voice Assistants and Other Applications
<td><img src="./_static/great_projects_picture/willow1.png" width="400"/></td>
### Project Source
[GitHub link](https://github.com/toverainc/willow)
[GitHub URL](https://heywillow.io)
### Project description
Willow is a powerful and privacy-focused voice assistant platform designed for the ESP32-BOX hardware family, offering a cost-effective, open-source, and highly customizable solution for voice interaction and home automation.
<td><img src="./_static/great_projects_picture/willow2.jpg" width="200"/></td>
Willow is an ESP IDF-based project primarily designed for the ESP32-BOX hardware family from Espressif. The project's main objectives are to deliver performance, accuracy, cost-effectiveness, and functionality comparable to Amazon Echo and Google Home when used with Home Assistant, openHAB, and other platforms.
It is 100% open source and self-hosted, providing fast response times (500ms or less), high wake word accuracy, and low false activation rates. Willow offers flexibility with the option to use the Willow Inference Server or perform command recognition solely on the device. The project is known for its reliability, having been tested extensively with a failure rate of less than 1%.
Willow is not only fast and accurate but also prioritizes privacy. Users can inspect the source code, build and flash it themselves, proxy through another server for traffic inspection, use it on their own server, or operate it without internet access. It is a practical and aesthetically pleasing solution, ready to be deployed without drawing attention. The hardware cost is approximately $50, making it a cost-effective choice.
Willow supports features such as wake word detection, voice activity detection, integration with Home Assistant, openHAB, and generic REST APIs, far-field voice recognition, excellent audio quality, and reliable performance in challenging Wi-Fi environments.
The project's future plans include running the Willow Inference Server without CUDA, improving the LCD and touchscreen features, adding support for buttons and custom wake words, and configuring GPIO for user customization.
## ESP-BOX-EMU - A Retro Game Emulation System
<td><img src="./_static/great_projects_picture/esp-box-emu1.png" width="200"/></td>
### Project Source
[GitHub link](https://github.com/esp-cpp/esp-box-emu)
### Project description
ESP-BOX-EMU is a comprehensive project that allows users to enjoy retro game emulation on the ESP32-BOX hardware, with a user-friendly interface and various features for an enhanced gaming experience.
<td><img src="./_static/great_projects_picture/esp-box-emu2.jpg" width="400"/></td>
This project, "esp-box-emu," is an emulation system running on the ESP32-BOX hardware. It is designed to emulate retro games and is built using various components and software libraries, including ESPP, LVGL, Squareline Studio for LVGL design, Nofrendo for NES emulation, and GNUBoy for Game Boy/Game Boy Color emulation.
The project offers videos showcasing its capabilities, including emulation for Game Boy Color, NES games (e.g: Super Mario Bros. and Zelda), and Game Boy games (e.g: Pokemon and Link's Awakening). The videos demonstrate features like audio and video settings, ROM scaling options, and audio control.
The project supports both internal storage using LittleFS and external storage via a uSD card with a FAT filesystem. ROM images and metadata are organized in a specific format for ease of use.
## **ESP32-S3-BOX-3-JoyStick** - A JoyStick Combines Gaming Controller And Aircraft Remote
<td><img src="./_static/great_projects_picture/joystick.png" width="200"/></td>
### Project Source
[OSHWHub link](https://oshwhub.com/esp-college/esp_box_3_joystick)
### Project description
The ESP32-S3-BOX-3-JoyStick hardware system comprises the ESP32-S3-BOX-3 development board, JoyStick controller, and ESP32-S3-USB-Bridge receiver. The ESP32-S3-BOX-3 serves as the main controller, connecting to the JoyStick controller and ESP32-S3-USB-Bridge receiver through a PCI-E interface. The system operates in "Game Mode" and "RC Remote Control Mode." In Game Mode, it supports USB-HID and BLE-HID protocols for computer gaming control, as well as an NES emulator mode. In RC Remote Control Mode, it utilizes the ESP-NOW wireless communication protocol to pair with ESP32-S3-USB-Bridge and other Espressif development boards, enabling wireless control of RC vehicles and ESP-Drone quadcopters.
@@ -92,5 +92,5 @@ ESP32-S3-BOX-3-BREAD is an adapter that enables easy connection of the ESP32-S3-
## Hardware Source Files
* [ESP32-S3-BOX-3 Kit PCB](../../../hardware/PCB_ESP32-S3-BOX-3_V1.0)
* [ESP32-S3-BOX-3 Kit Schematic](../../../hardware/SCH_ESP32-S3-BOX-3_V1.0)
* [ESP32-S3-BOX-3 3D Shell CAD](../../../hardware/esp32_s3_box_3_shell_stl)
* [ESP32-S3-BOX-3 3D Shell CAD](../../../hardware/esp32_s3_box_3_shell)
* [ESP32-S3-BOX-3 Bracket Mounting Template](../../../hardware/ESP32-S3-BOX-3-BRACKET_template.PDF)
@@ -97,5 +97,5 @@ ESP32-S3-BOX-3-BREAD 是一个转接板,方便用户轻松连接 ESP32-S3-BOX-
* [ESP32-S3-BOX-3 Kit PCB](../../../hardware/PCB_ESP32-S3-BOX-3_V1.0)
* [ESP32-S3-BOX-3 Kit Schematic](../../../hardware/SCH_ESP32-S3-BOX-3_V1.0)
* [ESP32-S3-BOX-3 3D Shell CAD](../../../hardware/esp32_s3_box_3_shell_stl)
* [ESP32-S3-BOX-3 3D Shell CAD](../../../hardware/esp32_s3_box_3_shell)
* [ESP32-S3-BOX-3 Bracket Mounting Template](../../../hardware/ESP32-S3-BOX-3-BRACKET_template.PDF)
@@ -27,10 +27,6 @@ It does however have a number of advantages at the moment including:
For MP3 support you'll need the [esp-libhelix-mp3](https://github.com/chmorgan/esp-libhelix-mp3) component.
## Tests
Unity tests are implemented in the [test/](../test) folder.
## States
```mermaid
+1 -2
View File
@@ -1,4 +1,3 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
@@ -46,4 +45,4 @@ void audio_record_init();
void audio_record_save(int16_t *audio_buffer, int audio_chunksize);
void audio_register_play_finish_cb(audio_play_finish_cb_t cb);
void audio_register_play_finish_cb(audio_play_finish_cb_t cb);
@@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#pragma once
#include "OpenAI.h"
@@ -19,4 +20,4 @@ typedef struct {
esp_err_t settings_factory_reset(void);
esp_err_t settings_read_parameter_from_nvs(void);
sys_param_t *settings_get_parameter(void);
sys_param_t *settings_get_parameter(void);
@@ -1,9 +0,0 @@
idf_component_register(
SRCS "aht20.c"
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS "priv_include"
REQUIRES "driver"
)
include(package_manager)
cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR})
@@ -1,14 +0,0 @@
[![Component Registry](https://components.espressif.com/components/espressif/aht20/badge.svg)](https://components.espressif.com/components/espressif/aht20)
# Component: AHT20
I2C driver and definition of AHT20 humidity and temperature sensor.
See [AHT20 datasheet](http://www.aosong.com/en/products-32.html).
## Operation modes
New data from AHT20 can be obtained in Polling modes.
> Note: The user is responsible for initialization and configuration of I2C bus.
### Polling mode
After calling `aht20_new_sensor()` and `aht20_init_sensor()` the user is responsible for reading out new samples from AHT20.
@@ -1,194 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include "aht20.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_check.h"
#include "aht20_reg.h"
const static char *TAG = "AHT20";
typedef struct {
i2c_port_t i2c_port;
uint8_t i2c_addr;
} aht20_dev_t;
static inline esp_err_t aht20_write_reg(aht20_dev_handle_t dev, uint8_t reg_addr, uint8_t *data, uint8_t len)
{
aht20_dev_t *sens = (aht20_dev_t *) dev;
esp_err_t ret;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
ret = i2c_master_start(cmd);
assert(ESP_OK == ret);
ret = i2c_master_write_byte(cmd, sens->i2c_addr | I2C_MASTER_WRITE, true);
assert(ESP_OK == ret);
ret = i2c_master_write_byte(cmd, reg_addr, true);
assert(ESP_OK == ret);
if (len) {
ret = i2c_master_write(cmd, data, len, true);
assert(ESP_OK == ret);
}
ret = i2c_master_stop(cmd);
assert(ESP_OK == ret);
ret = i2c_master_cmd_begin(sens->i2c_port, cmd, 5000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
static inline esp_err_t aht20_read_reg(aht20_dev_handle_t dev, uint8_t *data, size_t len)
{
aht20_dev_t *sens = (aht20_dev_t *) dev;
esp_err_t ret;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
ret = i2c_master_start(cmd);
assert(ESP_OK == ret);
ret = i2c_master_write_byte(cmd, sens->i2c_addr | I2C_MASTER_READ, true);
assert(ESP_OK == ret);
ret = i2c_master_read(cmd, data, len, I2C_MASTER_LAST_NACK);
assert(ESP_OK == ret);
ret = i2c_master_stop(cmd);
assert(ESP_OK == ret);
ret = i2c_master_cmd_begin(sens->i2c_port, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
static uint8_t aht20_calc_crc(uint8_t *data, uint8_t len)
{
uint8_t i;
uint8_t byte;
uint8_t crc = 0xFF;
for (byte = 0; byte < len; byte++) {
crc ^= data[byte];
for (i = 8; i > 0; --i) {
if ((crc & 0x80) != 0) {
crc = (crc << 1) ^ 0x31;
} else {
crc = crc << 1;
}
}
}
return crc;
}
static esp_err_t aht20_reset_reg(aht20_dev_handle_t *handle, uint8_t addr)
{
uint8_t buf[3];
uint8_t regs[3];
buf[0] = 0x00;
buf[1] = 0x00;
ESP_RETURN_ON_ERROR(aht20_write_reg(handle, addr, buf, 2), TAG, "I2C read/write error");
vTaskDelay(pdMS_TO_TICKS(5));
ESP_RETURN_ON_ERROR(aht20_read_reg(handle, regs, 3), TAG, "I2C read/write error");
vTaskDelay(pdMS_TO_TICKS(10));
buf[0] = regs[1];
buf[1] = regs[2];
ESP_RETURN_ON_ERROR(aht20_write_reg(handle, (0xB0 | addr), buf, 2), TAG, "I2C read/write error");
return ESP_OK;
}
esp_err_t aht20_init_sensor(aht20_dev_handle_t *handle)
{
uint8_t status;
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid device handle pointer");
ESP_RETURN_ON_ERROR(aht20_write_reg(handle, 0x71, NULL, 0), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(aht20_read_reg(handle, &status, 1), TAG, "I2C read/write error");
if ((status & 0x18) != 0x18) {
ESP_RETURN_ON_ERROR(aht20_reset_reg(handle, 0x1B), TAG, "0x1B reset error");
ESP_RETURN_ON_ERROR(aht20_reset_reg(handle, 0x1C), TAG, "0x1C reset error");
ESP_RETURN_ON_ERROR(aht20_reset_reg(handle, 0x1E), TAG, "0x1E reset error");
}
return ESP_OK;
}
esp_err_t aht20_read_temperature_humidity(aht20_dev_handle_t handle,
uint32_t *temperature_raw, float *temperature_s,
uint32_t *humidity_raw, uint8_t *humidity_s)
{
uint8_t status;
uint8_t buf[7];
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid device handle pointer");
buf[0] = 0x33;
buf[1] = 0x00;
ESP_RETURN_ON_ERROR(aht20_write_reg(handle, AHT20_START_MEASURMENT_CMD, buf, 2), TAG, "I2C read/write error");
vTaskDelay(pdMS_TO_TICKS(100));
ESP_RETURN_ON_ERROR(aht20_read_reg(handle, &status, 1), TAG, "I2C read/write error");
if ((status & 0x80) == 0) {
ESP_RETURN_ON_ERROR(aht20_read_reg(handle, buf, 7), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR((aht20_calc_crc(buf, 6) != buf[6]), TAG, "crc is error");
*humidity_raw = (((uint32_t)buf[1]) << 16) |
(((uint32_t)buf[2]) << 8) |
(((uint32_t)buf[3]) << 0);
*humidity_raw = (*humidity_raw) >> 4;
*humidity_s = (uint8_t)((float)(*humidity_raw) / 1048576.0f * 100.0f);
*temperature_raw = (((uint32_t)buf[3]) << 16) |
(((uint32_t)buf[4]) << 8) |
(((uint32_t)buf[5]) << 0);
*temperature_raw = (*temperature_raw) & 0xFFFFF;
*temperature_s = (float)(*temperature_raw) / 1048576.0f * 200.0f - 50.0f;
return 0;
} else {
ESP_LOGI(TAG, "data is not ready");
return 4;
}
}
esp_err_t aht20_new_sensor(const aht20_i2c_config_t *i2c_conf, aht20_dev_handle_t *handle_out)
{
ESP_LOGI(TAG, "%-15s: %d.%d.%d", CHIP_NAME, AHT20_VER_MAJOR, AHT20_VER_MINOR, AHT20_VER_PATCH);
ESP_LOGI(TAG, "%-15s: %1.1f - %1.1fV", "SUPPLY_VOLTAGE", SUPPLY_VOLTAGE_MIN, SUPPLY_VOLTAGE_MAX);
ESP_LOGI(TAG, "%-15s: %.2f - %.2f℃", "TEMPERATURE", TEMPERATURE_MIN, TEMPERATURE_MAX);
ESP_RETURN_ON_FALSE(i2c_conf, ESP_ERR_INVALID_ARG, TAG, "invalid device config pointer");
ESP_RETURN_ON_FALSE(handle_out, ESP_ERR_INVALID_ARG, TAG, "invalid device handle pointer");
aht20_dev_t *handle = calloc(1, sizeof(aht20_dev_t));
ESP_RETURN_ON_FALSE(handle, ESP_ERR_NO_MEM, TAG, "memory allocation for device handler failed");
handle->i2c_port = i2c_conf->i2c_port;
handle->i2c_addr = i2c_conf->i2c_addr;
*handle_out = handle;
return ESP_OK;
}
esp_err_t aht20_del_sensor(aht20_dev_handle_t handle)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid device handle pointer");
free(handle);
return ESP_OK;
}
@@ -1,6 +0,0 @@
version: 1.1.0
description: I2C driver for AHT20 humidity and temperature sensor
url: https://github.com/espressif/esp-iot-solution/tree/master/components/sensors/aht20
dependencies:
idf: '>=4.3'
cmake_utilities: "0.*"
@@ -1,92 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_types.h"
#include "esp_err.h"
#include "driver/i2c.h"
/* AHT20 address: CE pin low - 0x38, CE pin high - 0x39 */
#define AHT20_ADDRRES_0 (0x38<<1)
#define AHT20_ADDRESS_1 (0x39<<1)
/**
* @brief Type of es7210 device handle
*
*/
typedef void *aht20_dev_handle_t;
/**
* @brief AHT20 I2C config struct
*
*/
typedef struct {
i2c_port_t i2c_port; /*!< I2C port used to connecte AHT20 device */
uint8_t i2c_addr; /*!< I2C address of AHT20 device, can be 0x38 or 0x39 according to A0 pin */
} aht20_i2c_config_t;
/**
* @brief Init AHT20.
*
* @param[in] i2c_conf Config for I2C used by AHT20
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t aht20_init_sensor(aht20_dev_handle_t *handle);
/**
* @brief Create new AHT20 device handle.
*
* @param[in] i2c_conf Config for I2C used by AHT20
* @param[out] handle_out New AHT20 device handle
* @return
* - ESP_OK Device handle creation success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
* - ESP_ERR_NO_MEM Memory allocation failed.
*
*/
esp_err_t aht20_new_sensor(const aht20_i2c_config_t *i2c_conf, aht20_dev_handle_t *handle_out);
/**
* @brief Delete AHT20 device handle.
*
* @param[in] handle AHT20 device handle
* @return
* - ESP_OK Device handle deletion success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*
*/
esp_err_t aht20_del_sensor(aht20_dev_handle_t handle);
/**
* @brief read the temperature and humidity data
*
* @param[in] *handle points to an aht20 handle structure
* @param[out] *temperature_raw points to a raw temperature buffer
* @param[out] *temperature_s points to a converted temperature buffer
* @param[out] *humidity_raw points to a raw humidity buffer
* @param[out] *humidity_s points to a converted humidity buffer
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t aht20_read_temperature_humidity(aht20_dev_handle_t handle,
uint32_t *temperature_raw, float *temperature_s,
uint32_t *humidity_raw, uint8_t *humidity_s);
#ifdef __cplusplus
}
#endif
@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
@@ -1,18 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
/**
* @brief chip information definition
*/
#define CHIP_NAME "ASAIR AHT20" /**< chip name */
#define SUPPLY_VOLTAGE_MIN (2.2f) /**< chip min supply voltage */
#define SUPPLY_VOLTAGE_MAX (5.5f) /**< chip max supply voltage */
#define TEMPERATURE_MIN (-40.0f) /**< chip min operating temperature */
#define TEMPERATURE_MAX (125.0f) /**< chip max operating temperature */
#define AHT20_START_MEASURMENT_CMD 0xAC /* start measurment command */
@@ -1,8 +0,0 @@
# 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(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components"
"../../aht20")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(aht20_test)
@@ -1,3 +0,0 @@
idf_component_register(SRC_DIRS "."
PRIV_INCLUDE_DIRS "."
PRIV_REQUIRES unity test_utils aht20)
@@ -1,105 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "unity.h"
#include "driver/i2c.h"
#include "aht20.h"
#include "esp_system.h"
#include "esp_log.h"
static const char *TAG = "aht20 test";
#define TEST_MEMORY_LEAK_THRESHOLD (-400)
#define I2C_MASTER_SCL_IO GPIO_NUM_40 /*!< gpio number for I2C master clock */
#define I2C_MASTER_SDA_IO GPIO_NUM_41 /*!< gpio number for I2C master data */
#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */
#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */
static aht20_dev_handle_t aht20 = NULL;
/**
* @brief i2c master initialization
*/
static void i2c_bus_init(void)
{
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = (gpio_num_t)I2C_MASTER_SDA_IO;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_io_num = (gpio_num_t)I2C_MASTER_SCL_IO;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
conf.clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL;
esp_err_t ret = i2c_param_config(I2C_MASTER_NUM, &conf);
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, ret, "I2C config returned error");
ret = i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0);
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, ret, "I2C install returned error");
}
static void i2c_sensor_ath20_init(void)
{
aht20_i2c_config_t i2c_conf = {
.i2c_port = I2C_MASTER_NUM,
.i2c_addr = AHT20_ADDRRES_0,
};
i2c_bus_init();
aht20_new_sensor(&i2c_conf, &aht20);
TEST_ASSERT_NOT_NULL_MESSAGE(aht20, "AHT20 create returned NULL");
aht20_init_sensor(aht20);
}
TEST_CASE("sensor aht20 test", "[aht20][iot][sensor]")
{
esp_err_t ret = ESP_OK;
uint32_t temperature_raw, humidity_raw;
float temperature_s = 0;
uint8_t humidity_s = 0;
i2c_sensor_ath20_init();
aht20_read_temperature_humidity(aht20, &temperature_raw, &temperature_s, &humidity_raw, &humidity_s);
ESP_LOGI(TAG, "%-20s: %d %%", "humidity value is", humidity_s);
ESP_LOGI(TAG, "%-20s: %2.2f degC", "temperature value is", temperature_s);
aht20_del_sensor(aht20);
ret = i2c_driver_delete(I2C_MASTER_NUM);
TEST_ASSERT_EQUAL(ESP_OK, ret);
}
static size_t before_free_8bit;
static size_t before_free_32bit;
static void check_leak(size_t before_free, size_t after_free, const char *type)
{
ssize_t delta = after_free - before_free;
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
}
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)
{
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
check_leak(before_free_8bit, after_free_8bit, "8BIT");
check_leak(before_free_32bit, after_free_32bit, "32BIT");
}
void app_main(void)
{
printf("AHT20 TEST \n");
unity_run_menu();
}
@@ -1,8 +0,0 @@
idf_component_register(
SRCS "at581x.c"
INCLUDE_DIRS "include"
REQUIRES "driver"
)
include(package_manager)
cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR})
@@ -1,11 +0,0 @@
[![Component Registry](https://components.espressif.com/components/espressif/at581x/badge.svg)](https://components.espressif.com/components/espressif/at581x)
# Component: AT581X
I2C driver and definition of AT581X radar sensor.
See [AT581X datasheet](http://www.aosong.com/en/products-32.html).
## Operation modes
After calling `at581x_new_sensor()` and `at581x_init_sensor()` the user is responsible for reading detecting status from IO.
> Note: The user is responsible for initialization and configuration of I2C bus.
@@ -1,228 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include "at581x.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_check.h"
#include "at581x_reg.h"
const static char *TAG = "AT581X";
/**
* @brief Radar default setting
*/
#define PWR_40UA_SWITCH true /*!< FALSE: 68uAAT5815:68uA, AT5812:9mA, TRUE: 40uAAT5815 support */
#define DEF_SELF_CHECK_TIME 2000 /*!< Power-on self-test time, range: 0~65536 ms */
#define DEF_PROTECT_TIME 1000 /*!< protection time, recommended 1000ms */
#define DEF_TRIGGER_BASE_TIME 500 /*!< Default: 500ms */
#define DEF_TRIGGER_KEEP_TIME 1500 /*!< Total trigger time = TRIGGER_BASE_TIME + DEF_TRIGGER_KEEP_TIME, minimum: 1 */
#define DEF_DELTA 200 /*!< Delta value: 0~1023, the larger the value, the shorter the distance */
#define DEF_GAIN AT581X_STAGE_GAIN_3 /*!< 0x7B, within 2 meters */
/**
* @brief Light sensor default setting (no light sensor by default)
*/
#define LIGHT_SENSOR_STATUS false /*!< FALSE: turn off, true: turn on */
#define LIGHT_SENSOR_VALUE_LOW 500 /*!< light sensor threshold, 0~1023, 10bit */
#define LIGHT_SENSOR_VALUE_HIGH 530 /*!< light sensor threshold, 0~1023, 10bit */
#define LIGHT_SENSOR_INIVERSE 0 /*!< 0 default, don't change */
typedef struct {
i2c_port_t i2c_port;
uint8_t i2c_addr;
} at581x_dev_t;
static inline esp_err_t at581x_write_reg(at581x_dev_handle_t dev, uint8_t reg_addr, uint8_t data)
{
at581x_dev_t *sens = (at581x_dev_t *) dev;
const uint8_t write_buf[2] = {reg_addr, data};
return i2c_master_write_to_device(sens->i2c_port, (sens->i2c_addr) >> 1, write_buf, sizeof(write_buf), pdMS_TO_TICKS(1000));
}
static inline esp_err_t at581x_read_reg(at581x_dev_handle_t dev, uint8_t *data, size_t len)
{
at581x_dev_t *sens = (at581x_dev_t *) dev;
esp_err_t ret;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
ret = i2c_master_start(cmd);
assert(ESP_OK == ret);
ret = i2c_master_write_byte(cmd, sens->i2c_addr | I2C_MASTER_READ, true);
assert(ESP_OK == ret);
ret = i2c_master_read(cmd, data, len, I2C_MASTER_LAST_NACK);
assert(ESP_OK == ret);
ret = i2c_master_stop(cmd);
assert(ESP_OK == ret);
ret = i2c_master_cmd_begin(sens->i2c_port, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
esp_err_t at581x_soft_reset(at581x_dev_handle_t *handle)
{
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x00, 0x00), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x00, 0x01), TAG, "I2C read/write error");
return ESP_OK;
}
esp_err_t at581x_set_freq_point(at581x_dev_handle_t *handle, uint8_t freq_0x5f, uint8_t freq_0x60)
{
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x61, 0xC2), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x5F, freq_0x5f), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x60, freq_0x60), TAG, "I2C read/write error");
return ESP_OK;
}
esp_err_t at581x_set_self_check_time(at581x_dev_handle_t *handle, uint32_t self_check_time)
{
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x38, (uint8_t)(self_check_time)), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x39, (uint8_t)(self_check_time >> 8)), TAG, "I2C read/write error");
return ESP_OK;
}
esp_err_t at581x_set_trigger_base_time(at581x_dev_handle_t *handle, uint64_t base_time)
{
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x3d, (uint8_t)(base_time)), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x3e, (uint8_t)(base_time >> 8)), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x3f, (uint8_t)(base_time >> 16)), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x40, (uint8_t)(base_time >> 24)), TAG, "I2C read/write error");
return ESP_OK;
}
esp_err_t at581x_set_protect_time(at581x_dev_handle_t *handle, uint32_t protect_time)
{
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x4e, (uint8_t)(protect_time)), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x4f, (uint8_t)(protect_time >> 8)), TAG, "I2C read/write error");
return ESP_OK;
}
esp_err_t at581x_set_distance(at581x_dev_handle_t *handle, bool pwr_40uA_switch, uint32_t delta, at581x_gain_t gain)
{
if (pwr_40uA_switch) { // 40uA
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x68, (0x48 & 0xc7) | 0x38), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x67, (0xf3 & 0xf0) | 0x08), TAG, "I2C read/write error");
} else { // 70uA
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x68, 0x48), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x67, 0xf3), TAG, "I2C read/write error");
}
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x10, (uint8_t)(delta)), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x11, (uint8_t)(delta >> 8)), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x5C, (0x0B | (gain << 4))), TAG, "I2C read/write error");
return ESP_OK;
}
esp_err_t at581x_set_trigger_keep_time(at581x_dev_handle_t *handle, uint64_t keep_time)
{
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x41, 0x01), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x42, (uint8_t)(keep_time)), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x43, (uint8_t)(keep_time >> 8)), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x44, (uint8_t)(keep_time >> 16)), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x45, (uint8_t)(keep_time >> 24)), TAG, "I2C read/write error");
return ESP_OK;
}
esp_err_t at581x_set_light_sensor_threshold(at581x_dev_handle_t *handle,
bool onoff,
uint32_t light_sensor_value_high,
uint32_t light_sensor_value_low,
uint32_t light_sensor_iniverse)
{
if (onoff) {
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x66, 0x42), TAG, "I2C read/write error");
} else {
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x66, 0x4a), TAG, "I2C read/write error");
}
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x34, (uint8_t)(light_sensor_value_low)), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x35, (uint8_t)(light_sensor_value_high)), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x36, (uint8_t)((light_sensor_value_low >> 8) | ((light_sensor_value_high >> 8) << 2) | (light_sensor_iniverse << 4))), TAG, "I2C read/write error");
return ESP_OK;
}
esp_err_t at581x_set_rf_onoff(at581x_dev_handle_t *handle, bool onoff)
{
if (onoff) {
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x5d, 0x45), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x62, 0x55), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x51, 0xa0), TAG, "I2C read/write error");
} else {
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x5d, 0x46), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x62, 0xaa), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x51, 0x50), TAG, "I2C read/write error");
}
return ESP_OK;
}
esp_err_t set_detect_window(at581x_dev_handle_t *handle, uint8_t window_length, uint8_t window_threshold)
{
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x31, window_length), TAG, "I2C read/write error");
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x32, window_threshold), TAG, "I2C read/write error");
return ESP_OK;
}
esp_err_t at581x_init_sensor(at581x_dev_handle_t *handle)
{
esp_err_t ret = ESP_OK;
ret |= at581x_set_freq_point(handle, FREQ_0X5F_5869MHZ, FREQ_0X60_5869MHZ);
ret |= at581x_set_distance(handle, PWR_40UA_SWITCH, DEF_DELTA, DEF_GAIN);
ret |= at581x_set_trigger_base_time(handle, DEF_TRIGGER_BASE_TIME);
ret |= at581x_set_trigger_keep_time(handle, DEF_TRIGGER_KEEP_TIME);
ret |= at581x_set_self_check_time(handle, DEF_SELF_CHECK_TIME);
ret |= at581x_set_protect_time(handle, DEF_PROTECT_TIME);
// at581x_set_light_sensor_threshold(LIGHT_SENSOR_STATUS, LIGHT_SENSOR_VALUE_LOW, LIGHT_SENSOR_VALUE_HIGH, LIGHT_SENSOR_INIVERSE);
ESP_RETURN_ON_ERROR(at581x_write_reg(handle, 0x55, 0x04), TAG, "I2C read/write error");
at581x_soft_reset(handle);
return ret;
}
esp_err_t at581x_new_sensor(const at581x_i2c_config_t *i2c_conf, at581x_dev_handle_t *handle_out)
{
ESP_LOGI(TAG, "%-15s: %d.%d.%d", CHIP_NAME, AT581X_VER_MAJOR, AT581X_VER_MINOR, AT581X_VER_PATCH);
ESP_RETURN_ON_FALSE(i2c_conf, ESP_ERR_INVALID_ARG, TAG, "invalid device config pointer");
ESP_RETURN_ON_FALSE(handle_out, ESP_ERR_INVALID_ARG, TAG, "invalid device handle pointer");
at581x_dev_t *handle = calloc(1, sizeof(at581x_dev_t));
ESP_RETURN_ON_FALSE(handle, ESP_ERR_NO_MEM, TAG, "memory allocation for device handler failed");
handle->i2c_port = i2c_conf->i2c_port;
handle->i2c_addr = i2c_conf->i2c_addr;
*handle_out = handle;
return ESP_OK;
}
esp_err_t at581x_del_sensor(at581x_dev_handle_t handle)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid device handle pointer");
free(handle);
return ESP_OK;
}
@@ -1,6 +0,0 @@
version: 1.1.0
description: I2C driver for AT581x radar sensor
url: https://github.com/espressif/esp-iot-solution/tree/master/components/sensors/at581x
dependencies:
idf: '>=4.3'
cmake_utilities: "0.*"
@@ -1,199 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_types.h"
#include "esp_err.h"
#include "driver/i2c.h"
#include "at581x_reg.h"
/* AT581X address */
#define AT581X_ADDRRES_0 (0x28<<1)
/**
* @brief Type of AT581X device handle
*
*/
typedef void *at581x_dev_handle_t;
/**
* @brief AT581X I2C config struct
*
*/
typedef struct {
i2c_port_t i2c_port; /*!< I2C port used to connecte AT581X device */
uint8_t i2c_addr; /*!< I2C address of AT581X device */
} at581x_i2c_config_t;
/**
* @brief Init AT581X.
*
* @param[in] handle AT581X device handle
*
* @return
* - ESP_OK Success
* - ESP_FAIL Fail
*/
esp_err_t at581x_init_sensor(at581x_dev_handle_t *handle);
/**
* @brief Create new AT581X device handle.
*
* @param[in] i2c_conf Config for I2C used by AT581X
* @param[out] handle_out New AT581X device handle
* @return
* - ESP_OK Device handle creation success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
* - ESP_ERR_NO_MEM Memory allocation failed.
*/
esp_err_t at581x_new_sensor(const at581x_i2c_config_t *i2c_conf, at581x_dev_handle_t *handle_out);
/**
* @brief Delete AT581X device handle.
*
* @param handle AT581X device handle
* @return
* - ESP_OK Device handle deletion success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*/
esp_err_t at581x_del_sensor(at581x_dev_handle_t handle);
/**
* @brief Software reset.
*
* @param handle AT581X device handle
* @return
* - ESP_OK Device handle deletion success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*/
esp_err_t at581x_soft_reset(at581x_dev_handle_t *handle);
/**
* @brief Set the RF transmit frequency point.
*
* @param handle AT581X device handle
* @param[in] freq_0x5f Refer to the frequency configuration table in at581x_reg.h
* @param[in] freq_0x60 Refer to the frequency configuration table in at581x_reg.h
* @return
* - ESP_OK Device handle deletion success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*/
esp_err_t at581x_set_freq_point(at581x_dev_handle_t *handle, uint8_t freq_0x5f, uint8_t freq_0x60);
/**
* @brief Set self_test time after poweron.
*
* @note at581x_soft_reset is required after modification.
*
* @param handle AT581X device handle
* @param[in] self_check_time time of self_test, unit: ms
* @return
* - ESP_OK Device handle deletion success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*/
esp_err_t at581x_set_self_check_time(at581x_dev_handle_t *handle, uint32_t self_check_time);
/**
* @brief Set the trigger base time (minimum 500ms).
*
* @param handle AT581X device handle
* @param[in] base_time trigger base time, unit: ms
* @return
* - ESP_OK Device handle deletion success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*/
esp_err_t at581x_set_trigger_base_time(at581x_dev_handle_t *handle, uint64_t base_time);
/**
* @brief Set the protection time after triggering.
*
* @note There is no sensing function within the protection time.
*
* @param handle AT581X device handle
* @param[in] protect_time protection time, unit: ms
* @return
* - ESP_OK Device handle deletion success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*/
esp_err_t at581x_set_protect_time(at581x_dev_handle_t *handle, uint32_t protect_time);
/**
* @brief Set detection distance.
*
* @param handle AT581X device handle
* @param[in] pwr_40uA_switch The default current is about 68uA, minimum 40uA
* @param[in] delta Threshold range: 0 ~ 1023
* @param[in] gain Gain of radar, please adjust according to your radar's sensitivity
* @return
* - ESP_OK Device handle deletion success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*/
esp_err_t at581x_set_distance(at581x_dev_handle_t *handle, bool pwr_40uA_switch, uint32_t delta, at581x_gain_t gain);
/**
* @brief Set the delay time after the trigger.
*
* @param handle AT581X device handle
* @param[in] keep_time delay time, unit: ms
* @return
* - ESP_OK Device handle deletion success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*/
esp_err_t at581x_set_trigger_keep_time(at581x_dev_handle_t *handle, uint64_t keep_time);
/**
* @brief Set light sensor (no light sensor by default).
*
* @param handle AT581X device handle
* @param[in] onoff on/off the light sensor
* @param[in] light_sensor_value_high threshold high
* @param[in] light_sensor_value_low threshold low
* @param[in] light_sensor_iniverse inverse
*
* @return
* - ESP_OK Device handle deletion success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*/
esp_err_t at581x_set_light_sensor_threshold(at581x_dev_handle_t *handle,
bool onoff,
uint32_t light_sensor_value_high,
uint32_t light_sensor_value_low,
uint32_t light_sensor_iniverse);
/**
* @brief Control the RF module.
*
* @note After the RF module is off, it can save about 10uA power consumption.
*
* @param handle AT581X device handle
* @param[in] onoff on/off the RF module
* @return
* - ESP_OK Device handle deletion success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*/
esp_err_t at581x_set_rf_onoff(at581x_dev_handle_t *handle, bool onoff);
/**
* @brief Set detect window length & threshold
*
* @param handle AT581X device handle
* @param[in] window_length Number of windows per detection (Default: 4)
* @param[in] window_threshold Number of windows needed to trigger (Default: 3)
* @return
* - ESP_OK Device handle deletion success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*/
esp_err_t set_detect_window(at581x_dev_handle_t *handle, uint8_t window_length, uint8_t window_threshold);
#ifdef __cplusplus
}
#endif
@@ -1,74 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
/**
* @brief chip information definition
*/
#define CHIP_NAME "MoreSense AT581X" /**< chip name */
/**
* @brief Select gain for AT581X
*
* Range: 0x0000 ~ 0x1100 (the larger the value, the smaller the gain)
* Step: 3db
* Recommended: GAIN_3 ~ GAIN_9
*/
typedef enum {
AT581X_STAGE_GAIN_0 = 0,
AT581X_STAGE_GAIN_1,
AT581X_STAGE_GAIN_2,
AT581X_STAGE_GAIN_3,
AT581X_STAGE_GAIN_4,
AT581X_STAGE_GAIN_5,
AT581X_STAGE_GAIN_6,
AT581X_STAGE_GAIN_7,
AT581X_STAGE_GAIN_8,
AT581X_STAGE_GAIN_9,
AT581X_STAGE_GAIN_A,
AT581X_STAGE_GAIN_B,
AT581X_STAGE_GAIN_C,
} at581x_gain_t;
/**
* @brief Frequency Configuration Table
*/
#define FREQ_0X5F_5696MHZ 0x40
#define FREQ_0X60_5696MHZ 0x9d
#define FREQ_0X5F_5715MHZ 0x41
#define FREQ_0X60_5715MHZ 0x9d
#define FREQ_0X5F_5730MHZ 0x42
#define FREQ_0X60_5730MHZ 0x9d
#define FREQ_0X5F_5748MHZ 0x43
#define FREQ_0X60_5748MHZ 0x9d
#define FREQ_0X5F_5765MHZ 0x44
#define FREQ_0X60_5765MHZ 0x9d
#define FREQ_0X5F_5784MHZ 0x45
#define FREQ_0X60_5784MHZ 0x9d
#define FREQ_0X5F_5800MHZ 0x46
#define FREQ_0X60_5800MHZ 0x9d
#define FREQ_0X5F_5819MHZ 0x47
#define FREQ_0X60_5819MHZ 0x9d
#define FREQ_0X5F_5836MHZ 0x40
#define FREQ_0X60_5836MHZ 0x9e
#define FREQ_0X5F_5851MHZ 0x41
#define FREQ_0X60_5851MHZ 0x9e
#define FREQ_0X5F_5869MHZ 0x42
#define FREQ_0X60_5869MHZ 0x9e
#define FREQ_0X5F_5888MHZ 0x43
#define FREQ_0X60_5888MHZ 0x9e
@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
@@ -1,8 +0,0 @@
# 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(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components"
"../../at581x")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(at581x_test)
@@ -1,3 +0,0 @@
idf_component_register(SRC_DIRS "."
PRIV_INCLUDE_DIRS "."
PRIV_REQUIRES unity test_utils at581x)
@@ -1,124 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "unity.h"
#include "sdkconfig.h"
#include "driver/i2c.h"
#include "at581x.h"
#include "esp_system.h"
#include "esp_log.h"
static const char *TAG = "AT581X TEST";
#define TEST_MEMORY_LEAK_THRESHOLD (-400)
#define I2C_MASTER_SCL_IO GPIO_NUM_40 /*!< gpio number for I2C master clock */
#define I2C_MASTER_SDA_IO GPIO_NUM_41 /*!< gpio number for I2C master data */
#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */
#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */
#define RADAR_OUTPUT_IO GPIO_NUM_21 /*!< radar output IO */
static at581x_dev_handle_t at581x = NULL;
static void IRAM_ATTR gpio_isr_handler(void *arg)
{
uint32_t gpio_num = (uint32_t) arg;
esp_rom_printf("GPIO[%d] intr, val: %d\n", gpio_num, gpio_get_level(gpio_num));
}
/**
* @brief i2c master initialization
*/
static void i2c_bus_init(void)
{
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = (gpio_num_t)I2C_MASTER_SDA_IO;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_io_num = (gpio_num_t)I2C_MASTER_SCL_IO;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
conf.clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL;
esp_err_t ret = i2c_param_config(I2C_MASTER_NUM, &conf);
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, ret, "I2C config returned error");
ret = i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0);
TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, ret, "I2C install returned error");
}
static void i2c_sensor_at581x_init(void)
{
at581x_dev_handle_t sensor_handle;
at581x_i2c_config_t i2c_conf = {
.i2c_port = I2C_MASTER_NUM,
.i2c_addr = AT581X_ADDRRES_0,
};
i2c_bus_init();
at581x_new_sensor(&i2c_conf, &at581x);
TEST_ASSERT_NOT_NULL_MESSAGE(at581x, "AT581X create returned NULL");
at581x_init_sensor(at581x);
}
TEST_CASE("sensor at581x test", "[at581x][iot][sensor]")
{
esp_err_t ret;
i2c_sensor_at581x_init();
gpio_config_t io_conf = {};
io_conf.intr_type = GPIO_INTR_POSEDGE;
io_conf.pin_bit_mask = (1ULL << RADAR_OUTPUT_IO);
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_up_en = 1;
gpio_config(&io_conf);
gpio_set_intr_type(RADAR_OUTPUT_IO, GPIO_INTR_ANYEDGE);
gpio_install_isr_service(0x00);
gpio_isr_handler_add(RADAR_OUTPUT_IO, gpio_isr_handler, (void *) RADAR_OUTPUT_IO);
vTaskDelay(pdMS_TO_TICKS(8000));
gpio_isr_handler_remove(RADAR_OUTPUT_IO);
gpio_uninstall_isr_service();
at581x_del_sensor(at581x);
ret = i2c_driver_delete(I2C_MASTER_NUM);
TEST_ASSERT_EQUAL(ESP_OK, ret);
}
static size_t before_free_8bit;
static size_t before_free_32bit;
static void check_leak(size_t before_free, size_t after_free, const char *type)
{
ssize_t delta = after_free - before_free;
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
}
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)
{
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
check_leak(before_free_8bit, after_free_8bit, "8BIT");
check_leak(before_free_32bit, after_free_32bit, "32BIT");
}
void app_main(void)
{
printf("AT581X TEST \n");
unity_run_menu();
}
@@ -1 +0,0 @@
3e8e8cd424411e890f50627f59adfb17d2b0cb1c0a597f5a8fcd0a9916326335
@@ -1,33 +0,0 @@
# ChangeLog
## v2.5.4 - 2023-7-27
### Enhancements:
* Add test apps and ci auto test
## v2.5.3 - 2023-7-26
### Enhancements:
* `repeat` defined in struct button_dev_t is reset to 0 after event `BUTTON_PRESS_REPEAT_DONE`
## v2.5.2 - 2023-7-18
### Enhancements:
* Set "event" member to BUTTON_PRESS_REPEAT before calling the BUTTON_PRESS_REPEAT callback
## v2.5.1 - 2023-3-14
### Enhancements:
* Update doc and code specification
* Avoid overwriting callback by @franz-ms-muc in #252
## v2.5.0 - 2023-2-1
### Enhancements:
* Support custom button
* Add BUTTON_PRESS_REPEAT_DONE event
@@ -1,15 +0,0 @@
set(PRIVREQ esp_timer)
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0")
list(APPEND REQ esp_adc)
else()
list(APPEND REQ esp_adc_cal)
endif()
idf_component_register(SRCS "button_adc.c" "button_gpio.c" "iot_button.c"
INCLUDE_DIRS include
REQUIRES driver ${REQ}
PRIV_REQUIRES ${PRIVREQ})
include(package_manager)
cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR})
@@ -1,55 +0,0 @@
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
help
"One CONFIG_BUTTON_DEBOUNCE_TICKS equal to CONFIG_BUTTON_PERIOD_TIME_MS"
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 BUTTON_SERIAL_TIME_MS
int "BUTTON SERIAL TIME (MS)"
range 2 1000
default 20
help
"Serial trigger interval"
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
@@ -1,29 +0,0 @@
[![Component Registry](https://components.espressif.com/components/espressif/button/badge.svg)](https://components.espressif.com/components/espressif/button)
# Component: Button
[Online documentation](https://docs.espressif.com/projects/esp-iot-solution/en/latest/input_device/button.html)
After creating a new button object by calling function `button_create()`, the button object can create press events, every press event can have its own callback.
List of supported events:
* Button pressed
* Button released
* Button pressed repeat
* Button press repeat done
* Button single click
* Button double click
* Button long press start
* Button long press hold
There are three ways this driver can handle buttons:
1. Buttons connected to standard digital GPIO
2. Multiple buttons connected to single ADC channel
3. Custom button connect to any driver
## Add component to your project
Please use the component manager command `add-dependency` to add the `button` to your project's dependency, during the `CMake` step the component will be downloaded automatically
```
idf.py add-dependency "espressif/button=*"
```
@@ -1,310 +0,0 @@
/* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <inttypes.h>
#include "esp_log.h"
#include "esp_timer.h"
#include "esp_idf_version.h"
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
#include "soc/soc_caps.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#else
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"
#endif
#include "button_adc.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
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
#define ADC_BUTTON_WIDTH SOC_ADC_RTC_MAX_BITWIDTH
#define ADC1_BUTTON_CHANNEL_MAX SOC_ADC_MAX_CHANNEL_NUM
#define ADC_BUTTON_ATTEN ADC_ATTEN_DB_11
#else
#define ADC_BUTTON_WIDTH ADC_WIDTH_MAX-1
#define ADC1_BUTTON_CHANNEL_MAX ADC1_CHANNEL_MAX
#define ADC_BUTTON_ATTEN ADC_ATTEN_DB_11
#endif
#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 {
uint8_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;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
adc_cali_handle_t adc1_cali_handle;
adc_oneshot_unit_handle_t adc1_handle;
#else
esp_adc_cal_characteristics_t adc_chars;
#endif
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(uint8_t channel)
{
for (size_t i = 0; i < ADC_BUTTON_MAX_CHANNEL; i++) {
if (channel == g_button.ch[i].channel) {
return i;
}
}
return -1;
}
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
static esp_err_t adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_cali_handle_t *out_handle)
{
adc_cali_handle_t handle = NULL;
esp_err_t ret = ESP_FAIL;
bool calibrated = false;
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
if (!calibrated) {
ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting");
adc_cali_curve_fitting_config_t cali_config = {
.unit_id = unit,
.atten = atten,
.bitwidth = ADC_BUTTON_WIDTH,
};
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
#endif
#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
if (!calibrated) {
ESP_LOGI(TAG, "calibration scheme version is %s", "Line Fitting");
adc_cali_line_fitting_config_t cali_config = {
.unit_id = unit,
.atten = atten,
.bitwidth = ADC_BUTTON_WIDTH,
};
ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
#endif
*out_handle = handle;
if (ret == ESP_OK) {
ESP_LOGI(TAG, "Calibration Success");
} else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated) {
ESP_LOGW(TAG, "eFuse not burnt, skip software calibration");
} else {
ESP_LOGE(TAG, "Invalid arg or no memory");
}
return calibrated?ESP_OK:ESP_FAIL;
}
#endif
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_BUTTON_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) {
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_err_t ret;
if (NULL == config->adc_handle) {
//ADC1 Init
adc_oneshot_unit_init_cfg_t init_config = {
.unit_id = ADC_UNIT_1,
};
ret = adc_oneshot_new_unit(&init_config, &g_button.adc1_handle);
ADC_BTN_CHECK(ret == ESP_OK, "adc oneshot new unit fail!", ESP_FAIL);
} else {
g_button.adc1_handle = *config->adc_handle ;
ESP_LOGI(TAG, "ADC1 has been initialized");
}
#else
//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");
}
#endif
g_button.is_configured = 1;
}
/** initialize adc channel */
if (0 == g_button.ch[ch_index].is_init) {
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
//ADC1 Config
adc_oneshot_chan_cfg_t oneshot_config = {
.bitwidth = ADC_BUTTON_WIDTH,
.atten = ADC_BUTTON_ATTEN,
};
esp_err_t ret = adc_oneshot_config_channel(g_button.adc1_handle, config->adc_channel, &oneshot_config);
ADC_BTN_CHECK(ret == ESP_OK, "adc oneshot config channel fail!", ESP_FAIL);
//-------------ADC1 Calibration Init---------------//
ret = adc_calibration_init(ADC_BUTTON_ADC_UNIT, ADC_BUTTON_ATTEN, &g_button.adc1_cali_handle);
ADC_BTN_CHECK(ret == ESP_OK, "ADC1 Calibration Init False", 0);
#else
adc1_config_channel_atten(config->adc_channel, ADC_BUTTON_ATTEN);
#endif
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(uint8_t channel, int button_index)
{
ADC_BTN_CHECK(channel < ADC1_BUTTON_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 */
g_button.ch[ch_index].is_init = 0;
g_button.ch[ch_index].channel = ADC1_BUTTON_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 */
g_button.is_configured = false;
memset(&g_button, 0, sizeof(adc_button_t));
ESP_LOGD(TAG, "all channel is unused, , deinit adc");
}
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_err_t ret = adc_oneshot_del_unit(g_button.adc1_handle);
ADC_BTN_CHECK(ret == ESP_OK, "adc oneshot deinit fail", ESP_FAIL);
#endif
return ESP_OK;
}
static uint32_t get_adc_volatge(uint8_t channel)
{
uint32_t adc_reading = 0;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
int adc_raw = 0;
for (int i = 0; i < NO_OF_SAMPLES; i++) {
adc_oneshot_read(g_button.adc1_handle, channel, &adc_raw);
adc_reading += adc_raw;
}
adc_reading /= NO_OF_SAMPLES;
//Convert adc_reading to voltage in mV
int voltage = 0;
adc_cali_raw_to_voltage(g_button.adc1_cali_handle, adc_reading, &voltage);
ESP_LOGV(TAG, "Raw: %"PRIu32"\tVoltage: %dmV", adc_reading, voltage);
#else
//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 = esp_adc_cal_raw_to_voltage(adc_reading, &g_button.adc_chars);
ESP_LOGV(TAG, "Raw: %"PRIu32"\tVoltage: %"PRIu32"mV", adc_reading, voltage);
#endif
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_BUTTON_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;
}
@@ -1,57 +0,0 @@
/* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#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_BTN_CHECK(GPIO_IS_VALID_GPIO(config->gpio_num), "GPIO number error", 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);
}
@@ -1,8 +0,0 @@
#
# "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 := .
@@ -1,11 +0,0 @@
dependencies:
cmake_utilities:
version: 0.*
idf:
version: '>=4.0'
description: GPIO and ADC button driver
documentation: https://docs.espressif.com/projects/esp-iot-solution/en/latest/input_device/button.html
issues: https://github.com/espressif/esp-iot-solution/issues
repository: https://github.com/espressif/esp-iot-solution.git
url: https://github.com/espressif/esp-iot-solution/tree/master/components/button
version: 2.5.4
@@ -1,76 +0,0 @@
/* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_idf_version.h"
#include "driver/gpio.h"
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
#include "esp_adc/adc_oneshot.h"
#else
#include "driver/adc.h"
#endif
#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 {
uint8_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 */
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
adc_oneshot_unit_handle_t *adc_handle; /**< handle of adc unit, if NULL will create new one internal, else will use the handle */
#endif
} 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(uint8_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
@@ -1,54 +0,0 @@
/* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "driver/gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief gpio button configuration
*
*/
typedef struct {
int32_t gpio_num; /**< num of gpio */
uint8_t active_level; /**< gpio level when press down */
} 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
@@ -1,190 +0,0 @@
/* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "button_adc.h"
#include "button_gpio.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (* button_cb_t)(void *button_handle, void *usr_data);
typedef void *button_handle_t;
/**
* @brief Button events
*
*/
typedef enum {
BUTTON_PRESS_DOWN = 0,
BUTTON_PRESS_UP,
BUTTON_PRESS_REPEAT,
BUTTON_PRESS_REPEAT_DONE,
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_CUSTOM
} button_type_t;
/**
* @brief custom button configuration
*
*/
typedef struct {
uint8_t active_level; /**< active level when press down */
esp_err_t (*button_custom_init)(void *param); /**< user defined button init */
uint8_t (*button_custom_get_key_value)(void *param); /**< user defined button get key value */
esp_err_t (*button_custom_deinit)(void *param); /**< user defined button deinit */
void *priv; /**< private data used for custom button, MUST be allocated dynamically and will be auto freed in iot_button_delete*/
} button_custom_config_t;
/**
* @brief Button configuration
*
*/
typedef struct {
button_type_t type; /**< button type, The corresponding button configuration must be filled */
uint16_t long_press_time; /**< Trigger time(ms) for long press, if 0 default to BUTTON_LONG_PRESS_TIME_MS */
uint16_t short_press_time; /**< Trigger time(ms) for short press, if 0 default to BUTTON_SHORT_PRESS_TIME_MS */
union {
button_gpio_config_t gpio_button_config; /**< gpio button configuration */
button_adc_config_t adc_button_config; /**< adc button configuration */
button_custom_config_t custom_button_config; /**< custom button configuration */
}; /**< button configuration */
} button_config_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 iot_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 iot_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.
* @param usr_data user data
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG Arguments is invalid.
* - ESP_ERR_INVALID_STATE The Callback is already registered. No free Space for another Callback.
*/
esp_err_t iot_button_register_cb(button_handle_t btn_handle, button_event_t event, button_cb_t cb, void *usr_data);
/**
* @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_INVALID_STATE The Callback is already registered. No free Space for another Callback.
*/
esp_err_t iot_button_unregister_cb(button_handle_t btn_handle, button_event_t event);
/**
* @brief how many Callbacks are still registered.
*
* @param btn_handle A button handle to unregister
*
* @return 0 if no callbacks registered, or 1 .. (BUTTON_EVENT_MAX-1) for the number of Registered Buttons.
*/
size_t iot_button_count_cb(button_handle_t btn_handle);
/**
* @brief Get button event
*
* @param btn_handle Button handle
*
* @return Current button event. See button_event_t
*/
button_event_t iot_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 iot_button_get_repeat(button_handle_t btn_handle);
/**
* @brief Get button ticks time
*
* @param btn_handle Button handle
*
* @return Actual time from press down to up (ms).
*/
uint16_t iot_button_get_ticks_time(button_handle_t btn_handle);
/**
* @brief Get button long press hold count
*
* @param btn_handle Button handle
*
* @return Count of trigger cb(BUTTON_LONG_PRESS_HOLD)
*/
uint16_t iot_button_get_long_press_hold_cnt(button_handle_t btn_handle);
/**
* @brief Resume button
*
* @param btn_handle A button handle to delete
*
* @return
* - ESP_OK Success
* - ESP_FAIL Failure
*/
esp_err_t iot_button_resume(void);
/**
* @brief Stop button
*
* @param btn_handle A button handle to delete
*
* @return
* - ESP_OK Success
* - ESP_FAIL Failure
*/
esp_err_t iot_button_stop(void);
#ifdef __cplusplus
}
#endif
@@ -1,396 +0,0 @@
/* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#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 "iot_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); \
}
/**
* @brief Structs to record individual key parameters
*
*/
typedef struct Button {
uint16_t ticks;
uint16_t long_press_ticks; /*! Trigger ticks for long press*/
uint16_t short_press_ticks; /*! Trigger ticks for repeat press*/
uint16_t long_press_hold_cnt; /*! Record long press hold count*/
uint8_t repeat;
uint8_t state: 3;
uint8_t debounce_cnt: 3;
uint8_t active_level: 1;
uint8_t button_level: 1;
button_event_t event;
uint8_t (*hal_button_Level)(void *hardware_data);
esp_err_t (*hal_button_deinit)(void *hardware_data);
void *hardware_data;
void *usr_data[BUTTON_EVENT_MAX];
button_type_t type;
button_cb_t cb[BUTTON_EVENT_MAX];
struct Button *next;
} button_dev_t;
//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 SERIAL_TICKS (CONFIG_BUTTON_SERIAL_TIME_MS /TICKS_INTERVAL)
#define CALL_EVENT_CB(ev) if(btn->cb[ev])btn->cb[ev](btn, btn->usr_data[ev])
#define TIME_TO_TICKS(time, congfig_time) (0 == (time))?congfig_time:(((time) / TICKS_INTERVAL))?((time) / TICKS_INTERVAL):1
/**
* @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->hardware_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 > btn->long_press_ticks) {
btn->event = (uint8_t)BUTTON_LONG_PRESS_START;
CALL_EVENT_CB(BUTTON_LONG_PRESS_START);
btn->state = 4;
}
break;
case 2:
if (btn->button_level == btn->active_level) {
btn->event = (uint8_t)BUTTON_PRESS_DOWN;
CALL_EVENT_CB(BUTTON_PRESS_DOWN);
btn->event = (uint8_t)BUTTON_PRESS_REPEAT;
btn->repeat++;
CALL_EVENT_CB(BUTTON_PRESS_REPEAT); // repeat hit
btn->ticks = 0;
btn->state = 3;
} else if (btn->ticks > btn->short_press_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->event = (uint8_t)BUTTON_PRESS_REPEAT_DONE;
CALL_EVENT_CB(BUTTON_PRESS_REPEAT_DONE); // repeat hit
btn->repeat = 0;
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 4:
if (btn->button_level == btn->active_level) {
//continue hold trigger
if (btn->ticks >= (btn->long_press_hold_cnt + 1) * SERIAL_TICKS) {
btn->event = (uint8_t)BUTTON_LONG_PRESS_HOLD;
btn->long_press_hold_cnt++;
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
btn->long_press_hold_cnt = 0;
}
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 *hardware_data), void *hardware_data, uint16_t long_press_ticks, uint16_t short_press_ticks)
{
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->hardware_data = hardware_data;
btn->event = BUTTON_NONE_PRESS;
btn->active_level = active_level;
btn->hal_button_Level = hal_get_key_state;
btn->button_level = !active_level;
btn->long_press_ticks = long_press_ticks;
btn->short_press_ticks = short_press_ticks;
/** 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 iot_button_create(const button_config_t *config)
{
ESP_LOGI(TAG, "IoT Button Version: %d.%d.%d", BUTTON_VER_MAJOR, BUTTON_VER_MINOR, BUTTON_VER_PATCH);
BTN_CHECK(config, "Invalid button config", NULL);
esp_err_t ret = ESP_OK;
button_dev_t *btn = NULL;
uint16_t long_press_time = 0;
uint16_t short_press_time = 0;
long_press_time = TIME_TO_TICKS(config->long_press_time, LONG_TICKS);
short_press_time = TIME_TO_TICKS(config->short_press_time, SHORT_TICKS);
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, long_press_time, short_press_time);
} 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), long_press_time, short_press_time);
} break;
case BUTTON_TYPE_CUSTOM: {
if (config->custom_button_config.button_custom_init) {
ret = config->custom_button_config.button_custom_init(config->custom_button_config.priv);
BTN_CHECK(ESP_OK == ret, "custom button init failed", NULL);
}
btn = button_create_com(config->custom_button_config.active_level,
config->custom_button_config.button_custom_get_key_value,
config->custom_button_config.priv,
long_press_time, short_press_time);
if (btn) {
btn->hal_button_deinit = config->custom_button_config.button_custom_deinit;
}
} 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 iot_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->hardware_data));
break;
case BUTTON_TYPE_ADC:
ret = button_adc_deinit(ADC_BUTTON_SPLIT_CHANNEL(btn->hardware_data), ADC_BUTTON_SPLIT_INDEX(btn->hardware_data));
break;
case BUTTON_TYPE_CUSTOM:
if (btn->hal_button_deinit) {
ret = btn->hal_button_deinit(btn->hardware_data);
}
if (btn->hardware_data) {
free(btn->hardware_data);
btn->hardware_data = NULL;
}
break;
default:
break;
}
BTN_CHECK(ESP_OK == ret, "button deinit failed", ESP_FAIL);
button_delete_com(btn);
return ESP_OK;
}
esp_err_t iot_button_register_cb(button_handle_t btn_handle, button_event_t event, button_cb_t cb, void *usr_data)
{
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_CHECK(NULL == btn->cb[event], "Callback is already registered", ESP_ERR_INVALID_STATE);
btn->cb[event] = cb;
btn->usr_data[event] = usr_data;
return ESP_OK;
}
esp_err_t iot_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_CHECK(NULL != btn->cb[event], "Callback is not registered yet", ESP_ERR_INVALID_STATE);
btn->cb[event] = NULL;
btn->usr_data[event] = NULL;
return ESP_OK;
}
size_t iot_button_count_cb(button_handle_t btn_handle)
{
BTN_CHECK(NULL != btn_handle, "Pointer of handle is invalid", ESP_ERR_INVALID_ARG);
button_dev_t *btn = (button_dev_t *) btn_handle;
size_t ret = 0;
for (size_t i = 0; i < BUTTON_EVENT_MAX; i++) {
if (btn->cb[i]) {
ret++;
}
}
return ret;
}
button_event_t iot_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 iot_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;
}
uint16_t iot_button_get_ticks_time(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->ticks * TICKS_INTERVAL);
}
uint16_t iot_button_get_long_press_hold_cnt(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->long_press_hold_cnt;
}
esp_err_t iot_button_resume(void)
{
if (g_button_timer_handle != NULL) {
esp_timer_restart(g_button_timer_handle, TICKS_INTERVAL * 1000U);
}
return ESP_OK;
}
esp_err_t iot_button_stop(void)
{
if (g_button_timer_handle != NULL) {
esp_timer_restart(g_button_timer_handle, TICKS_INTERVAL * 1000U * 100);
}
return ESP_OK;
}
@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
@@ -1,9 +0,0 @@
# 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(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components"
"../../button")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(button_test)
@@ -1,9 +0,0 @@
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0")
list(APPEND PRIVREQ esp_adc)
else()
list(APPEND PRIVREQ esp_adc_cal)
endif()
idf_component_register(SRC_DIRS "."
PRIV_INCLUDE_DIRS "."
PRIV_REQUIRES unity test_utils button ${PRIVREQ})
@@ -1,477 +0,0 @@
/* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "stdio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/timers.h"
#include "freertos/semphr.h"
#include "esp_idf_version.h"
#include "esp_log.h"
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
#include "esp_adc/adc_cali.h"
#endif
#include "unity.h"
#include "iot_button.h"
#include "sdkconfig.h"
static const char *TAG = "BUTTON TEST";
#define TEST_MEMORY_LEAK_THRESHOLD (-400)
#define BUTTON_IO_NUM 0
#define BUTTON_ACTIVE_LEVEL 0
#define BUTTON_NUM 16
static size_t before_free_8bit;
static size_t before_free_32bit;
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, void *data)
{
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, void *data)
{
TEST_ASSERT_EQUAL_HEX(BUTTON_PRESS_UP, iot_button_get_event(arg));
ESP_LOGI(TAG, "BTN%d: BUTTON_PRESS_UP[%d]", get_btn_index((button_handle_t)arg), iot_button_get_ticks_time((button_handle_t)arg));
}
static void button_press_repeat_cb(void *arg, void *data)
{
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, void *data)
{
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, void *data)
{
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, void *data)
{
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, void *data)
{
TEST_ASSERT_EQUAL_HEX(BUTTON_LONG_PRESS_HOLD, iot_button_get_event(arg));
ESP_LOGI(TAG, "BTN%d: BUTTON_LONG_PRESS_HOLD[%d],count is [%d]", get_btn_index((button_handle_t)arg), iot_button_get_ticks_time((button_handle_t)arg), iot_button_get_long_press_hold_cnt((button_handle_t)arg));
}
static void button_press_repeat_done_cb(void *arg, void *data)
{
TEST_ASSERT_EQUAL_HEX(BUTTON_PRESS_REPEAT_DONE, iot_button_get_event(arg));
ESP_LOGI(TAG, "BTN%d: BUTTON_PRESS_REPEAT_DONE[%d]", get_btn_index((button_handle_t)arg), iot_button_get_repeat((button_handle_t)arg));
}
static esp_err_t custom_button_gpio_init(void *param)
{
button_gpio_config_t *cfg = (button_gpio_config_t *)param;
return button_gpio_init(cfg);
}
static uint8_t custom_button_gpio_get_key_value(void *param)
{
button_gpio_config_t *cfg = (button_gpio_config_t *)param;
return button_gpio_get_key_level((void *)cfg->gpio_num);
}
static esp_err_t custom_button_gpio_deinit(void *param)
{
button_gpio_config_t *cfg = (button_gpio_config_t *)param;
return button_gpio_deinit(cfg->gpio_num);
}
TEST_CASE("custom button test", "[button][iot]")
{
button_gpio_config_t *gpio_cfg = calloc(1, sizeof(button_gpio_config_t));
gpio_cfg->active_level = 0;
gpio_cfg->gpio_num = 0;
button_config_t cfg = {
.type = BUTTON_TYPE_CUSTOM,
.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
.custom_button_config = {
.button_custom_init = custom_button_gpio_init,
.button_custom_deinit = custom_button_gpio_deinit,
.button_custom_get_key_value = custom_button_gpio_get_key_value,
.active_level = 0,
.priv = gpio_cfg,
},
};
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, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_UP, button_press_up_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL);
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
iot_button_delete(g_btns[0]);
}
TEST_CASE("gpio button test", "[button][iot]")
{
button_config_t cfg = {
.type = BUTTON_TYPE_GPIO,
.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
.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, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_UP, button_press_up_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL);
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
iot_button_delete(g_btns[0]);
}
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
TEST_CASE("adc button test", "[button][iot]")
{
/** ESP32-S3-Korvo board */
const uint16_t vol[6] = {380, 820, 1180, 1570, 1980, 2410};
button_config_t cfg = {0};
cfg.type = BUTTON_TYPE_ADC;
cfg.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS;
cfg.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS;
for (size_t i = 0; i < 6; i++) {
cfg.adc_button_config.adc_channel = 7,
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, NULL);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_UP, button_press_up_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL);
}
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
for (size_t i = 0; i < 6; i++) {
iot_button_delete(g_btns[i]);
}
}
#else
static esp_err_t adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_cali_handle_t *out_handle)
{
adc_cali_handle_t handle = NULL;
esp_err_t ret = ESP_FAIL;
bool calibrated = false;
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
if (!calibrated) {
ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting");
adc_cali_curve_fitting_config_t cali_config = {
.unit_id = unit,
.atten = atten,
.bitwidth = ADC_BUTTON_WIDTH,
};
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
#endif
#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
if (!calibrated) {
ESP_LOGI(TAG, "calibration scheme version is %s", "Line Fitting");
adc_cali_line_fitting_config_t cali_config = {
.unit_id = unit,
.atten = atten,
.bitwidth = ADC_BUTTON_WIDTH,
};
ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle);
if (ret == ESP_OK) {
calibrated = true;
}
}
#endif
*out_handle = handle;
if (ret == ESP_OK) {
ESP_LOGI(TAG, "Calibration Success");
} else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated) {
ESP_LOGW(TAG, "eFuse not burnt, skip software calibration");
} else {
ESP_LOGE(TAG, "Invalid arg or no memory");
}
return calibrated ? ESP_OK : ESP_FAIL;
}
TEST_CASE("adc button idf5 drive test", "[button][iot]")
{
adc_oneshot_unit_handle_t adc1_handle;
adc_cali_handle_t adc1_cali_handle;
adc_oneshot_unit_init_cfg_t init_config = {
.unit_id = ADC_UNIT_1,
};
esp_err_t ret = adc_oneshot_new_unit(&init_config, &adc1_handle);
TEST_ASSERT_TRUE(ret == ESP_OK);
adc_calibration_init(ADC_UNIT_1, ADC_ATTEN_DB_11, &adc1_cali_handle);
/** ESP32-S3-Korvo board */
const uint16_t vol[6] = {380, 820, 1180, 1570, 1980, 2410};
button_config_t cfg = {0};
cfg.type = BUTTON_TYPE_ADC;
cfg.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS;
cfg.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS;
for (size_t i = 0; i < 6; i++) {
cfg.adc_button_config.adc_handle = &adc1_handle;
cfg.adc_button_config.adc_channel = 7,
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, NULL);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_UP, button_press_up_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL);
iot_button_register_cb(g_btns[i], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL);
}
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
for (size_t i = 0; i < 6; i++) {
iot_button_delete(g_btns[i]);
}
}
#endif
#define GPIO_OUTPUT_IO_45 45
static SemaphoreHandle_t g_check = NULL;
static SemaphoreHandle_t g_auto_check_pass = NULL;
static const char* button_event_str[BUTTON_EVENT_MAX] = {
"BUTTON_PRESS_DOWN",
"BUTTON_PRESS_UP",
"BUTTON_PRESS_REPEAT",
"BUTTON_PRESS_REPEAT_DONE",
"BUTTON_SINGLE_CLICK",
"BUTTON_DOUBLE_CLICK",
"BUTTON_LONG_PRESS_START",
"BUTTON_LONG_PRESS_HOLD",
};
static void button_auto_press_test_task(void *arg)
{
// test BUTTON_PRESS_DOWN
xSemaphoreTake(g_check, portMAX_DELAY);
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
vTaskDelay(pdMS_TO_TICKS(100));
// // test BUTTON_PRESS_UP
xSemaphoreTake(g_check, portMAX_DELAY);
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
vTaskDelay(pdMS_TO_TICKS(200));
// test BUTTON_PRESS_REPEAT
xSemaphoreTake(g_check, portMAX_DELAY);
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
vTaskDelay(pdMS_TO_TICKS(100));
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
vTaskDelay(pdMS_TO_TICKS(100));
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
vTaskDelay(pdMS_TO_TICKS(100));
// test BUTTON_PRESS_REPEAT_DONE
xSemaphoreTake(g_check, portMAX_DELAY);
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
vTaskDelay(pdMS_TO_TICKS(200));
// test BUTTON_SINGLE_CLICK
xSemaphoreTake(g_check, portMAX_DELAY);
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
vTaskDelay(pdMS_TO_TICKS(100));
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
vTaskDelay(pdMS_TO_TICKS(200));
// test BUTTON_DOUBLE_CLICK
xSemaphoreTake(g_check, portMAX_DELAY);
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
vTaskDelay(pdMS_TO_TICKS(100));
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
vTaskDelay(pdMS_TO_TICKS(100));
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
vTaskDelay(pdMS_TO_TICKS(100));
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
vTaskDelay(pdMS_TO_TICKS(200));
// test BUTTON_LONG_PRESS_START
xSemaphoreTake(g_check, portMAX_DELAY);
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
vTaskDelay(pdMS_TO_TICKS(1500));
// test BUTTON_LONG_PRESS_HOLD
xSemaphoreTake(g_check, portMAX_DELAY);
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
ESP_LOGI(TAG, "Auto Press Success!");
vTaskDelete(NULL);
}
static button_event_t state = BUTTON_PRESS_DOWN;
static void button_auto_check_cb(void *arg, void *data)
{
if (iot_button_get_event(g_btns[0]) == state) {
ESP_LOGI(TAG, "Auto check: button event %s pass", button_event_str[state]);
if (++state >= BUTTON_EVENT_MAX) {
xSemaphoreGive(g_auto_check_pass);
return;
}
xSemaphoreGive(g_check);
}
}
TEST_CASE("gpio button auto-test", "[button][iot][auto]")
{
state = BUTTON_PRESS_DOWN;
g_check = xSemaphoreCreateBinary();
g_auto_check_pass = xSemaphoreCreateBinary();
xSemaphoreGive(g_check);
button_config_t cfg = {
.type = BUTTON_TYPE_GPIO,
.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
.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_auto_check_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_UP, button_auto_check_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT, button_auto_check_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_SINGLE_CLICK, button_auto_check_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_DOUBLE_CLICK, button_auto_check_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_START, button_auto_check_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_HOLD, button_auto_check_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT_DONE, button_auto_check_cb, NULL);
gpio_config_t io_conf = {
.intr_type = GPIO_INTR_DISABLE,
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = (1ULL << GPIO_OUTPUT_IO_45),
.pull_down_en = 0,
.pull_up_en = 0,
};
gpio_config(&io_conf);
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
xTaskCreate(button_auto_press_test_task, "button_auto_press_test_task", 1024 * 4, NULL, 10, NULL);
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(g_auto_check_pass, pdMS_TO_TICKS(5000)));
TEST_ASSERT_EQUAL(ESP_OK,iot_button_delete(g_btns[0]));
vSemaphoreDelete(g_check);
vSemaphoreDelete(g_auto_check_pass);
vTaskDelay(pdMS_TO_TICKS(100));
}
static void check_leak(size_t before_free, size_t after_free, const char *type)
{
ssize_t delta = after_free - before_free;
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
}
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)
{
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
check_leak(before_free_8bit, after_free_8bit, "8BIT");
check_leak(before_free_32bit, after_free_32bit, "32BIT");
}
void app_main(void)
{
printf("USB STREAM TEST \n");
unity_run_menu();
}
@@ -1,5 +0,0 @@
#
#Component Makefile
#
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
@@ -1,20 +0,0 @@
'''
Steps to run these cases:
- Build
- . ${IDF_PATH}/export.sh
- pip install idf_build_apps
- python tools/build_apps.py components/button/test_apps -t esp32s3
- Test
- pip install -r tools/requirements/requirement.pytest.txt
- pytest components/button/test_apps --target esp32s3
'''
import pytest
from pytest_embedded import Dut
@pytest.mark.target('esp32s3')
@pytest.mark.env('button')
def test_usb_stream(dut: Dut)-> None:
dut.expect_exact('Press ENTER to see the list of tests.')
dut.write('[auto]')
dut.expect_unity_test_output(timeout = 60)
@@ -1,9 +0,0 @@
# For IDF 5.0
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT_EN=n
# For IDF4.4
CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP_TASK_WDT=n
@@ -1,11 +0,0 @@
idf_component_register(
SRCS "ir_encoder.c" "ir_learn.c"
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS "priv_include"
REQUIRES driver ${REQ}
PRIV_REQUIRES esp_timer)
include(cmake_utilities)
cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR})
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
@@ -1,18 +0,0 @@
menu "IR Learn"
config RMT_MEM_BLOCK_SYMBOLS
int "RMT MEM BLOCK SYMBOLS (DMA)"
range 64 1024
default 512
help
"Size of memory block, in number of `rmt_symbol_word_t`, must be an even."
"In the DMA mode, this field controls the DMA buffer size, it can be set to a large value (e.g. 1024)"
config RMT_DECODE_MARGIN_US
int "DECODE MARGIN TIME (US)"
range 10 300
default 200
help
"Allowable error margin for each symbol level"
endmenu
@@ -1,29 +0,0 @@
[![Component Registry](https://components.espressif.com/components/espressif/ir_learn/badge.svg)](https://components.espressif.com/components/espressif/ir_learn)
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
## Component IR Learn
This is an RMT-based `IR Learn` component that can receive to analyze infrared signals with a `38KHz` carrier. The signal collected by the component is saved and forwarded in the form of `raw`, and the specific analysis of the infrared protocol is not supported now.
## How to Use Example
### Hardware Required
* A development board with supported SoC mentioned in the above `Supported Targets` table
* An USB cable for power supply and programming
* A 5mm infrared LED (e.g. IR333C) used to transmit encoded IR signals
* An infrared receiver module (e.g. IRM-3638T), which integrates a demodulator and AGC circuit
### Hardware Connection
```
IR Receiver (IRM-3638T) ESP Board IR Transmitter (IR333C)
+--------------------------+ +----------------------+ +---------------------------+
| RX+-------+IR_RX_GPIO IR_TX_GPIO+--------------+TX |
| | | | | |
| 3V3+-------+3V3 5V+--------------+VCC |
| | | | | |
| GND+-------+GND GND+--------------+GND |
+--------------------------+ +----------------------+ +---------------------------+
```
@@ -1,15 +0,0 @@
version: "0.1.0"
targets:
- esp32c3
- esp32c6
- esp32
- esp32h2
- esp32s2
- esp32s3
description: ir learn with RMT
url: https://github.com/espressif/esp-iot-solution/tree/master/components/features/ir_learn
issues: https://github.com/espressif/esp-iot-solution/issues
repository: https://github.com/espressif/esp-iot-solution.git
dependencies:
idf: ">=5.0"
cmake_utilities: "0.*"
@@ -1,38 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "driver/rmt_encoder.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Type of IR encoder configuration
*/
typedef struct {
uint32_t resolution; /*!< Encoder resolution, in Hz */
} ir_encoder_config_t;
/**
* @brief Create RMT encoder for encoding raw symbols into RMT symbols.
*
* @param[in] config Encoder configuration
* @param[out] ret_encoder Returned encoder handle
* @return
* - ESP_OK Create RMT copy encoder successfully
* - ESP_ERR_INVALID_ARG Create RMT copy encoder failed because of invalid argument
* - ESP_ERR_NO_MEM Create RMT copy encoder failed because out of memory
* - ESP_FAIL Create RMT copy encoder failed because of other error
*/
esp_err_t ir_encoder_new(const ir_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder);
#ifdef __cplusplus
}
#endif
@@ -1,176 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <sys/queue.h>
#include <sys/queue.h>
#include "driver/rmt_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Type of IR learn handle
*/
typedef struct ir_learn_t *ir_learn_handle_t;
typedef enum {
IR_LEARN_STATE_STEP, /**< IR learn step, start from 1 */
IR_LEARN_STATE_READY = 20, /**< IR learn ready, after successful initialization */
IR_LEARN_STATE_END, /**< IR learn successfully */
IR_LEARN_STATE_FAIL, /**< IR learn failure */
IR_LEARN_STATE_EXIT, /**< IR learn exit */
} ir_learn_state_t;
typedef struct ir_learn_sub_list_t {
uint32_t timediff; /*!< The interval time from the previous packet (ms) */
rmt_rx_done_event_data_t symbols; /*!< Received RMT symbols */
SLIST_ENTRY(ir_learn_sub_list_t) next; /*!< Pointer to the next packet */
} ir_learn_sub_list_t;
typedef struct ir_learn_list_t {
SLIST_HEAD(ir_learn_sub_list_head, ir_learn_sub_list_t) cmd_sub_node; /*!< Package head of every cmd */
SLIST_ENTRY(ir_learn_list_t) next; /*!< Pointer to the next packet */
} ir_learn_list_t;
SLIST_HEAD(ir_learn_list_head, ir_learn_list_t);
/**
* @brief IR learn result user callback.
*
* @param[out] state IR learn step
* @param[out] sub_step Interval less than 500 ms, we think it's the same command
* @param[out] data Command list of this step
*
*/
typedef void (*ir_learn_result_cb)(ir_learn_state_t state, uint8_t sub_step, struct ir_learn_sub_list_head *data);
/**
* @brief IR learn configuration
*/
typedef struct {
rmt_clock_source_t clk_src; /*!< RMT clock source */
uint32_t resolution; /*!< RMT resolution, in Hz */
int learn_count; /*!< IR learn count needed */
int learn_gpio; /*!< IR learn io that consumed by the sensor */
ir_learn_result_cb callback;/*!< IR learn result callback for user */
int task_priority; /*!< IR learn task priority */
int task_stack; /*!< IR learn task stack size */
int task_affinity; /*!< IR learn task pinned to core (-1 is no affinity) */
} ir_learn_cfg_t;
/**
* @brief Create new IR learn handle.
*
* @param[in] cfg Config for IR learn
* @param[out] handle_out New IR learn handle
* @return
* - ESP_OK Device handle creation success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
* - ESP_ERR_NO_MEM Memory allocation failed.
*
*/
esp_err_t ir_learn_new(const ir_learn_cfg_t *cfg, ir_learn_handle_t *handle_out);
/**
* @brief Restart IR learn process.
*
* @param[in] handle IR learn handle
* @return
* - ESP_OK Restart process success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*
*/
esp_err_t ir_learn_restart(ir_learn_handle_t ir_learn_hdl);
/**
* @brief Stop IR learn process.
* @note Delete all
*
* @param[in] handle IR learn handle
* @return
* - ESP_OK Stop process success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*
*/
esp_err_t ir_learn_stop(ir_learn_handle_t *ir_learn_hdl);
/**
* @brief Add IR learn list node, every new learn list will create it.
*
* @param[in] learn_head IR learn list head
* @return
* - ESP_OK Create learn list success.
* - ESP_ERR_NO_MEM Memory allocation failed.
*
*/
esp_err_t ir_learn_add_list_node(struct ir_learn_list_head *learn_head);
/**
* @brief Add IR learn sub step list node, every sub step should be added.
*
* @param[in] sub_head IR learn sub step list head
* @param[in] timediff Time diff between each sub step
* @param[in] symbol symbols of each sub step
* @return
* - ESP_OK Create learn list success.
* - ESP_ERR_NO_MEM Memory allocation failed.
*
*/
esp_err_t ir_learn_add_sub_list_node(struct ir_learn_sub_list_head *sub_head,
uint32_t timediff, const rmt_rx_done_event_data_t *symbol);
/**
* @brief Delete IR learn list node, will recursively delete sub steps.
*
* @param[in] learn_head IR learn list head
* - ESP_OK Stop process success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*
*/
esp_err_t ir_learn_clean_data(struct ir_learn_list_head *learn_head);
/**
* @brief Delete sub steps.
*
* @param[in] learn_head IR learn list head
* - ESP_OK Stop process success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*
*/
esp_err_t ir_learn_clean_sub_data(struct ir_learn_sub_list_head *sub_head);
/**
* @brief Add IR learn list node, every new learn list will create it.
*
* @param[in] learn_head IR learn list head
* @param[out] result_out IR learn result
* @return
* - ESP_OK Get learn result process.
* - ESP_ERR_INVALID_SIZE Size error.
*
*/
esp_err_t ir_learn_check_valid(struct ir_learn_list_head *learn_head,
struct ir_learn_sub_list_head *result_out);
/**
* @brief Print the RMT symbols.
*
* @param[in] cmd_list IR learn list head
* - ESP_OK Stop process success.
* - ESP_ERR_INVALID_ARG Invalid device handle or argument.
*
*/
esp_err_t ir_learn_print_raw(struct ir_learn_sub_list_head *cmd_list);
#ifdef __cplusplus
}
#endif
@@ -1,105 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_err.h"
#include "ir_encoder.h"
#include "ir_learn_err_check.h"
static const char *TAG = "raw_encoder";
typedef struct {
rmt_encoder_t base; // the base "class", declares the standard encoder interface
rmt_encoder_t *copy_encoder; // use the copy_encoder to encode the leading and ending pulse
rmt_encoder_t *bytes_encoder; // use the bytes_encoder to encode the address and command data
rmt_symbol_word_t nec_leading_symbol; // NEC leading code with RMT representation
rmt_symbol_word_t nec_ending_symbol; // NEC ending code with RMT representation
int state;
} rmt_ir_nec_encoder_t;
static size_t ir_encoder_rmt_raw(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
IR_LEARN_CHECK(encoder, "invalid argument", ESP_ERR_INVALID_ARG);
rmt_ir_nec_encoder_t *nec_encoder = __containerof(encoder, rmt_ir_nec_encoder_t, base);
rmt_encode_state_t session_state = 0;
rmt_encode_state_t state = 0;
size_t encoded_symbols = 0;
rmt_encoder_handle_t copy_encoder = nec_encoder->copy_encoder;
encoded_symbols += copy_encoder->encode(copy_encoder, channel, primary_data, data_size * sizeof(rmt_symbol_word_t), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
nec_encoder->state = 1; // we can only switch to next state when p_symbolsrent encoder finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state |= RMT_ENCODING_MEM_FULL;
goto out; // yield if there's no free space to put other encoding artifacts
}
out:
*ret_state = state;
return encoded_symbols;
}
static esp_err_t ir_encoder_del(rmt_encoder_t *encoder)
{
IR_LEARN_CHECK(encoder, "invalid argument", ESP_ERR_INVALID_ARG);
rmt_ir_nec_encoder_t *nec_encoder = __containerof(encoder, rmt_ir_nec_encoder_t, base);
if (nec_encoder->copy_encoder) {
rmt_del_encoder(nec_encoder->copy_encoder);
}
if (nec_encoder->bytes_encoder) {
rmt_del_encoder(nec_encoder->bytes_encoder);
}
free(nec_encoder);
return ESP_OK;
}
static esp_err_t ir_encoder_reset(rmt_encoder_t *encoder)
{
IR_LEARN_CHECK(encoder, "invalid argument", ESP_ERR_INVALID_ARG);
rmt_ir_nec_encoder_t *nec_encoder = __containerof(encoder, rmt_ir_nec_encoder_t, base);
if (nec_encoder->copy_encoder) {
rmt_encoder_reset(nec_encoder->copy_encoder);
}
if (nec_encoder->bytes_encoder) {
rmt_encoder_reset(nec_encoder->bytes_encoder);
}
nec_encoder->state = 0;
return ESP_OK;
}
esp_err_t ir_encoder_new(const ir_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
esp_err_t ret = ESP_OK;
rmt_ir_nec_encoder_t *nec_encoder = NULL;
IR_LEARN_CHECK(config && ret_encoder, "invalid argument", ESP_ERR_INVALID_ARG);
nec_encoder = calloc(1, sizeof(rmt_ir_nec_encoder_t));
IR_LEARN_CHECK(nec_encoder, "no mem for ir nec encoder", ESP_ERR_NO_MEM);
nec_encoder->base.encode = ir_encoder_rmt_raw;
nec_encoder->base.del = ir_encoder_del;
nec_encoder->base.reset = ir_encoder_reset;
rmt_copy_encoder_config_t copy_encoder_config = {};
ret = rmt_new_copy_encoder(&copy_encoder_config, &nec_encoder->copy_encoder);
IR_LEARN_CHECK_GOTO((ESP_OK == ret), "create copy encoder failed", ESP_FAIL, err);
*ret_encoder = &nec_encoder->base;
return ESP_OK;
err:
if (nec_encoder) {
if (nec_encoder->bytes_encoder) {
rmt_del_encoder(nec_encoder->bytes_encoder);
}
if (nec_encoder->copy_encoder) {
rmt_del_encoder(nec_encoder->copy_encoder);
}
free(nec_encoder);
}
return ret;
}
@@ -1,561 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <sys/queue.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "freertos/semphr.h"
#include "esp_timer.h"
#include "esp_log.h"
#include "esp_err.h"
#include "driver/rmt_tx.h"
#include "driver/rmt_rx.h"
#include "ir_learn.h"
#include "ir_encoder.h"
#include "ir_learn_err_check.h"
static const char *TAG = "ir learn";
#define RMT_RX_MEM_BLOCK_SIZE CONFIG_RMT_MEM_BLOCK_SYMBOLS
#define RMT_DECODE_MARGIN CONFIG_RMT_DECODE_MARGIN_US
static const int LEARN_TASK_DELETE = BIT0;
typedef struct ir_learn_t {
rmt_channel_handle_t channel_rx; /*!< rmt rx channel handler */
rmt_rx_done_event_data_t rmt_rx; /*!< received RMT symbols */
struct ir_learn_list_head learn_list;
struct ir_learn_sub_list_head learn_result;
SemaphoreHandle_t rmt_mux;
QueueHandle_t receive_queue; /*!< A queue used to send the raw data to the task from the ISR */
bool running;
uint32_t pre_time;
uint8_t learn_count;
uint8_t learned_count;
uint8_t learned_sub;
} ir_learn_t;
const static rmt_receive_config_t ir_learn_rmt_rx_cfg = {
.signal_range_min_ns = 1000,
.signal_range_max_ns = 20 * 1000 * 1000,
};
static ir_learn_t *ir_learn_ctx = NULL;
static EventGroupHandle_t ir_learn_event_group;
bool ir_learn_list_lock(uint32_t timeout_ms)
{
const TickType_t timeout_ticks = (timeout_ms == 0) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms);
return xSemaphoreTakeRecursive(ir_learn_ctx->rmt_mux, timeout_ticks) == pdTRUE;
}
void ir_learn_list_unlock(void)
{
xSemaphoreGiveRecursive(ir_learn_ctx->rmt_mux);
}
static bool ir_learn_rx_done_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *edata, void *user_data)
{
BaseType_t task_woken = pdFALSE;
ir_learn_t *ir_learn = (ir_learn_t *)user_data;
xQueueSendFromISR(ir_learn->receive_queue, edata, &task_woken);
return task_woken;
}
esp_err_t ir_learn_print_raw(struct ir_learn_sub_list_head *cmd_list)
{
IR_LEARN_CHECK(cmd_list, "list pointer can't be NULL!", ESP_ERR_INVALID_ARG);
uint8_t sub_num = 0;
ir_learn_sub_list_t *sub_it;
rmt_symbol_word_t *p_symbols;
SLIST_FOREACH(sub_it, cmd_list, next) {
ESP_LOGI(TAG, "sub_it:[%d], timediff:%03d ms, symbols:%03d",
sub_num++,
sub_it->timediff / 1000,
sub_it->symbols.num_symbols);
p_symbols = sub_it->symbols.received_symbols;
for (int i = 0; i < sub_it->symbols.num_symbols; i++) {
printf("symbol:[%03d] %04d| %04d\r\n",
i, p_symbols->duration0, p_symbols->duration1);
p_symbols++;
}
}
return ESP_OK;
}
static esp_err_t ir_learn_remove_all_symbol(void)
{
ir_learn_list_lock(0);
ir_learn_clean_data(&ir_learn_ctx->learn_list);
ir_learn_clean_sub_data(&ir_learn_ctx->learn_result);
ir_learn_list_unlock();
return ESP_OK;
}
static esp_err_t ir_learn_destroy(ir_learn_t *ir_learn)
{
ir_learn_remove_all_symbol();
if (ir_learn->channel_rx) {
rmt_disable(ir_learn->channel_rx);
rmt_del_channel(ir_learn->channel_rx);
}
if (ir_learn->receive_queue) {
vQueueDelete(ir_learn->receive_queue);
}
if (ir_learn->rmt_mux) {
vSemaphoreDelete(ir_learn->rmt_mux);
}
if (ir_learn->rmt_rx.received_symbols) {
free(ir_learn->rmt_rx.received_symbols);
}
free(ir_learn);
return ESP_OK;
}
esp_err_t ir_learn_clean_sub_data(struct ir_learn_sub_list_head *sub_head)
{
IR_LEARN_CHECK(sub_head, "list pointer can't be NULL!", ESP_ERR_INVALID_ARG);
ir_learn_sub_list_t *result_it;
while (!SLIST_EMPTY(sub_head)) {
result_it = SLIST_FIRST(sub_head);
if (result_it->symbols.received_symbols) {
heap_caps_free(result_it->symbols.received_symbols);
}
SLIST_REMOVE_HEAD(sub_head, next);
if (result_it) {
heap_caps_free(result_it);
}
}
SLIST_INIT(sub_head);
return ESP_OK;
}
esp_err_t ir_learn_clean_data(struct ir_learn_list_head *learn_head)
{
IR_LEARN_CHECK(learn_head, "list pointer can't be NULL!", ESP_ERR_INVALID_ARG);
ir_learn_list_t *learn_list;
while (!SLIST_EMPTY(learn_head)) {
learn_list = SLIST_FIRST(learn_head);
ir_learn_clean_sub_data(&learn_list->cmd_sub_node);
SLIST_REMOVE_HEAD(learn_head, next);
if (learn_list) {
heap_caps_free(learn_list);
}
}
SLIST_INIT(learn_head);
return ESP_OK;
}
static void ir_learn_task(void *arg)
{
int64_t cur_time;
size_t period;
ir_learn_result_cb ir_learn_user_callback = (ir_learn_result_cb) arg;
rmt_rx_done_event_data_t learn_data;
ir_learn_ctx->running = true;
ir_learn_ctx->learned_count = 0;
ir_learn_ctx->learned_sub = 0;
rmt_receive(ir_learn_ctx->channel_rx,
ir_learn_ctx->rmt_rx.received_symbols, ir_learn_ctx->rmt_rx.num_symbols, &ir_learn_rmt_rx_cfg);
while (1) {
if ((LEARN_TASK_DELETE & xEventGroupGetBits(ir_learn_event_group))) {
ir_learn_ctx->running = false;
vEventGroupDelete(ir_learn_event_group);
ir_learn_user_callback(IR_LEARN_STATE_EXIT, 0, NULL);
ir_learn_destroy(ir_learn_ctx);
vTaskDelete(NULL);
}
if (xQueueReceive(ir_learn_ctx->receive_queue, &learn_data, pdMS_TO_TICKS(500)) == pdPASS) {
if (learn_data.num_symbols < 5) {
rmt_receive(ir_learn_ctx->channel_rx,
ir_learn_ctx->rmt_rx.received_symbols, ir_learn_ctx->rmt_rx.num_symbols, &ir_learn_rmt_rx_cfg);
continue;
}
cur_time = esp_timer_get_time();
period = cur_time - ir_learn_ctx->pre_time;
ir_learn_ctx->pre_time = esp_timer_get_time();
if ((period < 500 * 1000)) {
ir_learn_ctx->learned_sub++;
} else {
period = 0;
ir_learn_ctx->learned_sub = 1;
ir_learn_ctx->learned_count++;
}
if (ir_learn_ctx->learned_count <= ir_learn_ctx->learn_count) {
ir_learn_list_lock(0);
if (1 == ir_learn_ctx->learned_sub) {
ir_learn_add_list_node(&ir_learn_ctx->learn_list);
}
ir_learn_list_t *main_it;
ir_learn_list_t *last = SLIST_FIRST(&ir_learn_ctx->learn_list);
while ((main_it = SLIST_NEXT(last, next)) != NULL) {
last = main_it;
}
ir_learn_add_sub_list_node(&last->cmd_sub_node, period, &learn_data);
ir_learn_list_unlock();
if (ir_learn_user_callback) {
ir_learn_user_callback(ir_learn_ctx->learned_count, ir_learn_ctx->learned_sub, &last->cmd_sub_node);
}
}
rmt_receive(ir_learn_ctx->channel_rx, \
ir_learn_ctx->rmt_rx.received_symbols, ir_learn_ctx->rmt_rx.num_symbols, &ir_learn_rmt_rx_cfg);
} else if (ir_learn_ctx->learned_sub) {
ir_learn_ctx->learned_sub = 0;
if (ir_learn_ctx->learned_count == ir_learn_ctx->learn_count) {
if (ir_learn_user_callback) {
ir_learn_list_lock(0);
esp_err_t ret = ir_learn_check_valid(&ir_learn_ctx->learn_list, &ir_learn_ctx->learn_result);
ir_learn_list_unlock();
if (ESP_OK == ret) {
ir_learn_user_callback(IR_LEARN_STATE_END, 0, &ir_learn_ctx->learn_result);
} else {
ir_learn_user_callback(IR_LEARN_STATE_FAIL, 0, NULL);
}
}
}
}
}
}
esp_err_t ir_learn_restart(ir_learn_handle_t ir_learn_hdl)
{
IR_LEARN_CHECK(ir_learn_hdl, "learn task not executed!", ESP_FAIL);
ir_learn_remove_all_symbol();
ir_learn_hdl->learned_count = 0;
return ESP_OK;
}
esp_err_t ir_learn_stop(ir_learn_handle_t *ir_learn_hdl)
{
IR_LEARN_CHECK(ir_learn_hdl && *ir_learn_hdl, "learn task not executed!", ESP_FAIL);
ir_learn_handle_t handle = *ir_learn_hdl;
if (handle->running) {
*ir_learn_hdl = NULL;
xEventGroupSetBits(ir_learn_event_group, LEARN_TASK_DELETE);
} else {
ESP_LOGI(TAG, "not running");
}
return ESP_OK;
}
esp_err_t ir_learn_add_sub_list_node(struct ir_learn_sub_list_head *sub_head, uint32_t timediff, const rmt_rx_done_event_data_t *symbol)
{
IR_LEARN_CHECK(sub_head, "list pointer can't be NULL!", ESP_ERR_INVALID_ARG);
esp_err_t ret = ESP_OK;
ir_learn_sub_list_t *item = (ir_learn_sub_list_t *)malloc(sizeof(ir_learn_sub_list_t));
IR_LEARN_CHECK_GOTO(item, "no mem to store received RMT symbols", ESP_ERR_NO_MEM, err);
item->timediff = timediff;
item->symbols.num_symbols = symbol->num_symbols;
item->symbols.received_symbols = malloc(symbol->num_symbols * sizeof(rmt_symbol_word_t));
IR_LEARN_CHECK_GOTO(item->symbols.received_symbols, "no mem to store received RMT symbols", ESP_ERR_NO_MEM, err);
memcpy(item->symbols.received_symbols, symbol->received_symbols, symbol->num_symbols * sizeof(rmt_symbol_word_t));
item->next.sle_next = NULL;
ir_learn_sub_list_t *last = SLIST_FIRST(sub_head);
if (last == NULL) {
SLIST_INSERT_HEAD(sub_head, item, next);
} else {
ir_learn_sub_list_t *sub_it;
while ((sub_it = SLIST_NEXT(last, next)) != NULL) {
last = sub_it;
}
SLIST_INSERT_AFTER(last, item, next);
}
return ret;
err:
if (item) {
free(item);
}
if (item->symbols.received_symbols) {
free(item->symbols.received_symbols);
item->symbols.received_symbols = NULL;
}
return ret;
}
esp_err_t ir_learn_add_list_node(struct ir_learn_list_head *learn_head)
{
IR_LEARN_CHECK(learn_head, "list pointer can't be NULL!", ESP_ERR_INVALID_ARG);
esp_err_t ret = ESP_OK;
ir_learn_list_t *item = (ir_learn_list_t *)malloc(sizeof(ir_learn_list_t));
IR_LEARN_CHECK_GOTO(item, "no mem to store received RMT symbols", ESP_ERR_NO_MEM, err);
SLIST_INIT(&item->cmd_sub_node);
item->next.sle_next = NULL;
ir_learn_list_t *last = SLIST_FIRST(learn_head);
if (last == NULL) {
SLIST_INSERT_HEAD(learn_head, item, next);
} else {
ir_learn_list_t *it;
while ((it = SLIST_NEXT(last, next)) != NULL) {
last = it;
}
SLIST_INSERT_AFTER(last, item, next);
}
return ret;
err:
if (item) {
free(item);
}
return ret;
}
static esp_err_t ir_learn_check_duration(
struct ir_learn_list_head *learn_head,
struct ir_learn_sub_list_head *result_out,
uint8_t sub_cmd_offset,
uint32_t sub_num_symbols,
uint32_t timediff)
{
esp_err_t ret = ESP_OK;
uint32_t duration_average0 = 0;
uint32_t duration_average1 = 0;
uint8_t learn_total_num = 0;
ir_learn_list_t *main_it;
rmt_symbol_word_t *p_symbols, *p_learn_symbols = NULL;
rmt_rx_done_event_data_t add_symbols;
add_symbols.num_symbols = sub_num_symbols;
add_symbols.received_symbols = malloc(sub_num_symbols * sizeof(rmt_symbol_word_t));
p_learn_symbols = add_symbols.received_symbols;
IR_LEARN_CHECK_GOTO(p_learn_symbols, "no mem to store received RMT symbols", ESP_ERR_NO_MEM, err);
for (int i = 0; i < sub_num_symbols; i++) {
p_symbols = NULL;
ret = ESP_OK;
duration_average0 = 0;
duration_average1 = 0;
learn_total_num = 0;
SLIST_FOREACH(main_it, learn_head, next) {
ir_learn_sub_list_t *sub_it = SLIST_FIRST(&main_it->cmd_sub_node);
for (int j = 0; j < sub_cmd_offset; j++) {
sub_it = SLIST_NEXT(sub_it, next);
}
p_symbols = sub_it->symbols.received_symbols;
p_symbols += i;
if (duration_average0) {
if ((p_symbols->duration0 > (duration_average0 / learn_total_num + RMT_DECODE_MARGIN)) ||
(p_symbols->duration0 < (duration_average0 / learn_total_num - RMT_DECODE_MARGIN))) {
ret = ESP_FAIL;
}
}
if (duration_average1) {
if ((p_symbols->duration1 > (duration_average1 / learn_total_num + RMT_DECODE_MARGIN)) ||
(p_symbols->duration1 < (duration_average1 / learn_total_num - RMT_DECODE_MARGIN))) {
ret = ESP_FAIL;
}
}
IR_LEARN_CHECK_GOTO((ESP_OK == ret), "add cmd duration error", ESP_ERR_INVALID_ARG, err);
duration_average0 += p_symbols->duration0;
duration_average1 += p_symbols->duration1;
learn_total_num++;
}
if (learn_total_num && p_symbols) {
p_learn_symbols->duration0 = duration_average0 / learn_total_num;
p_learn_symbols->duration1 = duration_average1 / learn_total_num;
p_learn_symbols->level0 = p_symbols->level1;
p_learn_symbols->level1 = p_symbols->level0;
p_learn_symbols++;
}
}
ir_learn_add_sub_list_node(result_out, timediff, &add_symbols);
if (add_symbols.received_symbols) {
free(add_symbols.received_symbols);
}
return ESP_OK;
err:
if (add_symbols.received_symbols) {
free(add_symbols.received_symbols);
}
return ESP_FAIL;
}
esp_err_t ir_learn_check_valid(struct ir_learn_list_head *learn_head, struct ir_learn_sub_list_head *result_out)
{
IR_LEARN_CHECK(learn_head, "list pointer can't be NULL!", ESP_ERR_INVALID_ARG);
esp_err_t ret = ESP_OK;
ir_learn_list_t *learned_it;
ir_learn_sub_list_t *sub_it;
uint8_t expect_sub_cmd_num = 0xFF;
uint8_t sub_cmd_num = 0;
uint8_t learned_num = 0;
SLIST_FOREACH(learned_it, learn_head, next) {
sub_cmd_num = 0;
learned_num++;
SLIST_FOREACH(sub_it, &learned_it->cmd_sub_node, next) {
sub_cmd_num++;
}
if (0xFF == expect_sub_cmd_num) {
expect_sub_cmd_num = sub_cmd_num;
}
ESP_LOGI(TAG, "list:%d-%d", learned_num, sub_cmd_num);
IR_LEARN_CHECK(expect_sub_cmd_num == sub_cmd_num, "cmd num mismatch", ESP_ERR_INVALID_SIZE);
}
uint16_t sub_num_symbols;
uint32_t time_diff;
for (int i = 0 ; i < sub_cmd_num; i++) {
sub_num_symbols = 0xFFFF;
time_diff = 0xFFFF;
SLIST_FOREACH(learned_it, learn_head, next) {
ir_learn_sub_list_t *sub_item = SLIST_FIRST(&learned_it->cmd_sub_node);
for (int j = 0; j < i; j++) {
sub_item = SLIST_NEXT(sub_item, next);
}
if (0xFFFF == sub_num_symbols) {
sub_num_symbols = sub_item->symbols.num_symbols;
}
if (0xFFFF == time_diff) {
time_diff = sub_item->timediff;
} else {
time_diff += sub_item->timediff;
}
IR_LEARN_CHECK(sub_num_symbols == sub_item->symbols.num_symbols, "sub symbol mismatch", ESP_ERR_INVALID_SIZE);
}
ret = ir_learn_check_duration(learn_head, result_out, i, sub_num_symbols, time_diff / learned_num);
IR_LEARN_CHECK((ESP_OK == ret), "symbol add failed", ESP_ERR_INVALID_SIZE);
}
return ESP_OK;
}
esp_err_t ir_learn_new(const ir_learn_cfg_t *cfg, ir_learn_handle_t *handle_out)
{
ESP_LOGI(TAG, "IR learn Version: %d.%d.%d", IR_LEARN_VER_MAJOR, IR_LEARN_VER_MINOR, IR_LEARN_VER_PATCH);
BaseType_t res;
esp_err_t ret = ESP_OK;
IR_LEARN_CHECK(cfg && handle_out, "invalid argument", ESP_ERR_INVALID_ARG);
IR_LEARN_CHECK(cfg->learn_count < IR_LEARN_STATE_READY, "learn count too larger", ESP_ERR_INVALID_ARG);
ir_learn_ctx = calloc(1, sizeof(ir_learn_t));
IR_LEARN_CHECK(ir_learn_ctx, "no mem for ir_learn_ctx", ESP_ERR_NO_MEM);
rmt_rx_channel_config_t rx_channel_cfg = {
.clk_src = cfg->clk_src,
.gpio_num = cfg->learn_gpio,
.resolution_hz = cfg->resolution,
.mem_block_symbols = RMT_RX_MEM_BLOCK_SIZE,
.flags.with_dma = true,
};
ret = rmt_new_rx_channel(&rx_channel_cfg, &ir_learn_ctx->channel_rx);
IR_LEARN_CHECK_GOTO((ESP_OK == ret), "create rmt rx channel failed", ESP_FAIL, err);
SLIST_INIT(&ir_learn_ctx->learn_list);
ir_learn_ctx->learn_count = cfg->learn_count;
ir_learn_ctx->rmt_rx.num_symbols = RMT_RX_MEM_BLOCK_SIZE * 4;
ir_learn_ctx->rmt_rx.received_symbols = (rmt_symbol_word_t *)heap_caps_malloc(\
ir_learn_ctx->rmt_rx.num_symbols * sizeof(rmt_symbol_word_t), \
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
IR_LEARN_CHECK_GOTO(ir_learn_ctx->rmt_rx.received_symbols, "no mem to store received RMT symbols", ESP_ERR_NO_MEM, err);
ir_learn_ctx->receive_queue = xQueueCreate(1, sizeof(rmt_rx_done_event_data_t));
IR_LEARN_CHECK_GOTO(ir_learn_ctx->receive_queue, "create rmt receive queue failed", ESP_FAIL, err);
ir_learn_ctx->rmt_mux = xSemaphoreCreateRecursiveMutex();
IR_LEARN_CHECK_GOTO(ir_learn_ctx->rmt_mux, "create rmt mux failed", ESP_FAIL, err);
rmt_rx_event_callbacks_t cbs = {
.on_recv_done = ir_learn_rx_done_callback,
};
ret = rmt_rx_register_event_callbacks(ir_learn_ctx->channel_rx, &cbs, ir_learn_ctx);
IR_LEARN_CHECK_GOTO((ESP_OK == ret), "register rmt rx callback failed", ESP_FAIL, err);
ret = rmt_enable(ir_learn_ctx->channel_rx);
IR_LEARN_CHECK_GOTO((ESP_OK == ret), "enable rmt rx channel failed", ESP_FAIL, err);
ir_learn_event_group = xEventGroupCreate();
IR_LEARN_CHECK_GOTO(ir_learn_event_group, "create event group failed", ESP_FAIL, err);
if (cfg->task_affinity < 0) {
res = xTaskCreate(ir_learn_task, "ir learn task", cfg->task_stack, cfg->callback, cfg->task_priority, NULL);
} else {
res = xTaskCreatePinnedToCore(ir_learn_task, "ir learn task", cfg->task_stack, cfg->callback, cfg->task_priority, NULL, cfg->task_affinity);
}
IR_LEARN_CHECK_GOTO(res == pdPASS, "create ir_learn task fail!", ESP_FAIL, err);
if (cfg->callback) {
cfg->callback(IR_LEARN_STATE_READY, 0, NULL);
}
*handle_out = ir_learn_ctx;
return ret;
err:
if (ir_learn_ctx) {
ir_learn_destroy(ir_learn_ctx);
}
return ret;
}
@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
@@ -1,23 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_check.h"
#include "esp_log.h"
#define IR_LEARN_CHECK(a, str, ret_val) \
if (!(a)) \
{ \
ESP_LOGE(TAG, "%s(%d): %s", __FUNCTION__, __LINE__, str); \
return (ret_val); \
}
#define IR_LEARN_CHECK_GOTO(a, str, err_code, label) if(!(a)) { \
ESP_LOGE(TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str); \
ret = err_code;\
goto label; \
}
@@ -1,9 +0,0 @@
# 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(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components"
"../../ir_learn")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ir_learn_test)
@@ -1,3 +0,0 @@
idf_component_register(SRC_DIRS "."
PRIV_INCLUDE_DIRS "."
PRIV_REQUIRES unity test_utils nvs_flash ir_learn)
@@ -1,314 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/* C includes */
#include <stdio.h>
#include <string.h>
/* FreeRTOS includes */
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "freertos/event_groups.h"
/* ESP32 includes */
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "driver/gpio.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "unity.h"
#include "driver/rmt_tx.h"
#include "driver/rmt_rx.h"
/* IR learn includes */
#include "ir_learn.h"
#include "ir_encoder.h"
static const int NEED_DELETE = BIT0;
static const int DELETE_END = BIT1;
static EventGroupHandle_t learn_event_group;
#define TEST_MEMORY_LEAK_THRESHOLD (-400)
#define NEC_IR_RESOLUTION_HZ 1000000 // 1MHz resolution, 1 tick = 1us
#define NEC_IR_TX_GPIO_NUM 39
#define NEC_IR_RX_GPIO_NUM 38
#define NEC_IR_RX_CTRL_GPIO_NUM 44
static const char *TAG = "ir_learn_test";
static QueueHandle_t rmt_out_queue = NULL;
static ir_learn_handle_t ir_learn_handle = NULL;
/**
* @brief result
*
*/
struct ir_learn_sub_list_head ir_leran_data_cmd;
void boot_send_btn_handler(void *arg)
{
if (gpio_get_level(GPIO_NUM_0)) {
if (!SLIST_EMPTY(&ir_leran_data_cmd)) {
esp_rom_printf(DRAM_STR("send rmt out\r\n"));
xQueueSendFromISR(rmt_out_queue, &ir_leran_data_cmd, 0);
} else {
esp_rom_printf(DRAM_STR("ir learn cmd empty\r\n"));
}
}
}
esp_err_t ir_lean_test_send_detect(void)
{
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_NUM_0;
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));
gpio_install_isr_service(0);
ESP_ERROR_CHECK(gpio_isr_handler_add(GPIO_NUM_0, boot_send_btn_handler, NULL));
return ESP_OK;
}
static void ir_learn_test_save_result(struct ir_learn_sub_list_head *data_save, struct ir_learn_sub_list_head *data_src)
{
assert(data_src && "rmt_symbols is null");
ir_learn_sub_list_t *sub_it;
ir_learn_sub_list_t *last;
last = SLIST_FIRST(data_src);
while ((sub_it = SLIST_NEXT(last, next)) != NULL) {
last = sub_it;
}
ir_learn_add_sub_list_node(data_save, last->timediff, &last->symbols);
return;
}
static void ir_learn_test_tx_raw(struct ir_learn_sub_list_head *rmt_out)
{
rmt_tx_channel_config_t tx_channel_cfg = {
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = NEC_IR_RESOLUTION_HZ,
.mem_block_symbols = 128,
.trans_queue_depth = 4,
.gpio_num = NEC_IR_TX_GPIO_NUM,
// .flags.invert_out = true,
};
rmt_channel_handle_t tx_channel = NULL;
ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_channel_cfg, &tx_channel));
rmt_carrier_config_t carrier_cfg = {
.duty_cycle = 0.33,
.frequency_hz = 38000, // 38KHz
};
ESP_ERROR_CHECK(rmt_apply_carrier(tx_channel, &carrier_cfg));
rmt_transmit_config_t transmit_config = {
.loop_count = 0, // no loop
};
ir_encoder_config_t nec_encoder_cfg = {
.resolution = NEC_IR_RESOLUTION_HZ,
};
rmt_encoder_handle_t nec_encoder = NULL;
ESP_ERROR_CHECK(ir_encoder_new(&nec_encoder_cfg, &nec_encoder));
ESP_ERROR_CHECK(rmt_enable(tx_channel));
ir_learn_sub_list_t *sub_it;
SLIST_FOREACH(sub_it, rmt_out, next) {
ESP_LOGI(TAG, "timediff:%" PRIu32 " ms, symbols:%03u",
sub_it->timediff / 1000, sub_it->symbols.num_symbols);
vTaskDelay(pdMS_TO_TICKS(sub_it->timediff / 1000));
rmt_symbol_word_t *rmt_nec_symbols = sub_it->symbols.received_symbols;
size_t symbol_num = sub_it->symbols.num_symbols;
ESP_ERROR_CHECK(rmt_transmit(tx_channel, nec_encoder, rmt_nec_symbols, symbol_num, &transmit_config));
rmt_tx_wait_all_done(tx_channel, -1);
}
rmt_disable(tx_channel);
rmt_del_channel(tx_channel);
nec_encoder->del(nec_encoder);
}
void ir_learn_test_tx_task(void *arg)
{
esp_err_t ret = ESP_OK;
struct ir_learn_sub_list_head tx_data;
gpio_config_t io_conf = {};
io_conf.pin_bit_mask = BIT64(NEC_IR_RX_CTRL_GPIO_NUM);
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pull_up_en = true;
gpio_config(&io_conf);
gpio_set_level(NEC_IR_RX_CTRL_GPIO_NUM, 0);//enable IR TX
rmt_out_queue = xQueueCreate(1, sizeof(rmt_rx_done_event_data_t));
ESP_GOTO_ON_FALSE(rmt_out_queue, ESP_ERR_NO_MEM, err, TAG, "receive queue creation failed");
ir_lean_test_send_detect();
while (1) {
if ((NEED_DELETE & xEventGroupGetBits(learn_event_group))) {
xEventGroupSetBits(learn_event_group, DELETE_END);
if (rmt_out_queue) {
vQueueDelete(rmt_out_queue);
rmt_out_queue = NULL;
}
gpio_isr_handler_remove(0);
gpio_uninstall_isr_service();
vTaskDelete(NULL);
}
if (xQueueReceive(rmt_out_queue, &tx_data, pdMS_TO_TICKS(500)) == pdPASS) {
ir_learn_test_tx_raw(&tx_data);
xEventGroupSetBits(learn_event_group, NEED_DELETE);
}
}
err:
ESP_LOGI(TAG, "ir_learn_test_tx_task exit:%d", ret);
vTaskDelete(NULL);
}
void ir_learn_learn_send_callback(ir_learn_state_t state, uint8_t sub_step, struct ir_learn_sub_list_head *data)
{
switch (state) {
case IR_LEARN_STATE_READY:
ESP_LOGI(TAG, "IR Learn ready");
break;
case IR_LEARN_STATE_EXIT:
ESP_LOGI(TAG, "IR Learn exit");
break;
case IR_LEARN_STATE_END:
ESP_LOGI(TAG, "IR Learn end");
ir_learn_test_save_result(&ir_leran_data_cmd, data);
ir_learn_stop(&ir_learn_handle);
break;
case IR_LEARN_STATE_FAIL:
ESP_LOGE(TAG, "IR Learn faield, retry");
ir_learn_restart(ir_learn_handle);
break;
case IR_LEARN_STATE_STEP:
default:
ESP_LOGI(TAG, "IR Learn step:[%d][%d]", state, sub_step);
break;
}
return;
}
void ir_learn_keep_learn_callback(ir_learn_state_t state, uint8_t sub_step, struct ir_learn_sub_list_head *data)
{
switch (state) {
case IR_LEARN_STATE_READY:
ESP_LOGI(TAG, "IR Learn ready");
break;
case IR_LEARN_STATE_EXIT:
ESP_LOGI(TAG, "IR Learn exit");
break;
case IR_LEARN_STATE_END:
ESP_LOGI(TAG, "IR Learn end");
ir_learn_print_raw(data);
ir_learn_restart(ir_learn_handle);
break;
case IR_LEARN_STATE_FAIL:
ESP_LOGI(TAG, "IR Learn faield, retry");
ir_learn_restart(ir_learn_handle);
break;
case IR_LEARN_STATE_STEP:
default:
ESP_LOGI(TAG, "IR Learn step:[%d][%d]", state, sub_step);
break;
}
return;
}
esp_err_t ir_learn_test(ir_learn_result_cb cb)
{
esp_err_t ret = ESP_OK;
learn_event_group = xEventGroupCreate();
ESP_GOTO_ON_FALSE(learn_event_group, ESP_FAIL, IR_LEARN_END, TAG, "create event group failed");
xTaskCreate(ir_learn_test_tx_task, "ir_learn_test_tx_task", 1024 * 4, NULL, 10, NULL);
ir_learn_cfg_t ir_learn_config = {
.learn_count = 4,
.learn_gpio = NEC_IR_RX_GPIO_NUM,
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution = NEC_IR_RESOLUTION_HZ,
.task_stack = 4096,
.task_priority = 5,
.task_affinity = 1,
.callback = cb,
};
ESP_ERROR_CHECK(ir_learn_new(&ir_learn_config, &ir_learn_handle));
xEventGroupWaitBits(learn_event_group, DELETE_END, true, true, portMAX_DELAY);
ir_learn_stop(&ir_learn_handle);
ir_learn_clean_sub_data(&ir_leran_data_cmd);
vEventGroupDelete(learn_event_group);
IR_LEARN_END:
vTaskDelay(pdMS_TO_TICKS(1000));
ESP_LOGI(TAG, "Process end");
return ret;
}
TEST_CASE("IR learn and send test", "[IR][IOT]")
{
ir_learn_test(ir_learn_learn_send_callback);
}
TEST_CASE("IR keep learn test", "[IR][IOT]")
{
ir_learn_test(ir_learn_keep_learn_callback);
}
static size_t before_free_8bit;
static size_t before_free_32bit;
static void check_leak(size_t before_free, size_t after_free, const char *type)
{
ssize_t delta = after_free - before_free;
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
}
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)
{
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
check_leak(before_free_8bit, after_free_8bit, "8BIT");
check_leak(before_free_32bit, after_free_32bit, "32BIT");
}
void app_main(void)
{
printf("IR learn TEST \n");
unity_run_menu();
}
@@ -1,7 +0,0 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, , 0x1000,
fctry, data, nvs, , 0x6000,
factory, app, factory, , 3400K,
storage, data, spiffs, , 400K,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, , 0x1000,
5 fctry, data, nvs, , 0x6000,
6 factory, app, factory, , 3400K,
7 storage, data, spiffs, , 400K,
@@ -1,10 +0,0 @@
# For IDF 5.0
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=4096
# For IDF4.4
CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP_TASK_WDT=n
+7 -34
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -85,36 +85,10 @@ static const sr_cmd_t g_default_cmd_info[] = {
{SR_CMD_NEXT, SR_LANG_EN, 0, "Next Song", "NfKST Sel", {NULL}},
{SR_CMD_PAUSE, SR_LANG_EN, 0, "Pause Playing", "PeZ PLdgl", {NULL}},
{SR_CMD_AC_ON, SR_LANG_EN, 0, "Turn on the Air", "TkN nN jc fR", {NULL}},
{SR_CMD_AC_OFF, SR_LANG_EN, 0, "Turn off the Air", "TkN eF jc fR", {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}},
@@ -123,13 +97,13 @@ static const sr_cmd_t g_default_cmd_info[] = {
{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_NEXT, SR_LANG_CN, 0, "下一曲", "xia yi qu", {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_AC_ON, SR_LANG_CN, 0, "打开空调", "da kai kong tiao", {NULL}},
{SR_CMD_AC_OFF, 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}},
@@ -138,7 +112,6 @@ static const sr_cmd_t g_default_cmd_info[] = {
{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}},
#endif
};
static void audio_feed_task(void *arg)
+2
View File
@@ -50,6 +50,8 @@ typedef enum {
SR_CMD_NEXT,
SR_CMD_PLAY,
SR_CMD_PAUSE,
SR_CMD_AC_ON,
SR_CMD_AC_OFF,
SR_CMD_MAX,
} sr_user_cmd_t;
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -19,7 +19,7 @@
#include "ui_sr.h"
#include "app_sr_handler.h"
#include "settings.h"
#include "ui_sensor_monitor.h"
static const char *TAG = "sr_handler";
@@ -248,8 +248,7 @@ void sr_handler_task(void *pvParam)
last_player_state = AUDIO_PLAYER_STATE_PLAYING;
break;
case SR_CMD_PLAY:
ESP_LOGW(TAG, "SR_CMD_PLAY:%d, last_player_state:%d", audio_player_get_state(), last_player_state);
ESP_LOGD(TAG, "SR_CMD_PLAY:%d, last_player_state:%d", audio_player_get_state(), last_player_state);
if (AUDIO_PLAYER_STATE_IDLE == audio_player_get_state()) {
file_iterator_get_full_path_from_index(file_iterator, file_iterator_get_index(file_iterator), filename, sizeof(filename));
fp = fopen(filename, "rb");
@@ -267,6 +266,15 @@ void sr_handler_task(void *pvParam)
audio_player_pause();
last_player_state = AUDIO_PLAYER_STATE_PAUSE;
break;
case SR_CMD_AC_ON:
ui_sensor_set_ac_poweron();
break;
case SR_CMD_AC_OFF:
ui_sensor_set_ac_poweroff();
break;
default:
ESP_LOGE(TAG, "Unknow cmd");
break;
+5 -13
View File
@@ -1,16 +1,8 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE 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-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <string.h>
+5 -13
View File
@@ -1,16 +1,8 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE 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-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#ifndef _IOT_FILE_MANAGER_H_
#define _IOT_FILE_MANAGER_H_
File diff suppressed because it is too large Load Diff
@@ -84,6 +84,7 @@ void boot_animate_start(void (*fn)(void))
};
for (size_t i = 0; i < sizeof(arc) / sizeof(arc[0]); i++) {
arc[i] = lv_arc_create(page);
lv_obj_clear_flag(arc[i], LV_OBJ_FLAG_CLICKABLE);
lv_obj_set_size(arc[i], 220 - 30 * i, 220 - 30 * i);
lv_arc_set_bg_angles(arc[i], 120 * i, 0 + 120 * i);
lv_arc_set_value(arc[i], 0);
+11 -7
View File
@@ -56,14 +56,17 @@ static void ui_player_page_vol_dec_click_cb(lv_event_t *e)
static void play_present()
{
char filename[128];
file_iterator_get_full_path_from_index(file_iterator, file_iterator_get_index(file_iterator), filename, sizeof(filename));
FILE *fp = fopen(filename, "rb");
if (!fp) {
ESP_LOGE(TAG, "unable to open '%s'", filename);
return;
if(AUDIO_PLAYER_STATE_PAUSE == audio_player_get_state()) {
audio_player_resume();
} else {
file_iterator_get_full_path_from_index(file_iterator, file_iterator_get_index(file_iterator), filename, sizeof(filename));
FILE *fp = fopen(filename, "rb");
if (!fp) {
ESP_LOGE(TAG, "unable to open '%s'", filename);
return;
}
audio_player_play(fp);
}
audio_player_play(fp);
}
static void ui_player_page_pause_click_cb(lv_event_t *e)
@@ -98,6 +101,7 @@ static void ui_player_page_next_click_cb(lv_event_t *e)
{
lv_obj_t *obj = lv_event_get_user_data(e);
file_iterator_next(file_iterator);
play_present();
lv_label_set_text_static(g_lab_file, file_iterator_get_name_from_index(file_iterator, file_iterator_get_index(file_iterator)));
lv_event_t event = {
.user_data = obj,
+215 -189
View File
@@ -47,6 +47,8 @@ LV_FONT_DECLARE(font_en_12);
LV_FONT_DECLARE(font_en_bold_10);
LV_FONT_DECLARE(font_en_16);
LV_FONT_DECLARE(font_en_22);
LV_FONT_DECLARE(font_cn_gb1_16);
LV_FONT_DECLARE(font_cn_gb2_16);
LV_IMG_DECLARE(icon_temp)
LV_IMG_DECLARE(icon_humidity)
@@ -57,13 +59,14 @@ LV_IMG_DECLARE(icon_rader_off)
LV_IMG_DECLARE(icon_air_switch)
LV_IMG_DECLARE(icon_esp_sensor_base)
// static ui_sensor_monitor_img_type_t g_active_air_ctrl_btn_type = UI_AIR_SWITCH;
static void (*g_sensor_monitor_end_cb)(void) = NULL;
//aht21
static float temperature = 0;
static uint8_t humidity = 0;
static float humidity = 0;
static uint8_t Temp = 0;
static uint8_t Hum = 0;
@@ -80,7 +83,7 @@ typedef struct {
} image_src_t;
static const btn_image_src_t air_ctrl_btn_src_list[] = {
{ .type = UI_RADER, .name = "Rader", .img_on = &icon_rader_on, .img_off = &icon_rader_off },
{ .type = UI_RADAR, .name = "Radar", .img_on = &icon_rader_on, .img_off = &icon_rader_off },
{ .type = UI_AIR_SWITCH, .name = "Air Switch", .img_on = &icon_air_switch, .img_off = &icon_air_switch },
};
@@ -105,10 +108,10 @@ static lv_obj_t *reversal_lab = NULL;
static lv_obj_t *temp_sensor_panel = NULL;
static lv_obj_t *temp_value_label;
static lv_obj_t *hum_value_label;
static lv_obj_t *rader_panel = NULL;
static lv_obj_t *rader_image = NULL;
static lv_obj_t *rader_btn = NULL;
static lv_obj_t *rader_btn_lab = NULL;
static lv_obj_t *radar_panel = NULL;
static lv_obj_t *radar_image = NULL;
static lv_obj_t *radar_btn = NULL;
static lv_obj_t *radar_btn_lab = NULL;
static lv_obj_t *air_ctrl_panel = NULL;
static lv_obj_t *btn_ir_setting = NULL;
static lv_obj_t *ir_learning_tips_lab = NULL;
@@ -135,6 +138,48 @@ bool sensor_ir_learn_enable(void)
return ir_learn_enable;
}
esp_err_t ui_sensor_set_ac_poweroff(void)
{
if (!SLIST_EMPTY(&ir_leran_read_off)) {
if (rmt_out_queue) {
xQueueSendFromISR(rmt_out_queue, &ir_leran_read_off, 0);
}
ui_acquire();
if (AIR_SWITCH_REVERSE_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
lv_label_set_text(ac_switch_btn_lab, "Turn off the air");
} else {
lv_label_set_text(ac_switch_btn_lab, "Turn on the air");
}
ui_release();
xEventGroupClearBits(sensor_monitor_event_grp, AIR_POWER_STATE);
return ESP_OK;
} else {
ESP_LOGW(TAG, "not supported");
return ESP_ERR_NOT_SUPPORTED;
}
}
esp_err_t ui_sensor_set_ac_poweron(void)
{
if (!SLIST_EMPTY(&ir_leran_read_on)) {
if (rmt_out_queue) {
xQueueSendFromISR(rmt_out_queue, &ir_leran_read_on, 0);
}
ui_acquire();
if (AIR_SWITCH_REVERSE_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
lv_label_set_text(ac_switch_btn_lab, "Turn on the air");
} else {
lv_label_set_text(ac_switch_btn_lab, "Turn off the air");
}
ui_release();
xEventGroupSetBits(sensor_monitor_event_grp, AIR_POWER_STATE);
return ESP_OK;
} else {
ESP_LOGW(TAG, "not supported");
return ESP_ERR_NOT_SUPPORTED;
}
}
esp_err_t sensor_task_state_event_init(void)
{
sensor_monitor_event_grp = xEventGroupCreate();
@@ -144,10 +189,10 @@ esp_err_t sensor_task_state_event_init(void)
if (true == param->radar_en) {
bsp_board_get_sensor_handle()->set_radar_enable(true);
xEventGroupSetBits( sensor_monitor_event_grp, RADER_SWITCH_STATE );
xEventGroupSetBits(sensor_monitor_event_grp, RADAR_SWITCH_STATE);
} else {
bsp_board_get_sensor_handle()->set_radar_enable(false);
xEventGroupClearBits( sensor_monitor_event_grp, RADER_SWITCH_STATE );
xEventGroupClearBits(sensor_monitor_event_grp, RADAR_SWITCH_STATE);
}
return ESP_OK;
@@ -156,7 +201,7 @@ esp_err_t sensor_task_state_event_init(void)
EventBits_t sensor_task_state_event_get_bits(void)
{
ESP_RETURN_ON_FALSE(sensor_monitor_event_grp, ESP_ERR_INVALID_STATE, TAG, "event group don't init");
return xEventGroupGetBits( sensor_monitor_event_grp );
return xEventGroupGetBits(sensor_monitor_event_grp);
}
static void user_info_send(uint8_t num, char *tips, uint16_t next_delay)
@@ -167,7 +212,6 @@ static void user_info_send(uint8_t num, char *tips, uint16_t next_delay)
memcpy(user_tips_info[num].tips_info, tips, strlen(tips) > 30 ? 30 : strlen(tips));
if (user_info_queue) {
xQueueSendFromISR(user_info_queue, &user_tips_info[num], 0);
// xQueueSend(user_info_queue, &user_tips_info[num], 0);
}
}
}
@@ -289,8 +333,6 @@ static void ir_learn_test_tx_raw(struct ir_learn_sub_list_head *rmt_out)
static void ir_learn_test_tx_task(void *arg)
{
printf("ir learn tx_task start.\n");
struct ir_learn_sub_list_head tx_data;
gpio_config_t io_conf = {};
@@ -305,23 +347,23 @@ static void ir_learn_test_tx_task(void *arg)
ESP_LOGW(TAG, "receive queue creation failed");
}
if ( IR_LEARNING_STATE & xEventGroupGetBits(sensor_monitor_event_grp) ) {
if (IR_LEARNING_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
esp_err_t ret = ir_learn_read_cfg(POWER_ON_PATH, &ir_leran_read_on);
if (ret == ESP_OK) {
printf("air_on ir-data read OK.\n");
ESP_LOGD(TAG, "air_on ir-data read OK.");
}
ret = ir_learn_read_cfg(POWER_OFF_PATH, &ir_leran_read_off);
if (ret == ESP_OK) {
printf("air_off ir-data read OK.\n");
ESP_LOGD(TAG, "air_off ir-data read OK.");
}
}
xEventGroupClearBits( sensor_monitor_event_grp, NEED_DELETE );
xEventGroupClearBits(sensor_monitor_event_grp, NEED_DELETE);
while (1) {
if ((NEED_DELETE & xEventGroupGetBits(sensor_monitor_event_grp))) {
xEventGroupSetBits(sensor_monitor_event_grp, TX_CH_DELETED);
printf("ir learn tx_task delete.\n");
ESP_LOGD(TAG, "ir learn tx_task delete.");
if (rmt_out_queue) {
vQueueDelete(rmt_out_queue);
rmt_out_queue = NULL;
@@ -353,8 +395,7 @@ static void ir_learn_test_save_result(struct ir_learn_sub_list_head *data_save,
static void ir_learn_learn_send_callback(ir_learn_state_t state, uint8_t sub_step, struct ir_learn_sub_list_head *data)
{
// ESP_LOGI(TAG, "Free Stack for server task: '%d'", uxTaskGetStackHighWaterMark(NULL));
const sys_param_t *param = settings_get_parameter();
static uint8_t air_on_ir = 0;
static uint8_t air_off_ir = 0;
switch (state) {
@@ -363,7 +404,7 @@ static void ir_learn_learn_send_callback(ir_learn_state_t state, uint8_t sub_ste
break;
case IR_LEARN_STATE_READY:
ESP_LOGI(TAG, "IR Learn ready");
xEventGroupClearBits( sensor_monitor_event_grp, IR_LEARNING_STATE );
xEventGroupClearBits(sensor_monitor_event_grp, IR_LEARNING_STATE);
ui_acquire();
lv_obj_add_flag(ir_learning_tips_lab, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(ir_learning_btn, LV_OBJ_FLAG_HIDDEN);
@@ -374,7 +415,6 @@ static void ir_learn_learn_send_callback(ir_learn_state_t state, uint8_t sub_ste
break;
case IR_LEARN_STATE_END:
case IR_LEARN_STATE_FAIL:
ESP_LOGI(TAG, "IR_LEARN_STATE_FAIL");
if (ESP_OK == ir_learn_check_valid(&learn_on_head, &ir_leran_data_on)) {
ESP_LOGI(TAG, "IR Learn on ok");
air_on_ir = 1;
@@ -391,7 +431,7 @@ static void ir_learn_learn_send_callback(ir_learn_state_t state, uint8_t sub_ste
air_off_ir = 0;
}
if ( air_on_ir && air_off_ir ) {
if (air_on_ir && air_off_ir) {
ui_acquire();
lv_label_set_text(ir_learning_state_lab, "Learning successful.");
ui_release();
@@ -402,8 +442,13 @@ static void ir_learn_learn_send_callback(ir_learn_state_t state, uint8_t sub_ste
lv_obj_add_flag(ir_learning_prompt_words, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(btn_ir_setting, LV_OBJ_FLAG_HIDDEN);
lv_label_set_text(ir_learning_tips_lab,
"Click the button below to control your air conditioner!");
if (SR_LANG_EN == param->sr_lang) {
lv_label_set_text(ir_learning_tips_lab,
"Click the buton or say\n 'Turn on/off the Air'\n to control your air.");
} else {
lv_label_set_text(ir_learning_tips_lab,
"Click the buton or say\n '打开/关闭空调'\n to control your air.");
}
lv_obj_clear_flag(ir_learning_tips_lab, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(ac_switch_btn, LV_OBJ_FLAG_HIDDEN);
ui_release();
@@ -411,18 +456,18 @@ static void ir_learn_learn_send_callback(ir_learn_state_t state, uint8_t sub_ste
ir_learn_save_cfg(POWER_ON_PATH, &ir_leran_data_on);
esp_err_t ret = ir_learn_read_cfg(POWER_ON_PATH, &ir_leran_read_on);
if (ret == ESP_OK) {
printf("air_on ir-data read OK.\n");
ESP_LOGD(TAG, "air_on ir-data read OK.");
}
ir_learn_save_cfg(POWER_OFF_PATH, &ir_leran_data_off);
ret = ir_learn_read_cfg(POWER_OFF_PATH, &ir_leran_read_off);
if (ret == ESP_OK) {
printf("air_off ir-data read OK.\n");
ESP_LOGD(TAG, "air_off ir-data read OK.");
}
xEventGroupSetBits( sensor_monitor_event_grp, IR_LEARNING_STATE );
xEventGroupSetBits(sensor_monitor_event_grp, IR_LEARNING_STATE);
ir_learn_stop(&ir_learn_handle);
ir_learn_enable = false;
} else {
xEventGroupClearBits( sensor_monitor_event_grp, IR_LEARNING_STATE );
xEventGroupClearBits(sensor_monitor_event_grp, IR_LEARNING_STATE);
ESP_LOGI(TAG, "IR Learn ready");
user_info_send(0, "Learning failed, retry!", 1500);
@@ -471,7 +516,7 @@ static void ir_learn_learn_send_callback(ir_learn_state_t state, uint8_t sub_ste
return;
}
static esp_err_t ir_learn_test(ir_learn_result_cb cb)
static esp_err_t ir_learn_start(ir_learn_result_cb cb)
{
esp_err_t ret = ESP_OK;
@@ -500,7 +545,7 @@ static void ui_sensor_monitor_page_return_click_cb(lv_event_t *e)
ir_learn_clean_sub_data(&ir_leran_data_off);
ir_learn_clean_sub_data(&ir_leran_read_on);
ir_learn_clean_sub_data(&ir_leran_read_off);
xEventGroupClearBits( sensor_monitor_event_grp, SENSOR_MONITOR_ALIVE_STATE );
xEventGroupClearBits(sensor_monitor_event_grp, SENSOR_MONITOR_ALIVE_STATE);
if (timer_handle) {
lv_timer_del(timer_handle);
@@ -515,7 +560,7 @@ static void ui_sensor_monitor_page_return_click_cb(lv_event_t *e)
free(user_tips_info[i].tips_info);
}
if ( 0 == (IR_LEARNING_STATE & xEventGroupGetBits(sensor_monitor_event_grp) )) {
if (0 == (IR_LEARNING_STATE & xEventGroupGetBits(sensor_monitor_event_grp))) {
ir_learn_stop(&ir_learn_handle);
ir_learn_enable = false;
}
@@ -553,7 +598,7 @@ static void ui_next_btn_event(lv_event_t *e)
lv_obj_add_flag(btn_next, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(btn_return, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(temp_sensor_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(rader_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(radar_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(air_ctrl_panel, LV_OBJ_FLAG_HIDDEN);
}
@@ -561,7 +606,7 @@ static void ui_sensor_monitor_btn_ir_setting_event(lv_event_t *e)
{
lv_obj_add_flag(btn_return, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(temp_sensor_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(rader_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(radar_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(air_ctrl_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(reversal_lab, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(relearning_lab, LV_OBJ_FLAG_HIDDEN);
@@ -572,9 +617,8 @@ static void ui_sensor_monitor_btn_ir_setting_event(lv_event_t *e)
static void ui_sensor_monitor_btn_ir_learning_event(lv_event_t *e)
{
if ( SENSOR_BASE_CONNECT_STATE & xEventGroupGetBits(sensor_monitor_event_grp) ) {
printf("IR Learn TEST\n");
ir_learn_test(ir_learn_learn_send_callback);
if (SENSOR_BASE_CONNECT_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
ir_learn_start(ir_learn_learn_send_callback);
}
}
@@ -582,31 +626,9 @@ static void ui_sensor_monitor_btn_ac_switch_event(lv_event_t *e)
{
if (SENSOR_BASE_CONNECT_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
if (AIR_POWER_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
if (!SLIST_EMPTY(&ir_leran_read_off)) {
if (rmt_out_queue) {
xQueueSendFromISR(rmt_out_queue, &ir_leran_read_off, 0);
}
if ( AIR_SWITCH_REVERSE_STATE & xEventGroupGetBits(sensor_monitor_event_grp) ) {
lv_label_set_text(ac_switch_btn_lab, "Turn off the air");
} else {
lv_label_set_text(ac_switch_btn_lab, "Turn on the air");
}
printf("Turn off the air\n");
xEventGroupClearBits( sensor_monitor_event_grp, AIR_POWER_STATE );
}
ui_sensor_set_ac_poweroff();
} else {
if (!SLIST_EMPTY(&ir_leran_read_on)) {
if (rmt_out_queue) {
xQueueSendFromISR(rmt_out_queue, &ir_leran_read_on, 0);
}
if ( AIR_SWITCH_REVERSE_STATE & xEventGroupGetBits(sensor_monitor_event_grp) ) {
lv_label_set_text(ac_switch_btn_lab, "Turn on the air");
} else {
lv_label_set_text(ac_switch_btn_lab, "Turn off the air");
}
printf("Turn on the air\n");
xEventGroupSetBits( sensor_monitor_event_grp, AIR_POWER_STATE );
}
ui_sensor_set_ac_poweron();
}
}
}
@@ -646,12 +668,12 @@ static void update_timer_cb(lv_timer_t *timer)
char value_str[2] = {0};
sprintf(value_str, "%d", Temp);
lv_label_set_text(temp_value_label, value_str);
Hum = (uint8_t)humidity;
fractionalPart = humidity - Hum;
if (fractionalPart > 0.5) {
Hum++;
}
Hum += 10;
if (Hum >= 100) {
Hum = 99;
}
@@ -662,69 +684,66 @@ static void update_timer_cb(lv_timer_t *timer)
/**
* @brief update radar status
*/
if ( (RADER_SWITCH_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) ) {
if ((RADAR_SWITCH_STATE & xEventGroupGetBits(sensor_monitor_event_grp))) {
if (true == bsp_board_get_sensor_handle()->get_radar_status()) {
xEventGroupSetBits( sensor_monitor_event_grp, RADER_STATE );
if ( SENSOR_MONITOR_ALIVE_STATE & sensor_task_state_event_get_bits() ) {
lv_img_set_src(rader_image, air_ctrl_btn_src_list[0].img_on);
xEventGroupSetBits(sensor_monitor_event_grp, RADAR_STATE);
if (SENSOR_MONITOR_ALIVE_STATE & sensor_task_state_event_get_bits()) {
lv_img_set_src(radar_image, air_ctrl_btn_src_list[0].img_on);
}
} else {
xEventGroupClearBits( sensor_monitor_event_grp, RADER_STATE );
// printf("no people!\n");
if ( SENSOR_MONITOR_ALIVE_STATE & sensor_task_state_event_get_bits() ) {
lv_img_set_src(rader_image, air_ctrl_btn_src_list[0].img_off);
xEventGroupClearBits(sensor_monitor_event_grp, RADAR_STATE);
if (SENSOR_MONITOR_ALIVE_STATE & sensor_task_state_event_get_bits()) {
lv_img_set_src(radar_image, air_ctrl_btn_src_list[0].img_off);
}
}
}
}
static void ui_rader_btn_event(lv_event_t *e)
static void ui_radar_btn_event(lv_event_t *e)
{
sys_param_t *param = settings_get_parameter();
if (SENSOR_BASE_CONNECT_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
if (RADER_SWITCH_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
xEventGroupClearBits( sensor_monitor_event_grp, RADER_SWITCH_STATE );
if (RADAR_SWITCH_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
xEventGroupClearBits(sensor_monitor_event_grp, RADAR_SWITCH_STATE);
param->radar_en = false;
} else {
xEventGroupSetBits( sensor_monitor_event_grp, RADER_SWITCH_STATE );
xEventGroupSetBits(sensor_monitor_event_grp, RADAR_SWITCH_STATE);
param->radar_en = true;
}
bsp_board_get_sensor_handle()->set_radar_enable(param->radar_en);
settings_write_parameter_to_nvs();
if ( !(RADER_SWITCH_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) ) {
printf("rader close.\n");
lv_obj_set_style_border_color(rader_btn, lv_color_hex(0x9E9E9E), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_label_set_text(rader_btn_lab, "OFF");
lv_obj_set_style_bg_color(rader_btn_lab, lv_color_hex(0x9E9E9E), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_x(rader_btn_lab, -8);
lv_img_set_src(rader_image, air_ctrl_btn_src_list[0].img_off);
if (!(RADAR_SWITCH_STATE & xEventGroupGetBits(sensor_monitor_event_grp))) {
lv_obj_set_style_border_color(radar_btn, lv_color_hex(0x9E9E9E), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_label_set_text(radar_btn_lab, "OFF");
lv_obj_set_style_bg_color(radar_btn_lab, lv_color_hex(0x9E9E9E), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_x(radar_btn_lab, -8);
lv_img_set_src(radar_image, air_ctrl_btn_src_list[0].img_off);
} else {
// printf("rader start\n");
lv_obj_set_style_border_color(rader_btn, lv_color_hex(0xEB4839), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_label_set_text(rader_btn_lab, "ON");
lv_obj_set_style_bg_color(rader_btn_lab, lv_color_hex(0xEB4839), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_x(rader_btn_lab, 8);
lv_obj_set_style_border_color(radar_btn, lv_color_hex(0xEB4839), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_label_set_text(radar_btn_lab, "ON");
lv_obj_set_style_bg_color(radar_btn_lab, lv_color_hex(0xEB4839), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_x(radar_btn_lab, 8);
}
}
}
static void ui_sensor_monitor_air_switch_reversal_btn_event(lv_event_t *e)
{
if ( AIR_SWITCH_REVERSE_STATE & xEventGroupGetBits(sensor_monitor_event_grp) ) {
xEventGroupClearBits( sensor_monitor_event_grp, AIR_SWITCH_REVERSE_STATE );
if (AIR_SWITCH_REVERSE_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
xEventGroupClearBits(sensor_monitor_event_grp, AIR_SWITCH_REVERSE_STATE);
if (AIR_POWER_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
xEventGroupClearBits( sensor_monitor_event_grp, AIR_POWER_STATE );
xEventGroupClearBits(sensor_monitor_event_grp, AIR_POWER_STATE);
} else {
xEventGroupSetBits( sensor_monitor_event_grp, AIR_POWER_STATE );
xEventGroupSetBits(sensor_monitor_event_grp, AIR_POWER_STATE);
}
} else {
xEventGroupSetBits( sensor_monitor_event_grp, AIR_SWITCH_REVERSE_STATE );
xEventGroupSetBits(sensor_monitor_event_grp, AIR_SWITCH_REVERSE_STATE);
if (AIR_POWER_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
xEventGroupClearBits( sensor_monitor_event_grp, AIR_POWER_STATE );
xEventGroupClearBits(sensor_monitor_event_grp, AIR_POWER_STATE);
} else {
xEventGroupSetBits( sensor_monitor_event_grp, AIR_POWER_STATE );
xEventGroupSetBits(sensor_monitor_event_grp, AIR_POWER_STATE);
}
}
lv_obj_add_flag(reversal_lab, LV_OBJ_FLAG_HIDDEN);
@@ -734,13 +753,13 @@ static void ui_sensor_monitor_air_switch_reversal_btn_event(lv_event_t *e)
lv_obj_add_flag(air_switch_reversal_btn, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(btn_return, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(temp_sensor_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(rader_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(radar_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(air_ctrl_panel, LV_OBJ_FLAG_HIDDEN);
}
static void ui_sensor_monitor_relearn_btn_event(lv_event_t *e)
{
printf("relearn.\n");
ESP_LOGD(TAG, "relearn.");
lv_obj_add_flag(reversal_lab, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(relearning_lab, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(relearning_btn, LV_OBJ_FLAG_HIDDEN);
@@ -749,7 +768,7 @@ static void ui_sensor_monitor_relearn_btn_event(lv_event_t *e)
lv_obj_add_flag(ac_switch_btn, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(btn_return, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(temp_sensor_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(rader_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(radar_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(air_ctrl_panel, LV_OBJ_FLAG_HIDDEN);
ir_learn_clean_data(&learn_on_head);
@@ -760,21 +779,19 @@ static void ui_sensor_monitor_relearn_btn_event(lv_event_t *e)
ir_learn_clean_sub_data(&ir_leran_read_off);
if (remove(POWER_ON_PATH) == 0 && remove(POWER_OFF_PATH) == 0) {
printf("remove file succes.\n");
ESP_LOGD(TAG, "remove file succes.\n");
} else {
printf("remove file failed.\n");
ESP_LOGE(TAG, "remove file failed.\n");
}
if ( 0 == (IR_LEARNING_STATE & xEventGroupGetBits(sensor_monitor_event_grp) )) {
printf("ir_learn_stop.\n");
if (0 == (IR_LEARNING_STATE & xEventGroupGetBits(sensor_monitor_event_grp))) {
ESP_LOGD(TAG, "ir_learn_stop.\n");
ir_learn_stop(&ir_learn_handle);
ir_learn_enable = false;
}
vTaskDelay(pdMS_TO_TICKS(1000));
ir_learn_test(ir_learn_learn_send_callback);
ir_learn_start(ir_learn_learn_send_callback);
}
static void ir_learning_settings_close_event(lv_event_t *e)
{
lv_obj_add_flag(reversal_lab, LV_OBJ_FLAG_HIDDEN);
@@ -784,7 +801,7 @@ static void ir_learning_settings_close_event(lv_event_t *e)
lv_obj_add_flag(air_switch_reversal_btn, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(btn_return, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(temp_sensor_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(rader_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(radar_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(air_ctrl_panel, LV_OBJ_FLAG_HIDDEN);
}
@@ -792,12 +809,12 @@ void ui_sensor_monitor_start(void (*fn)(void))
{
ESP_LOGI(TAG, "sensor monitor initialize");
g_sensor_monitor_end_cb = fn;
const sys_param_t *param = settings_get_parameter();
struct stat file_stat;
if ( stat(POWER_ON_PATH, &file_stat) == 0 && stat(POWER_OFF_PATH, &file_stat) == 0) {
xEventGroupSetBits( sensor_monitor_event_grp, IR_LEARNING_STATE );
if (stat(POWER_ON_PATH, &file_stat) == 0 && stat(POWER_OFF_PATH, &file_stat) == 0) {
xEventGroupSetBits(sensor_monitor_event_grp, IR_LEARNING_STATE);
} else {
xEventGroupClearBits( sensor_monitor_event_grp, IR_LEARNING_STATE );
xEventGroupClearBits(sensor_monitor_event_grp, IR_LEARNING_STATE);
}
xTaskCreatePinnedToCore(ir_learn_test_tx_task, "ir_learn_test_tx_task", 1024 * 4, NULL, 10, NULL, 1);
@@ -808,16 +825,16 @@ void ui_sensor_monitor_start(void (*fn)(void))
}
for (int i = 0; i < sizeof(user_tips_info) / sizeof(user_tips_info[0]); i++) {
user_tips_info[i].tips_info = (char *)heap_caps_malloc(30, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
user_tips_info[i].tips_info = (char *)heap_caps_malloc(30, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
if (NULL == user_tips_info[i].tips_info) {
ESP_LOGW(TAG, "user_info[%d] malloc failed", i);
}
}
xEventGroupSetBits( sensor_monitor_event_grp, SENSOR_MONITOR_ALIVE_STATE );
xEventGroupClearBits( sensor_monitor_event_grp, AIR_SWITCH_REVERSE_STATE );
xEventGroupClearBits( sensor_monitor_event_grp, AIR_POWER_STATE );
xEventGroupSetBits( sensor_monitor_event_grp, SENSOR_BASE_CONNECT_STATE );
xEventGroupSetBits(sensor_monitor_event_grp, SENSOR_MONITOR_ALIVE_STATE);
xEventGroupClearBits(sensor_monitor_event_grp, AIR_SWITCH_REVERSE_STATE);
xEventGroupClearBits(sensor_monitor_event_grp, AIR_POWER_STATE);
xEventGroupSetBits(sensor_monitor_event_grp, SENSOR_BASE_CONNECT_STATE);
lv_obj_t *page = lv_obj_create(lv_scr_act());
lv_obj_set_size(page, lv_obj_get_width(lv_obj_get_parent(page)), lv_obj_get_height(lv_obj_get_parent(page)) - lv_obj_get_height(ui_main_get_status_bar()));
lv_obj_set_style_border_width(page, 0, LV_PART_MAIN);
@@ -842,10 +859,10 @@ void ui_sensor_monitor_start(void (*fn)(void))
lv_obj_set_width(reversal_lab, 260);
lv_obj_set_align(reversal_lab, LV_ALIGN_CENTER);
lv_obj_set_style_text_align(reversal_lab, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_label_set_text(reversal_lab, "If the AC power button works opposite to its intended function, click the \"Reversal\" button below to fix it.");
lv_label_set_text(reversal_lab, "If the power button is reversed, click \"Reversal\" button below to fix it.");
lv_obj_set_style_text_color(reversal_lab, lv_color_make(40, 40, 40), LV_STATE_DEFAULT);
lv_obj_set_style_text_font(reversal_lab, &font_en_16, LV_STATE_DEFAULT);
lv_obj_align(reversal_lab, LV_ALIGN_CENTER, 20, -65);
lv_obj_set_style_text_font(reversal_lab, &font_cn_gb2_16, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_align(reversal_lab, LV_ALIGN_CENTER, 20, -75);
lv_obj_add_flag(reversal_lab, LV_OBJ_FLAG_HIDDEN);
air_switch_reversal_btn = lv_btn_create(page);
@@ -854,10 +871,11 @@ void ui_sensor_monitor_start(void (*fn)(void))
lv_obj_add_style(air_switch_reversal_btn, &ui_button_styles()->style_focus_no_outline, LV_STATE_FOCUS_KEY);
lv_obj_add_style(air_switch_reversal_btn, &ui_button_styles()->style_focus_no_outline, LV_STATE_FOCUSED);
lv_obj_set_size(air_switch_reversal_btn, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_align(air_switch_reversal_btn, LV_ALIGN_CENTER, 0, -15);
lv_obj_align(air_switch_reversal_btn, LV_ALIGN_CENTER, 0, -30);
lv_obj_add_flag(air_switch_reversal_btn, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_event_cb(air_switch_reversal_btn, ui_sensor_monitor_air_switch_reversal_btn_event, LV_EVENT_CLICKED, page);
lv_obj_t *air_switch_reversal_btn_lab = lv_label_create(air_switch_reversal_btn);
lv_obj_set_style_text_font(air_switch_reversal_btn_lab, &font_cn_gb2_16, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_label_set_text(air_switch_reversal_btn_lab, "Reversal");
lv_obj_set_style_text_color(air_switch_reversal_btn_lab, lv_palette_main(LV_PALETTE_RED), LV_PART_MAIN);
lv_obj_center(air_switch_reversal_btn_lab);
@@ -866,10 +884,10 @@ void ui_sensor_monitor_start(void (*fn)(void))
lv_obj_set_width(relearning_lab, 260);
lv_obj_set_align(relearning_lab, LV_ALIGN_CENTER);
lv_obj_set_style_text_align(relearning_lab, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_label_set_text(relearning_lab, "To clear the learning history and start IR learning again, just click\nthe \"Relearn\" button.");
lv_label_set_text(relearning_lab, "Click the \"Relearn\" button to clear learning history and start IR learning again.");
lv_obj_set_style_text_color(relearning_lab, lv_color_make(40, 40, 40), LV_STATE_DEFAULT);
lv_obj_set_style_text_font(relearning_lab, &font_en_16, LV_STATE_DEFAULT);
lv_obj_align(relearning_lab, LV_ALIGN_CENTER, 20, 30);
lv_obj_set_style_text_font(relearning_lab, &font_cn_gb2_16, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_align(relearning_lab, LV_ALIGN_CENTER, 20, 20);
lv_obj_add_flag(relearning_lab, LV_OBJ_FLAG_HIDDEN);
relearning_btn = lv_btn_create(page);
@@ -878,10 +896,11 @@ void ui_sensor_monitor_start(void (*fn)(void))
lv_obj_add_style(relearning_btn, &ui_button_styles()->style_focus_no_outline, LV_STATE_FOCUS_KEY);
lv_obj_add_style(relearning_btn, &ui_button_styles()->style_focus_no_outline, LV_STATE_FOCUSED);
lv_obj_set_size(relearning_btn, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_align(relearning_btn, LV_ALIGN_CENTER, 0, 80);
lv_obj_align(relearning_btn, LV_ALIGN_CENTER, 0, 75);
lv_obj_add_flag(relearning_btn, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_event_cb(relearning_btn, ui_sensor_monitor_relearn_btn_event, LV_EVENT_CLICKED, page);
lv_obj_t *relearning_btn_lab = lv_label_create(relearning_btn);
lv_obj_set_style_text_font(relearning_btn_lab, &font_cn_gb2_16, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_label_set_text(relearning_btn_lab, "Relearn");
lv_obj_set_style_text_color(relearning_btn_lab, lv_palette_main(LV_PALETTE_RED), LV_PART_MAIN);
lv_obj_center(relearning_btn_lab);
@@ -932,63 +951,63 @@ void ui_sensor_monitor_start(void (*fn)(void))
lv_obj_align(percent_image, LV_ALIGN_CENTER, 59, 0);
lv_img_set_src(percent_image, sensor_monitor_img_src_list[4].img);
rader_panel = lv_obj_create(page);
lv_obj_set_size(rader_panel, 95, 50);
lv_obj_clear_flag(rader_panel, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_align(rader_panel, LV_ALIGN_TOP_LEFT, 195, -8);
lv_obj_set_style_radius(rader_panel, 10, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(rader_panel, 0, LV_STATE_DEFAULT);
lv_obj_set_style_shadow_opa(rader_panel, LV_OPA_30, LV_STATE_DEFAULT);
lv_obj_set_style_shadow_width(rader_panel, 10, LV_STATE_DEFAULT);
rader_btn = lv_btn_create(rader_panel);
lv_obj_set_size(rader_btn, 46, 18);
lv_obj_set_style_radius(rader_btn, 9, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(rader_btn, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(rader_btn, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
if ( (RADER_SWITCH_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) ) {
lv_obj_set_style_border_color(rader_btn, lv_color_hex(0xCE244F), LV_PART_MAIN | LV_STATE_DEFAULT);
radar_panel = lv_obj_create(page);
lv_obj_set_size(radar_panel, 95, 50);
lv_obj_clear_flag(radar_panel, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_align(radar_panel, LV_ALIGN_TOP_LEFT, 195, -8);
lv_obj_set_style_radius(radar_panel, 10, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(radar_panel, 0, LV_STATE_DEFAULT);
lv_obj_set_style_shadow_opa(radar_panel, LV_OPA_30, LV_STATE_DEFAULT);
lv_obj_set_style_shadow_width(radar_panel, 10, LV_STATE_DEFAULT);
radar_btn = lv_btn_create(radar_panel);
lv_obj_set_size(radar_btn, 46, 18);
lv_obj_set_style_radius(radar_btn, 9, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(radar_btn, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(radar_btn, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
if ((RADAR_SWITCH_STATE & xEventGroupGetBits(sensor_monitor_event_grp))) {
lv_obj_set_style_border_color(radar_btn, lv_color_hex(0xCE244F), LV_PART_MAIN | LV_STATE_DEFAULT);
} else {
lv_obj_set_style_border_color(rader_btn, lv_color_hex(0x9E9E9E), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_color(radar_btn, lv_color_hex(0x9E9E9E), LV_PART_MAIN | LV_STATE_DEFAULT);
}
lv_obj_set_style_border_opa(rader_btn, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_width(rader_btn, 1, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_shadow_color(rader_btn, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_shadow_opa(rader_btn, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_align(rader_btn, LV_ALIGN_CENTER, 19, -8);
lv_obj_add_event_cb(rader_btn, ui_rader_btn_event, LV_EVENT_CLICKED, rader_panel);
rader_btn_lab = lv_label_create(rader_btn);
lv_obj_set_width(rader_btn_lab, 24);
lv_obj_set_height(rader_btn_lab, 12);
if ( (RADER_SWITCH_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) ) {
lv_obj_set_x(rader_btn_lab, 8);
lv_label_set_text(rader_btn_lab, "ON");
lv_obj_set_style_bg_color(rader_btn_lab, lv_color_hex(0xCE244F), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_opa(radar_btn, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_width(radar_btn, 1, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_shadow_color(radar_btn, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_shadow_opa(radar_btn, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_align(radar_btn, LV_ALIGN_CENTER, 19, -8);
lv_obj_add_event_cb(radar_btn, ui_radar_btn_event, LV_EVENT_CLICKED, radar_panel);
radar_btn_lab = lv_label_create(radar_btn);
lv_obj_set_width(radar_btn_lab, 24);
lv_obj_set_height(radar_btn_lab, 12);
if ((RADAR_SWITCH_STATE & xEventGroupGetBits(sensor_monitor_event_grp))) {
lv_obj_set_x(radar_btn_lab, 8);
lv_label_set_text(radar_btn_lab, "ON");
lv_obj_set_style_bg_color(radar_btn_lab, lv_color_hex(0xCE244F), LV_PART_MAIN | LV_STATE_DEFAULT);
} else {
lv_obj_set_x(rader_btn_lab, -8);
lv_label_set_text(rader_btn_lab, "OFF");
lv_obj_set_style_bg_color(rader_btn_lab, lv_color_hex(0x9E9E9E), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_x(radar_btn_lab, -8);
lv_label_set_text(radar_btn_lab, "OFF");
lv_obj_set_style_bg_color(radar_btn_lab, lv_color_hex(0x9E9E9E), LV_PART_MAIN | LV_STATE_DEFAULT);
}
lv_obj_set_y(rader_btn_lab, 0);
lv_obj_set_align(rader_btn_lab, LV_ALIGN_CENTER);
lv_obj_set_style_text_color(rader_btn_lab, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_opa(rader_btn_lab, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_align(rader_btn_lab, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_font(rader_btn_lab, &font_en_bold_10, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_radius(rader_btn_lab, 7, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_y(radar_btn_lab, 0);
lv_obj_set_align(radar_btn_lab, LV_ALIGN_CENTER);
lv_obj_set_style_text_color(radar_btn_lab, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_opa(radar_btn_lab, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_align(radar_btn_lab, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_font(radar_btn_lab, &font_en_bold_10, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_radius(radar_btn_lab, 7, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(rader_btn_lab, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
rader_image = lv_img_create(rader_panel);
lv_obj_align(rader_image, LV_ALIGN_CENTER, -26, 0);
if ( (RADER_SWITCH_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) && (RADER_STATE & xEventGroupGetBits(sensor_monitor_event_grp))) {
lv_img_set_src(rader_image, air_ctrl_btn_src_list[0].img_on);
lv_obj_set_style_bg_opa(radar_btn_lab, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
radar_image = lv_img_create(radar_panel);
lv_obj_align(radar_image, LV_ALIGN_CENTER, -26, 0);
if ((RADAR_SWITCH_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) && (RADAR_STATE & xEventGroupGetBits(sensor_monitor_event_grp))) {
lv_img_set_src(radar_image, air_ctrl_btn_src_list[0].img_on);
} else {
lv_img_set_src(rader_image, air_ctrl_btn_src_list[0].img_off);
lv_img_set_src(radar_image, air_ctrl_btn_src_list[0].img_off);
}
lv_obj_t *rader_label = lv_label_create(rader_panel);
lv_label_set_text_static(rader_label, air_ctrl_btn_src_list[0].name);
lv_obj_set_style_text_color(rader_label, lv_color_make(40, 40, 40), LV_STATE_DEFAULT);
lv_obj_set_style_text_font(rader_label, &font_en_16, LV_STATE_DEFAULT);
lv_obj_align(rader_label, LV_ALIGN_CENTER, 19, 9);
lv_obj_t *radar_label = lv_label_create(radar_panel);
lv_label_set_text_static(radar_label, air_ctrl_btn_src_list[0].name);
lv_obj_set_style_text_color(radar_label, lv_color_make(40, 40, 40), LV_STATE_DEFAULT);
lv_obj_align(radar_label, LV_ALIGN_CENTER, 19, 9);
lv_obj_set_style_text_font(radar_label, &font_cn_gb2_16, LV_PART_MAIN | LV_STATE_DEFAULT);
air_ctrl_panel = lv_obj_create(page);
lv_obj_set_size(air_ctrl_panel, 255, 120);
@@ -1016,20 +1035,27 @@ void ui_sensor_monitor_start(void (*fn)(void))
lv_obj_set_width(ir_learning_tips_lab, 240);
lv_obj_set_height(ir_learning_tips_lab, LV_SIZE_CONTENT); /// 1
lv_obj_set_x(ir_learning_tips_lab, 0);
lv_obj_set_y(ir_learning_tips_lab, -20);
lv_obj_set_y(ir_learning_tips_lab, -23);
lv_obj_set_align(ir_learning_tips_lab, LV_ALIGN_CENTER);
lv_obj_clear_flag(ir_learning_tips_lab, LV_OBJ_FLAG_HIDDEN);
lv_obj_set_style_text_color(ir_learning_tips_lab, lv_color_make(40, 40, 40), LV_STATE_DEFAULT);
lv_obj_set_style_text_align(ir_learning_tips_lab, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_font(ir_learning_tips_lab, &font_en_16, LV_PART_MAIN | LV_STATE_DEFAULT);
if ( IR_LEARNING_STATE & xEventGroupGetBits(sensor_monitor_event_grp) ) {
lv_obj_set_style_text_font(ir_learning_tips_lab, &font_cn_gb2_16, LV_PART_MAIN | LV_STATE_DEFAULT);
if (IR_LEARNING_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
lv_obj_clear_flag(btn_ir_setting, LV_OBJ_FLAG_HIDDEN);
lv_label_set_text(ir_learning_tips_lab,
"Click the button below to control your air conditioner!");
if (SR_LANG_EN == param->sr_lang) {
lv_label_set_text(ir_learning_tips_lab,
"Click the buton or say\n 'Turn on/off the Air'\n to control your air.");
} else {
lv_label_set_text(ir_learning_tips_lab,
"Click the buton or say\n '打开/关闭空调'\n to control your air.");
}
} else {
lv_obj_add_flag(btn_ir_setting, LV_OBJ_FLAG_HIDDEN);
lv_label_set_text(ir_learning_tips_lab,
"To control your AC, IR learning is required. Click the button below to begin the learning process.");
"To control your AC, IR learning is required. Click the button below to begin the learning.");
}
ir_learning_btn = lv_btn_create(air_ctrl_panel);
@@ -1038,13 +1064,13 @@ void ui_sensor_monitor_start(void (*fn)(void))
lv_obj_add_style(ir_learning_btn, &ui_button_styles()->style_focus_no_outline, LV_STATE_FOCUS_KEY);
lv_obj_add_style(ir_learning_btn, &ui_button_styles()->style_focus_no_outline, LV_STATE_FOCUSED);
lv_obj_set_size(ir_learning_btn, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_align(ir_learning_btn, LV_ALIGN_CENTER, 0, 30);
lv_obj_align(ir_learning_btn, LV_ALIGN_CENTER, 0, 37);
lv_obj_add_event_cb(ir_learning_btn, ui_sensor_monitor_btn_ir_learning_event, LV_EVENT_CLICKED, page);
lv_obj_t *ir_learning_btn_lab = lv_label_create(ir_learning_btn);
lv_label_set_text(ir_learning_btn_lab, "OK Let's Go");
lv_obj_set_style_text_color(ir_learning_btn_lab, lv_palette_main(LV_PALETTE_RED), LV_PART_MAIN);
lv_obj_center(ir_learning_btn_lab);
if ( IR_LEARNING_STATE & xEventGroupGetBits(sensor_monitor_event_grp) ) {
if (IR_LEARNING_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
lv_obj_add_flag(ir_learning_btn, LV_OBJ_FLAG_HIDDEN);
} else {
lv_obj_clear_flag(ir_learning_btn, LV_OBJ_FLAG_HIDDEN);
@@ -1059,9 +1085,9 @@ void ui_sensor_monitor_start(void (*fn)(void))
lv_obj_add_flag(ir_learning_prompt_words, LV_OBJ_FLAG_HIDDEN);
lv_obj_set_style_text_color(ir_learning_prompt_words, lv_color_make(40, 40, 40), LV_STATE_DEFAULT);
lv_label_set_text(ir_learning_prompt_words,
"1. Point your controller towards the IR module.\n2. Press the power button of the controller.");
"1. Point your controller towards the IR module.\n2. Press the power button of the controller.");
lv_obj_set_style_text_align(ir_learning_prompt_words, LV_TEXT_ALIGN_LEFT, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_font(ir_learning_prompt_words, &font_en_16, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_font(ir_learning_prompt_words, &font_cn_gb2_16, LV_PART_MAIN | LV_STATE_DEFAULT);
ir_learning_state_lab = lv_label_create(air_ctrl_panel);
lv_obj_set_width(ir_learning_state_lab, LV_SIZE_CONTENT); /// 1
@@ -1071,7 +1097,7 @@ void ui_sensor_monitor_start(void (*fn)(void))
lv_obj_set_align(ir_learning_state_lab, LV_ALIGN_CENTER);
lv_obj_add_flag(ir_learning_state_lab, LV_OBJ_FLAG_HIDDEN);
lv_label_set_text(ir_learning_state_lab, "Press the button");
lv_obj_set_style_text_font(ir_learning_state_lab, &font_en_16, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_font(ir_learning_state_lab, &font_cn_gb2_16, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_color(ir_learning_state_lab, lv_color_make(206, 36, 79), LV_STATE_DEFAULT);
ac_switch_btn = lv_btn_create(air_ctrl_panel);
@@ -1080,15 +1106,15 @@ void ui_sensor_monitor_start(void (*fn)(void))
lv_obj_add_style(ac_switch_btn, &ui_button_styles()->style_focus_no_outline, LV_STATE_FOCUS_KEY);
lv_obj_add_style(ac_switch_btn, &ui_button_styles()->style_focus_no_outline, LV_STATE_FOCUSED);
lv_obj_set_size(ac_switch_btn, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_align(ac_switch_btn, LV_ALIGN_CENTER, 0, 30);
lv_obj_align(ac_switch_btn, LV_ALIGN_CENTER, 0, 32);
lv_obj_add_event_cb(ac_switch_btn, ui_sensor_monitor_btn_ac_switch_event, LV_EVENT_CLICKED, page);
if ( IR_LEARNING_STATE & xEventGroupGetBits(sensor_monitor_event_grp) ) {
if (IR_LEARNING_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
lv_obj_clear_flag(ac_switch_btn, LV_OBJ_FLAG_HIDDEN);
} else {
lv_obj_add_flag(ac_switch_btn, LV_OBJ_FLAG_HIDDEN);
}
ac_switch_btn_lab = lv_label_create(ac_switch_btn);
if ( AIR_POWER_STATE & xEventGroupGetBits(sensor_monitor_event_grp) ) {
if (AIR_POWER_STATE & xEventGroupGetBits(sensor_monitor_event_grp)) {
lv_label_set_text(ac_switch_btn_lab, "Turn off the air");
} else {
lv_label_set_text(ac_switch_btn_lab, "Turn on the air");
@@ -1102,11 +1128,11 @@ void ui_sensor_monitor_start(void (*fn)(void))
esp_err_t ret = bsp_board_get_sensor_handle()->get_humiture(&temperature, &humidity);
if (ret != ESP_OK) {
ESP_LOGI(TAG, "Failed to read AHT21: %d", ret);
xEventGroupClearBits( sensor_monitor_event_grp, SENSOR_BASE_CONNECT_STATE );
ESP_LOGW(TAG, "Failed to read AHT21: %d", ret);
xEventGroupClearBits(sensor_monitor_event_grp, SENSOR_BASE_CONNECT_STATE);
lv_obj_add_flag(btn_return, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(temp_sensor_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(rader_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(radar_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(air_ctrl_panel, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(relearning_lab, LV_OBJ_FLAG_HIDDEN);
lv_label_set_text(temp_value_label, "0");
@@ -1118,7 +1144,7 @@ void ui_sensor_monitor_start(void (*fn)(void))
tips_lab = lv_label_create(page);
lv_label_set_text(tips_lab, "Please mount the esp-box to\nthe sensor accessory");
lv_obj_set_style_text_color(tips_lab, lv_color_make(40, 40, 40), LV_STATE_DEFAULT);
lv_obj_set_style_text_font(tips_lab, &font_en_16, LV_STATE_DEFAULT);
lv_obj_set_style_text_font(tips_lab, &font_cn_gb2_16, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_align(tips_lab, LV_ALIGN_CENTER, 0, 25);
lv_obj_set_style_text_align(tips_lab, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
@@ -1142,7 +1168,7 @@ void ui_sensor_monitor_start(void (*fn)(void))
if (ui_get_btn_op_group()) {
lv_group_add_obj(ui_get_btn_op_group(), btn_return);
lv_group_add_obj(ui_get_btn_op_group(), btn_ir_setting);
lv_group_add_obj(ui_get_btn_op_group(), rader_btn);
lv_group_add_obj(ui_get_btn_op_group(), radar_btn);
lv_group_add_obj(ui_get_btn_op_group(), ir_learning_btn_lab);
lv_group_add_obj(ui_get_btn_op_group(), ac_switch_btn);
lv_group_add_obj(ui_get_btn_op_group(), air_switch_reversal_btn);
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@@ -36,7 +36,7 @@ extern "C" {
#endif
typedef enum {
UI_RADER,
UI_RADAR,
UI_AIR_SWITCH,
} ui_sensor_monitor_img_type_t;
@@ -44,8 +44,8 @@ typedef enum {
SENSOR_MONITOR_ALIVE_STATE = BIT(0),
AIR_SWITCH_REVERSE_STATE = BIT(1),
AIR_POWER_STATE = BIT(2),
RADER_SWITCH_STATE = BIT(3),
RADER_STATE = BIT(4),
RADAR_SWITCH_STATE = BIT(3),
RADAR_STATE = BIT(4),
IR_LEARNING_STATE = BIT(5),
SENSOR_BASE_CONNECT_STATE = BIT(6),
@@ -58,6 +58,24 @@ EventBits_t sensor_task_state_event_get_bits(void);
void ui_sensor_monitor_start(void (*fn)(void));
bool sensor_ir_learn_enable(void);
/**
* @brief Send AC poweron cmd, must enter ui_sensor_monitor page
*
* @return
* - ESP_OK On success
* - ESP_ERR_NOT_SUPPORTED This function is not supported.
*/
esp_err_t ui_sensor_set_ac_poweron(void);
/**
* @brief Send AC poweroff cmd, must enter ui_sensor_monitor page
*
* @return
* - ESP_OK On success
* - ESP_ERR_NOT_SUPPORTED This function is not supported.
*/
esp_err_t ui_sensor_set_ac_poweroff(void);
#ifdef __cplusplus
}
#endif
+4 -1
View File
@@ -18,4 +18,7 @@ dependencies:
espressif/led_strip: "~2.0.0"
espressif/json_generator: ^1
espressif/json_parser: =1.0.0
espressif/qrcode: ^0.1.0
espressif/qrcode: ^0.1.0
espressif/ir_learn: ^0.1.0
espressif/aht20: "^0.1.0"
espressif/at581x: "^0.1.0"
+1 -1
View File
@@ -11,7 +11,7 @@
/** Minor version number (x.X.x) */
#define BOX_DEMO_VERSION_MINOR 2
/** Patch version number (x.x.X) */
#define BOX_DEMO_VERSION_PATCH 1
#define BOX_DEMO_VERSION_PATCH 4
/**
* Macro to convert version number into an integer
+4 -4
View File
@@ -1,7 +1,7 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "bsp/esp-bsp.h"
@@ -25,7 +25,7 @@ void app_main(void)
*
*/
bsp_display_lock(0);
#if LV_USE_DEMO_WIDGETS
lv_demo_widgets(); /* A widgets example. This is what you get out of the box */
#endif
@@ -47,4 +47,4 @@ void app_main(void)
#endif
bsp_display_unlock();
}
}
+5 -13
View File
@@ -1,16 +1,8 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE 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-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <string.h>
+5 -13
View File
@@ -1,16 +1,8 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE 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-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#ifndef _IOT_FILE_MANAGER_H_
#define _IOT_FILE_MANAGER_H_
File diff suppressed because it is too large Load Diff

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