#task #interrupt #esp32 #freertos
Вопрос:
Я создаю свет на лестнице с 2 датчиками движения вверху и кнопкой, которая включает последовательность светодиодных полос в зависимости от того, с какой стороны она обнаруживает движение. Я использую FreeRTOS и сделал 2 задачи и 2 прерывания, и они идентичны по сборке, но я могу заставить работать только ту, которая называется nside_interrupt. Это не проблема с пин-кодом, он обнаруживает cside, если я меняю пин-коды, поэтому я думаю, что проблема заключается в прерывании. Включен только код, вызывающий проблемы.
Любая помощь будет очень признательна =)
Основной код (tcp_server.c):
#include <stdio.h>
#include <stdlib.h>
#include "led_strip.h"
#include "motion_detection.h"
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "driver/gpio.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>
#define PORT CONFIG_EXAMPLE_PORT
#define ESP_INR_FLAG_DEFAULT 0
#define MOTION_SENSOR_CSIDE_PIN 2
#define MOTION_SENSOR_NSIDE_PIN 4
int delay_sec = 5;
unsigned char mode_on_off_auto = 2; // 0
static const char *TAG = "Stairs project";
TaskHandle_t ISR = NULL;
void IRAM_ATTR mscside_isr_handler(void *arg)
{
xTaskResumeFromISR(ISR);
}
void IRAM_ATTR msnside_isr_handler(void *arg)
{
xTaskResumeFromISR(ISR);
}
void cside_interrupt(void *arg) {
while(1) {
vTaskSuspend(NULL);
if (mode_on_off_auto == 2) {
xTaskCreate(Active_Cside, "Active_Cside", 4096, (void*)delay_sec, 1, NULL);
}
}
}
void nside_interrupt(void *arg) {
while(1) {
vTaskSuspend(NULL);
if (mode_on_off_auto == 2) {
xTaskCreate(Active_Nside, "Active_Nside", 4096, (void*)delay_sec, 1, NULL);
}
}
}
void parse_message(char *message) {
if (strstr(message, "Color") != NULL) {
unsigned long color_RGB = strtol(message, NULL, 16);
ESP_LOGI(TAG, "COLOR %ld", color_RGB);
ls_set_color_RGB(color_RGB);
if (mode_on_off_auto == 0) {
ls_update_color(color_RGB);
}
}
else if (strstr(message, "Steps") != NULL) {
int steps = atoi(message);
ESP_LOGI(TAG, "STEPS %d", steps);
ls_set_steps(steps);
}
else if (strstr(message, "Leds") != NULL) {
int leds = atoi(message);
ESP_LOGI(TAG, "LEDS %d", leds);
ls_set_leds(leds);
} else if (strstr(message, "Cside") != NULL) {
if (mode_on_off_auto == 2) {
xTaskCreate(Active_Cside, "Active_Cside", 4096, (void*)delay_sec, 1, NULL);
}
} else if (strstr(message, "Nside") != NULL) {
if (mode_on_off_auto == 2) {
xTaskCreate(Active_Nside, "Active_Nside", 4096, (void*)delay_sec, 1, NULL);
}
} else if (strstr(message, "On") != NULL) {
ls_update_color(ls_get_color_RGB());
mode_on_off_auto = 0;
} else if (strstr(message, "Off") != NULL) {
ls_update_color(0);
mode_on_off_auto = 1;
} else if (strstr(message, "Auto") != NULL) {
ls_update_color(0);
mode_on_off_auto = 2;
} else if (strstr(message, "Brightness") != NULL) {
int brightness = atoi(message);
ls_brightness(brightness);
} else if (strstr(message, "Dim") != NULL) {
int procent = atoi(message);
ls_dim(procent);
} else if (strstr(message, "Brighten") != NULL) {
int procent = atoi(message);
ls_brighten(procent);
}
else {
ls_get_color_RGB();
ESP_LOGI(TAG, "Unknown command: %s", message);
}
}
void send_back_received(const int sock, int len, char *message) {
// send() can return less bytes than supplied length.
// Walk-around for robust implementation.
int loop_len = len;
while (loop_len > 0) {
int written = send(sock, message (len - loop_len), loop_len, 0);
if (written < 0) {
ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
}
loop_len -= written;
}
}
static void app_connection(const int sock)
{
int len;
char rx_buffer[128];
do {
len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
if (len < 0) {
ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno);
} else if (len == 0) {
ESP_LOGW(TAG, "Connection closed");
} else {
rx_buffer[len] = 0; // Null-terminate whatever is received and treat it like a string
ESP_LOGI(TAG, "Received %d bytes: %s", len, rx_buffer);
// Copy data to variable based on content
parse_message(rx_buffer);
send_back_received(sock, len, rx_buffer);
}
} while (len > 0);
}
static void tcp_server_task()
{
char addr_str[128];
int addr_family = AF_INET;
int ip_protocol = 0;
int opt = 1;
struct sockaddr_in6 dest_addr;
struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)amp;dest_addr;
dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY);
dest_addr_ip4->sin_family = AF_INET;
dest_addr_ip4->sin_port = htons(PORT);
ip_protocol = IPPROTO_IP;
int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (listen_sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
vTaskDelete(NULL);
return;
}
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, amp;opt, sizeof(opt));
ESP_LOGI(TAG, "Socket created");
int err = bind(listen_sock, (struct sockaddr *)amp;dest_addr, sizeof(dest_addr));
if (err != 0) {
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
ESP_LOGE(TAG, "IPPROTO: %d", addr_family);
goto CLEAN_UP;
}
ESP_LOGI(TAG, "Socket bound, port %d", PORT);
err = listen(listen_sock, 1);
if (err != 0) {
ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
goto CLEAN_UP;
}
while (1) {
ESP_LOGI(TAG, "Socket listening");
struct sockaddr_in6 source_addr;
uint addr_len = sizeof(source_addr);
int sock = accept(listen_sock, (struct sockaddr *)amp;source_addr, amp;addr_len);
if (sock < 0) {
ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
break;
}
inet_ntoa_r(((struct sockaddr_in *)amp;source_addr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1);
ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str);
app_connection(sock);
shutdown(sock, 0);
close(sock);
}
CLEAN_UP:
close(listen_sock);
vTaskDelete(NULL);
}
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(example_connect()); // Make wifi connection. examples/protocols/README.md
gpio_setup();
ls_setup(GPIO_NUM_0);
xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 5, NULL);
}
void gpio_setup(void) { // https://www.youtube.com/watch?v=VkCvKtRsunUamp;ab_channel=ControltheController
gpio_pad_select_gpio(MOTION_SENSOR_CSIDE_PIN);
gpio_pad_select_gpio(MOTION_SENSOR_NSIDE_PIN);
// Set pin direction
gpio_set_direction(MOTION_SENSOR_CSIDE_PIN, GPIO_MODE_INPUT);
gpio_set_direction(MOTION_SENSOR_NSIDE_PIN, GPIO_MODE_INPUT);
// Set interrupt on falling edge
gpio_set_intr_type(MOTION_SENSOR_CSIDE_PIN, GPIO_INTR_NEGEDGE);
gpio_set_intr_type(MOTION_SENSOR_NSIDE_PIN, GPIO_INTR_NEGEDGE);
// Install default ISR-service
gpio_install_isr_service(ESP_INR_FLAG_DEFAULT);
// Attach ISR-routines
gpio_isr_handler_add(MOTION_SENSOR_CSIDE_PIN, mscside_isr_handler, NULL);
gpio_isr_handler_add(MOTION_SENSOR_NSIDE_PIN, msnside_isr_handler, NULL);
// Create and start task
xTaskCreate( cside_interrupt, "cside_interrupt", 4096, NULL, 10, amp;ISR );
xTaskCreate( nside_interrupt, "nside_interrupt", 4096, NULL, 10, amp;ISR );
}
Функции обнаружения движения (motion_detection.c)
#include "motion_detection.h"
unsigned char Cflag = 0;
unsigned char Nflag = 0;
unsigned char rerun = 0;
unsigned int stepdelay = 200;
static const char *TAG = "Motion detection driver";
void Active_Cside(void * ptr) {
int delay_sec = (int) ptr;
unsigned long tempColor = ls_get_color_RGB();
if (Nflag == 0 amp;amp; Cflag == 0) {
ESP_LOGI(TAG, "Cside activated with rerun=%i", rerun);
Cflag = 1;
rerun = 0;
// Call waterfall with 200 ms delay, primary and off color
ls_walk_uc_side(stepdelay, tempColor, 0);
for(int i = delay_sec*10; i > 0; i--) {
// 100 ms delay
vTaskDelay(100 / portTICK_PERIOD_MS);
if (i % 10 == 0) {
ESP_LOGI(TAG, "Time left: %i seconds", i/10);
}
}
if (rerun == 0) {
ls_walk_uc_side(200, 0, tempColor);
Cflag = 0;
}
}
// Check for detection at opposite side
else if (Nflag == 1) {
rerun = 0;
ESP_LOGI(TAG, "Rerun value: %i", rerun);
ESP_LOGI(TAG, "Nside deactivated");
ls_walk_not_uc_side(200, 0, tempColor);
Nflag = 0;
}
else {
rerun ;
ESP_LOGI(TAG, "Rerun value: %i", rerun);
for(int i = delay_sec*10; i > 0; i--) {
// 100 ms delay
vTaskDelay(100 / portTICK_PERIOD_MS);
if (i % 10 == 0) {
ESP_LOGI(TAG, "Time left: %i seconds", i/10);
}
}
rerun--;
ESP_LOGI(TAG, "Rerun value: %i", rerun);
if (rerun == 0) {
ls_walk_uc_side(stepdelay, 0, tempColor);
Cflag = 0;
}
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
vTaskDelete(NULL);
}
void Active_Nside (void * ptr) {
int delay_sec = (int) ptr;
unsigned long tempColor = ls_get_color_RGB();
if (Nflag == 0 amp;amp; Cflag == 0) {
ESP_LOGI(TAG, "Nside activated with rerun=%i", rerun);
Nflag = 1;
rerun = 0;
// Call waterfall with 200 ms delay, primary and off color
ls_walk_not_uc_side(200, tempColor, 0);
for(int i = delay_sec*10; i > 0; i--) {
// 100 ms delay
vTaskDelay(100 / portTICK_PERIOD_MS);
if (i % 10 == 0) {
ESP_LOGI(TAG, "Time left: %i seconds", i/10);
}
}
if (rerun == 0) {
ls_walk_not_uc_side(200, 0, tempColor);
Nflag = 0;
}
}
// Check for detection at opposite side
else if (Cflag == 1) {
rerun = 0;
ESP_LOGI(TAG, "Rerun value: %i", rerun);
ESP_LOGI(TAG, "Cside deactivated");
ls_walk_uc_side(200, 0, tempColor);
Cflag = 0;
}
else {
rerun ;
ESP_LOGI(TAG, "Rerun value: %i", rerun);
for(int i = delay_sec*10; i > 0; i--) {
// 100 ms delay
vTaskDelay(100 / portTICK_PERIOD_MS);
if (i % 10 == 0) {
ESP_LOGI(TAG, "Time left: %i seconds", i/10);
}
}
rerun--;
ESP_LOGI(TAG, "Rerun value: %i", rerun);
if (rerun == 0) {
ls_walk_not_uc_side(200, 0, tempColor);
Cflag = 0;
}
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
vTaskDelete(NULL);
}
Комментарии:
1. Использование xTaskSuspend/Resume(FromISR) в качестве механизма синхронизации не рекомендуется (я бы сказал, неправильно). Например, возобновление запущенной задачи ничего не делает, событие теряется. Также можно динамически создавать/удалять задачи, но это не лучший подход.