mirror of
https://github.com/espressif/esp-idf.git
synced 2026-08-18 06:35:35 +03:00
Merge branch 'feature/add-eventfd' into 'master'
vfs: add eventfd support See merge request espressif/esp-idf!12573
This commit is contained in:
6
examples/system/eventfd/CMakeLists.txt
Normal file
6
examples/system/eventfd/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
# 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)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(eventfd)
|
||||
8
examples/system/eventfd/Makefile
Normal file
8
examples/system/eventfd/Makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := eventfd
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
74
examples/system/eventfd/README.md
Normal file
74
examples/system/eventfd/README.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# eventfd example
|
||||
|
||||
The example demonstrates the use of `eventfd()` to collect events from other tasks and ISRs in a
|
||||
`select()` based main loop. The example starts two tasks and installs a timer interrupt handler:
|
||||
1. The first task writes to the first `eventfd` periodically.
|
||||
2. The timer interrupt handler writes to the second `eventfd`.
|
||||
3. The second task collects the event from two fds with a `select()` loop.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example should be able to run on any commonly available ESP32, ESP32S2, ESP32S3 or ESP32C3 development board.
|
||||
|
||||
### Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
The default config will work.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(Replace PORT with the name of the serial port to use.)
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
The following log output should appear when the example runs (note that the bootloader log has been omitted).
|
||||
|
||||
```
|
||||
I (4310) eventfd_example: Time: 1.99s
|
||||
I (4310) eventfd_example: Select timeout
|
||||
I (4310) eventfd_example: =================================
|
||||
I (4310) eventfd_example: Select timeouted for 1 times
|
||||
I (4320) eventfd_example: Timer triggerred for 0 times
|
||||
I (4320) eventfd_example: Progress triggerred for 0 times
|
||||
I (4330) eventfd_example: =================================
|
||||
I (4810) eventfd_example: Time: 2.50s
|
||||
I (4810) eventfd_example: TimerEvent fd event triggered
|
||||
I (5810) eventfd_example: Time: 3.49s
|
||||
I (5810) eventfd_example: Progress fd event triggered
|
||||
I (7310) eventfd_example: Time: 5.00s
|
||||
I (7310) eventfd_example: TimerEvent fd event triggered
|
||||
I (9310) eventfd_example: Time: 6.99s
|
||||
I (9310) eventfd_example: Select timeout
|
||||
I (9310) eventfd_example: Time: 6.99s
|
||||
I (9310) eventfd_example: Progress fd event triggered
|
||||
I (9810) eventfd_example: Time: 7.50s
|
||||
I (9810) eventfd_example: TimerEvent fd event triggered
|
||||
I (11810) eventfd_example: Time: 9.49s
|
||||
I (11810) eventfd_example: Select timeout
|
||||
I (12310) eventfd_example: Time: 10.00s
|
||||
I (12310) eventfd_example: TimerEvent fd event triggered
|
||||
I (12810) eventfd_example: Time: 10.49s
|
||||
I (12810) eventfd_example: Progress fd event triggered
|
||||
I (14810) eventfd_example: Time: 12.49s
|
||||
I (14810) eventfd_example: Select timeout
|
||||
I (14810) eventfd_example: =================================
|
||||
I (14810) eventfd_example: Select timeouted for 4 times
|
||||
I (14820) eventfd_example: Timer triggerred for 4 times
|
||||
I (14820) eventfd_example: Progress triggerred for 3 times
|
||||
I (14830) eventfd_example: =================================
|
||||
```
|
||||
29
examples/system/eventfd/example_test.py
Normal file
29
examples/system/eventfd/example_test.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
import ttfw_idf
|
||||
from tiny_test_fw import Env, Utility
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC')
|
||||
def test_examples_eventfd(env, extra_data):
|
||||
# type: (Env, None) -> None
|
||||
|
||||
dut = env.get_dut('eventfd', 'examples/system/eventfd')
|
||||
dut.start_app()
|
||||
|
||||
dut.expect('cpu_start: Starting scheduler', timeout=30)
|
||||
|
||||
exp_list = [
|
||||
'eventfd_example: Select timeouted for 4 times',
|
||||
'eventfd_example: Timer triggerred for 4 times',
|
||||
'eventfd_example: Progress triggerred for 3 times',
|
||||
]
|
||||
|
||||
Utility.console_log('Expecting:{}{}'.format(os.linesep, os.linesep.join(exp_list)))
|
||||
dut.expect_all(*exp_list, timeout=60)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_eventfd()
|
||||
3
examples/system/eventfd/main/CMakeLists.txt
Normal file
3
examples/system/eventfd/main/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "eventfd_example.c"
|
||||
LDFRAGMENTS linker.lf
|
||||
INCLUDE_DIRS ".")
|
||||
6
examples/system/eventfd/main/component.mk
Normal file
6
examples/system/eventfd/main/component.mk
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
||||
COMPONENT_ADD_LDFRAGMENTS += linker.lf
|
||||
166
examples/system/eventfd/main/eventfd_example.c
Normal file
166
examples/system/eventfd/main/eventfd_example.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/* eventfd example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include "driver/timer.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_vfs.h"
|
||||
#include "esp_vfs_dev.h"
|
||||
#include "esp_vfs_eventfd.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "hal/timer_types.h"
|
||||
|
||||
#define TIMER_DIVIDER 16
|
||||
#define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER)
|
||||
#define MS_PER_S 1000
|
||||
#define TIMER_INTERVAL_SEC 2.5
|
||||
#define TEST_WITHOUT_RELOAD 0
|
||||
#define PROGRESS_INTERVAL_MS 3500
|
||||
#define TIMER_SIGNAL 1
|
||||
#define PROGRESS_SIGNAL 2
|
||||
|
||||
static const char *TAG = "eventfd_example";
|
||||
|
||||
int s_timer_fd;
|
||||
int s_progress_fd;
|
||||
|
||||
static void eventfd_timer_group0_isr(void *para)
|
||||
{
|
||||
timer_spinlock_take(TIMER_GROUP_0);
|
||||
int timer_idx = (int) para;
|
||||
|
||||
uint32_t timer_intr = timer_group_get_intr_status_in_isr(TIMER_GROUP_0);
|
||||
uint64_t timer_counter_value = timer_group_get_counter_value_in_isr(TIMER_GROUP_0, timer_idx);
|
||||
|
||||
if (timer_intr & TIMER_INTR_T0) {
|
||||
timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
|
||||
timer_counter_value += (uint64_t) (TIMER_INTERVAL_SEC * TIMER_SCALE);
|
||||
timer_group_set_alarm_value_in_isr(TIMER_GROUP_0, timer_idx, timer_counter_value);
|
||||
}
|
||||
|
||||
timer_group_enable_alarm_in_isr(TIMER_GROUP_0, timer_idx);
|
||||
|
||||
uint64_t signal = TIMER_SIGNAL;
|
||||
ssize_t val = write(s_timer_fd, &signal, sizeof(signal));
|
||||
assert(val == sizeof(signal));
|
||||
timer_spinlock_give(TIMER_GROUP_0);
|
||||
}
|
||||
|
||||
static void eventfd_timer_init(int timer_idx, double timer_interval_sec)
|
||||
{
|
||||
timer_config_t config = {
|
||||
.divider = TIMER_DIVIDER,
|
||||
.counter_dir = TIMER_COUNT_UP,
|
||||
.counter_en = TIMER_PAUSE,
|
||||
.alarm_en = TIMER_ALARM_EN,
|
||||
.auto_reload = false,
|
||||
};
|
||||
ESP_ERROR_CHECK(timer_init(TIMER_GROUP_0, timer_idx, &config));
|
||||
|
||||
ESP_ERROR_CHECK(timer_set_counter_value(TIMER_GROUP_0, timer_idx, 0x00000000ULL));
|
||||
|
||||
ESP_ERROR_CHECK(timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE));
|
||||
ESP_ERROR_CHECK(timer_enable_intr(TIMER_GROUP_0, timer_idx));
|
||||
ESP_ERROR_CHECK(timer_isr_register(TIMER_GROUP_0, timer_idx, eventfd_timer_group0_isr,
|
||||
NULL, ESP_INTR_FLAG_IRAM, NULL));
|
||||
|
||||
ESP_ERROR_CHECK(timer_start(TIMER_GROUP_0, timer_idx));
|
||||
}
|
||||
|
||||
static void worker_task(void *arg)
|
||||
{
|
||||
while (true) {
|
||||
vTaskDelay(pdMS_TO_TICKS(PROGRESS_INTERVAL_MS));
|
||||
uint64_t signal = PROGRESS_SIGNAL;
|
||||
ssize_t val = write(s_progress_fd, &signal, sizeof(signal));
|
||||
assert(val == sizeof(signal));
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void collector_task(void *arg)
|
||||
{
|
||||
esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&config));
|
||||
|
||||
s_timer_fd = eventfd(0, EFD_SUPPORT_ISR);
|
||||
s_progress_fd = eventfd(0, 0);
|
||||
assert(s_timer_fd > 0);
|
||||
assert(s_progress_fd > 0);
|
||||
|
||||
int maxFd = s_progress_fd > s_timer_fd ? s_progress_fd : s_timer_fd;
|
||||
int select_timeout_count = 0;
|
||||
int timer_trigger_count = 0;
|
||||
int progress_trigger_count = 0;
|
||||
|
||||
for (size_t i = 0; ; i++) {
|
||||
struct timeval timeout;
|
||||
uint64_t signal;
|
||||
|
||||
timeout.tv_sec = 2;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
fd_set readfds;
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(s_timer_fd, &readfds);
|
||||
FD_SET(s_progress_fd, &readfds);
|
||||
|
||||
int num_triggered = select(maxFd + 1, &readfds, NULL, NULL, &timeout);
|
||||
assert(num_triggered >= 0);
|
||||
|
||||
uint64_t task_counter_value;
|
||||
timer_get_counter_value(TIMER_GROUP_0, TIMER_0, &task_counter_value);
|
||||
ESP_LOGI(TAG, "Time: %.2fs", (double)task_counter_value / TIMER_SCALE);
|
||||
|
||||
if (FD_ISSET(s_progress_fd, &readfds)) {
|
||||
ssize_t ret = read(s_progress_fd, &signal, sizeof(signal));
|
||||
assert(ret == sizeof(signal));
|
||||
assert(signal == PROGRESS_SIGNAL);
|
||||
progress_trigger_count++;
|
||||
ESP_LOGI(TAG, "Progress fd event triggered");
|
||||
}
|
||||
if (FD_ISSET(s_timer_fd, &readfds)) {
|
||||
ssize_t ret = read(s_timer_fd, &signal, sizeof(signal));
|
||||
assert(ret == sizeof(signal));
|
||||
assert(signal == TIMER_SIGNAL);
|
||||
timer_trigger_count++;
|
||||
ESP_LOGI(TAG, "TimerEvent fd event triggered");
|
||||
}
|
||||
if (num_triggered == 0) {
|
||||
select_timeout_count++;
|
||||
ESP_LOGI(TAG, "Select timeout");
|
||||
}
|
||||
|
||||
if (i % 10 == 0) {
|
||||
ESP_LOGI(TAG, "=================================");
|
||||
ESP_LOGI(TAG, "Select timeouted for %d times", select_timeout_count);
|
||||
ESP_LOGI(TAG, "Timer triggerred for %d times", timer_trigger_count);
|
||||
ESP_LOGI(TAG, "Progress triggerred for %d times", progress_trigger_count);
|
||||
ESP_LOGI(TAG, "=================================");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
timer_deinit(TIMER_GROUP_0, TIMER_0);
|
||||
close(s_timer_fd);
|
||||
close(s_progress_fd);
|
||||
esp_vfs_eventfd_unregister();
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
eventfd_timer_init(TIMER_0, TIMER_INTERVAL_SEC);
|
||||
xTaskCreate(worker_task, "worker_task", 4 * 1024, NULL, 5, NULL);
|
||||
xTaskCreate(collector_task, "collector_task", 4 * 1024, NULL, 5, NULL);
|
||||
}
|
||||
4
examples/system/eventfd/main/linker.lf
Normal file
4
examples/system/eventfd/main/linker.lf
Normal file
@@ -0,0 +1,4 @@
|
||||
[mapping:main]
|
||||
archive: libmain.a
|
||||
entries:
|
||||
eventfd_example:eventfd_timer_group0_isr (noflash)
|
||||
Reference in New Issue
Block a user