Improve heartbeat indication and docs

This commit is contained in:
2025-12-16 16:19:33 +02:00
parent f3d5e4018b
commit 89ded8b119
6 changed files with 176 additions and 37 deletions

View File

@@ -7,6 +7,7 @@
#include "uart_mux.h"
#include <string.h>
#include <limits.h>
#include "dcdc_controller.h"
#include "driver/gpio.h"
@@ -18,6 +19,7 @@
#include "freertos/semphr.h"
#include "freertos/task.h"
#include "sdkconfig.h"
#include "ws2812_status.h"
#ifndef CONFIG_WATCH_UART_MUX_CHANNELS
#define CONFIG_WATCH_UART_MUX_CHANNELS 5
@@ -43,6 +45,7 @@ static size_t s_active_channel = SIZE_MAX;
static bool s_initialized;
static int64_t s_last_heartbeat_us[UART_MUX_MAX_CHANNELS];
static TaskHandle_t s_watchdog_task;
static uint8_t s_consecutive_miss[UART_MUX_MAX_CHANNELS];
// Перемикає апаратний мультиплексор на вказаний канал під захистом мьютекса,
// оновлюючи таймстемп останнього heartbeat для контролю watchdog.
@@ -68,7 +71,7 @@ static esp_err_t uart_mux_select_locked(size_t channel)
// якщо канал «мовчить» довше за CONFIG_WATCH_UART_HEARTBEAT_TIMEOUT_SEC.
static void uart_mux_watchdog_task(void *arg)
{
const TickType_t poll_interval = pdMS_TO_TICKS(1000);
const TickType_t poll_interval = pdMS_TO_TICKS(10000);
const TickType_t read_timeout = pdMS_TO_TICKS(10);
const int64_t timeout_us = (int64_t)CONFIG_WATCH_UART_HEARTBEAT_TIMEOUT_SEC * 1000000LL;
uint8_t buffer[CONFIG_WATCH_UART_MUX_DEFAULT_READ_LEN];
@@ -78,6 +81,7 @@ static void uart_mux_watchdog_task(void *arg)
int64_t now = esp_timer_get_time();
for (size_t ch = 0; ch < UART_MUX_MAX_CHANNELS; ++ch) {
if (xSemaphoreTake(s_mutex, pdMS_TO_TICKS(20)) == pdTRUE) {
ws2812_status_indicate_polling(ch, 2000);
if (uart_mux_select_locked(ch) == ESP_OK) {
int read = uart_read_bytes(CONFIG_WATCH_UART_PORT,
buffer,
@@ -85,16 +89,32 @@ static void uart_mux_watchdog_task(void *arg)
read_timeout);
if (read > 0) {
s_last_heartbeat_us[ch] = now;
s_consecutive_miss[ch] = 0;
ws2812_status_set_ack_state(ch, true);
} else if (s_consecutive_miss[ch] < UINT8_MAX) {
s_consecutive_miss[ch]++;
ws2812_status_set_ack_state(ch, false);
}
}
xSemaphoreGive(s_mutex);
}
if (dcdc_get_state(ch) && s_consecutive_miss[ch] >= 3) {
ESP_LOGW(TAG, "CH%u: немає відповіді 3 рази поспіль, перезапуск живлення", (unsigned)ch);
ws2812_status_set_ack_state(ch, false);
dcdc_disable(ch);
vTaskDelay(pdMS_TO_TICKS(2000));
dcdc_enable(ch);
s_consecutive_miss[ch] = 0;
s_last_heartbeat_us[ch] = esp_timer_get_time();
}
if (dcdc_get_state(ch) && s_last_heartbeat_us[ch] > 0 &&
(now - s_last_heartbeat_us[ch]) > timeout_us) {
ESP_LOGW(TAG, "Heartbeat каналу %u втрачено, перезавантаження...", (unsigned)ch);
ws2812_status_set_ack_state(ch, false);
dcdc_disable(ch);
vTaskDelay(pdMS_TO_TICKS(2000));
vTaskDelay(pdMS_TO_TICKS(3000));
dcdc_enable(ch);
s_last_heartbeat_us[ch] = esp_timer_get_time();
}
@@ -156,6 +176,7 @@ esp_err_t uart_mux_init(void)
int64_t now = esp_timer_get_time();
for (size_t ch = 0; ch < UART_MUX_MAX_CHANNELS; ++ch) {
s_last_heartbeat_us[ch] = now;
s_consecutive_miss[ch] = 0;
}
if (xTaskCreate(uart_mux_watchdog_task, "uart_mux_wd", 4096, NULL, 5, &s_watchdog_task) != pdPASS) {
@@ -208,6 +229,10 @@ esp_err_t uart_mux_write(size_t channel, const uint8_t *data, size_t length, Tic
int written = uart_write_bytes(CONFIG_WATCH_UART_PORT, (const char *)data, length);
if (written < 0 || (size_t)written != length) {
err = ESP_FAIL;
} else {
if (uart_wait_tx_done(CONFIG_WATCH_UART_PORT, timeout) != ESP_OK) {
err = ESP_ERR_TIMEOUT;
}
}
}
xSemaphoreGive(s_mutex);