Files
watch-watch/main/main.c

191 lines
7.0 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Developed by TComLab
* Version: v0.1
* Date: 2025-12-15
*/
#include <stddef.h>
#include <stdint.h>
#include <stdarg.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "dcdc_controller.h"
#include "ina226_monitor.h"
#include "uart_mux.h"
#include "usb_cdc_cli.h"
#include "usb_cdc_log.h"
#include "watch_config.h"
#include "ws2812_status.h"
static const char *TAG = "watch-watch";
static const char HB_MESSAGE[] = "{\"cmd\":\"status\"}\r\n";
static int noop_vprintf(const char *fmt, va_list args)
{
(void)fmt;
(void)args;
return 0;
}
void app_main(void)
{
esp_log_set_vprintf(noop_vprintf);
if (watch_config_init() != ESP_OK) {
ESP_LOGE(TAG, "Не вдалося ініціалізувати конфігурацію");
} else {
ESP_LOGI(TAG, "Конфігурацію завантажено");
}
if (usb_cdc_cli_init() == ESP_OK) {
ESP_LOGI(TAG, "USB CDC CLI активовано");
} else {
ESP_LOGW(TAG, "Не вдалося запустити USB CLI");
}
bool ws_ready = false;
if (ws2812_status_init() == ESP_OK) {
ws_ready = true;
} else {
ESP_LOGW(TAG, "WS2812 статусний індикатор недоступний");
}
const watch_config_t *cfg = watch_config_get();
const uint32_t start_delay_ms = cfg->heartbeat_start_delay_sec * 1000U;
TickType_t start_delay = pdMS_TO_TICKS(start_delay_ms);
if (start_delay > 0) {
ESP_LOGI(TAG, "Очікування %u с перед стартом опитування", cfg->heartbeat_start_delay_sec);
if (ws_ready) {
ws2812_status_set_startup_hold(start_delay_ms);
}
vTaskDelay(start_delay);
if (ws_ready) {
ws2812_status_set_startup_hold(0);
}
}
ESP_LOGI(TAG, "Запуск watch-watch systems");
if (dcdc_init() != ESP_OK) {
ESP_LOGE(TAG, "Помилка ініціалізації DCDC контролера");
if (ws_ready) {
ws2812_status_set_error(true);
}
return;
}
if (ws_ready) {
ws2812_status_refresh_from_dcdc();
}
if (ina226_monitor_init() == ESP_OK) {
ESP_LOGI(TAG, "INA226 моніторинг активовано");
ina226_monitor_sample(NULL);
} else {
ESP_LOGW(TAG, "Моніторинг навантаження недоступний");
}
if (uart_mux_init() == ESP_OK) {
ESP_LOGI(TAG, "UART мультиплексор активовано");
} else {
ESP_LOGW(TAG, "UART мультиплексор недоступний");
}
const TickType_t mux_timeout = pdMS_TO_TICKS(600);
TickType_t channel_next_hb[DCDC_CHANNEL_COUNT] = {0};
bool channel_powered[DCDC_CHANNEL_COUNT] = {false};
const TickType_t power_on_stagger = pdMS_TO_TICKS(3000);
ESP_LOGI(TAG, "Початок циклічного опитування всіх каналів");
while (true) {
cfg = watch_config_get();
TickType_t hb_period = pdMS_TO_TICKS(cfg->heartbeat_period_sec * 1000U);
if (hb_period == 0) {
hb_period = 1;
}
TickType_t now = xTaskGetTickCount();
size_t channels = dcdc_channel_count();
for (size_t ch = 0; ch < channels; ++ch) {
bool powered = dcdc_get_state(ch);
if (!powered) {
channel_powered[ch] = false;
ESP_LOGI(TAG, "-> Ввімкнення каналу %d", (int)ch);
if (dcdc_enable(ch) == ESP_OK) {
powered = true;
channel_powered[ch] = true;
channel_next_hb[ch] = now + hb_period;
if (ws_ready) {
ws2812_status_set_channel_state(ch, true);
}
vTaskDelay(power_on_stagger);
} else {
ESP_LOGE(TAG, "Не вдалося ввімкнути канал %d", (int)ch);
continue;
}
}
if (!channel_powered[ch]) {
channel_powered[ch] = true;
channel_next_hb[ch] = now + hb_period;
continue;
}
now = xTaskGetTickCount();
if (now < channel_next_hb[ch]) {
continue;
}
ina226_reading_t reading = {0};
if (ina226_monitor_ready() && ina226_monitor_sample(&reading) == ESP_OK) {
ESP_LOGI(TAG, "Живлення: %.2f В, %.2f А, %.2f Вт",
reading.voltage_v, reading.current_a, reading.power_w);
}
if (uart_mux_ready()) {
esp_err_t tx_err = uart_mux_write(ch,
(const uint8_t *)HB_MESSAGE,
sizeof(HB_MESSAGE) - 1,
mux_timeout);
if (tx_err != ESP_OK) {
ESP_LOGW(TAG, "Не вдалося надіслати heartbeat на канал %d: %s",
(int)ch, esp_err_to_name(tx_err));
} else {
uint8_t rx_buffer[CONFIG_WATCH_UART_MUX_DEFAULT_READ_LEN];
size_t received = 0;
esp_err_t rx_err = uart_mux_read(ch,
rx_buffer,
sizeof(rx_buffer),
&received,
mux_timeout);
if (rx_err == ESP_OK) {
if (received > 0) {
ESP_LOGI(TAG, "RX CH%u (%u байт після heartbeat)", (unsigned)ch, (unsigned)received);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, rx_buffer, received, ESP_LOG_INFO);
uart_mux_process_rx(ch, rx_buffer, received);
} else {
ESP_LOGW(TAG, "Канал %d не відповів даними на heartbeat", (int)ch);
uart_mux_report_miss(ch);
}
} else if (rx_err == ESP_ERR_TIMEOUT) {
ESP_LOGW(TAG, "Час очікування відповіді з каналу %d перевищено", (int)ch);
uart_mux_report_miss(ch);
} else {
ESP_LOGW(TAG, "Помилка читання відповіді CH%u: %s",
(unsigned)ch, esp_err_to_name(rx_err));
uart_mux_report_miss(ch);
}
}
} else {
ESP_LOGW(TAG, "UART мультиплексор недоступний, очікування...");
}
channel_next_hb[ch] = now + hb_period;
}
vTaskDelay(pdMS_TO_TICKS(50));
}
}