Add KiCad files and USB CDC logging support
This commit is contained in:
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -5,7 +5,7 @@
|
||||
"idf.openOcdConfigs": [
|
||||
"board/esp32s3-builtin.cfg"
|
||||
],
|
||||
"idf.port": "/dev/tty.BLTH",
|
||||
"idf.port": "/dev/tty.usbmodem14301",
|
||||
"idf.toolsPath": "/Users/tarassivas/.espressif",
|
||||
"idf.customExtraVars": {
|
||||
"IDF_TARGET": "esp32s3"
|
||||
@@ -15,5 +15,6 @@
|
||||
"--background-index",
|
||||
"--query-driver=/Users/tarassivas/.espressif/tools/xtensa-esp-elf/esp-14.2.0_20241119/xtensa-esp-elf/bin/xtensa-esp32-elf-gcc",
|
||||
"--compile-commands-dir=${workspaceFolder}/build"
|
||||
]
|
||||
],
|
||||
"idf.flashType": "UART"
|
||||
}
|
||||
|
||||
24
kicad/.gitignore
vendored
Normal file
24
kicad/.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Temporary and local KiCad artifacts
|
||||
*-backups/
|
||||
*.kicad_prl
|
||||
*.kicad_pro-bak
|
||||
*.kicad_sch-bak
|
||||
*.kicad_pcb-bak
|
||||
*.sch-bak
|
||||
*.pcb-bak
|
||||
*.bak
|
||||
|
||||
# Cache and automatically generated tables
|
||||
sym-lib-table-bak
|
||||
fp-lib-table-bak
|
||||
*-cache.lib
|
||||
*-cache.dcm
|
||||
|
||||
# Generated fabrication outputs (regenerate as needed)
|
||||
*.net
|
||||
*.xml
|
||||
*.csv
|
||||
*.tsv
|
||||
*.pos
|
||||
*.ipr
|
||||
*.rpt
|
||||
@@ -0,0 +1,2 @@
|
||||
(kicad_pcb (version 20241229) (generator "pcbnew") (generator_version "9.0")
|
||||
)
|
||||
417
kicad/watch-watchkicad_pro/watch-watchkicad_pro.kicad_pro
Normal file
417
kicad/watch-watchkicad_pro/watch-watchkicad_pro.kicad_pro
Normal file
@@ -0,0 +1,417 @@
|
||||
{
|
||||
"board": {
|
||||
"3dviewports": [],
|
||||
"design_settings": {
|
||||
"defaults": {},
|
||||
"diff_pair_dimensions": [],
|
||||
"drc_exclusions": [],
|
||||
"rules": {},
|
||||
"track_widths": [],
|
||||
"via_dimensions": []
|
||||
},
|
||||
"ipc2581": {
|
||||
"dist": "",
|
||||
"distpn": "",
|
||||
"internal_id": "",
|
||||
"mfg": "",
|
||||
"mpn": ""
|
||||
},
|
||||
"layer_pairs": [],
|
||||
"layer_presets": [],
|
||||
"viewports": []
|
||||
},
|
||||
"boards": [],
|
||||
"cvpcb": {
|
||||
"equivalence_files": []
|
||||
},
|
||||
"erc": {
|
||||
"erc_exclusions": [],
|
||||
"meta": {
|
||||
"version": 0
|
||||
},
|
||||
"pin_map": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
]
|
||||
],
|
||||
"rule_severities": {
|
||||
"bus_definition_conflict": "error",
|
||||
"bus_entry_needed": "error",
|
||||
"bus_to_bus_conflict": "error",
|
||||
"bus_to_net_conflict": "error",
|
||||
"different_unit_footprint": "error",
|
||||
"different_unit_net": "error",
|
||||
"duplicate_reference": "error",
|
||||
"duplicate_sheet_names": "error",
|
||||
"endpoint_off_grid": "warning",
|
||||
"extra_units": "error",
|
||||
"footprint_filter": "ignore",
|
||||
"footprint_link_issues": "warning",
|
||||
"four_way_junction": "ignore",
|
||||
"global_label_dangling": "warning",
|
||||
"hier_label_mismatch": "error",
|
||||
"label_dangling": "error",
|
||||
"label_multiple_wires": "warning",
|
||||
"lib_symbol_issues": "warning",
|
||||
"lib_symbol_mismatch": "warning",
|
||||
"missing_bidi_pin": "warning",
|
||||
"missing_input_pin": "warning",
|
||||
"missing_power_pin": "error",
|
||||
"missing_unit": "warning",
|
||||
"multiple_net_names": "warning",
|
||||
"net_not_bus_member": "warning",
|
||||
"no_connect_connected": "warning",
|
||||
"no_connect_dangling": "warning",
|
||||
"pin_not_connected": "error",
|
||||
"pin_not_driven": "error",
|
||||
"pin_to_pin": "warning",
|
||||
"power_pin_not_driven": "error",
|
||||
"same_local_global_label": "warning",
|
||||
"similar_label_and_power": "warning",
|
||||
"similar_labels": "warning",
|
||||
"similar_power": "warning",
|
||||
"simulation_model_issue": "ignore",
|
||||
"single_global_label": "ignore",
|
||||
"unannotated": "error",
|
||||
"unconnected_wire_endpoint": "warning",
|
||||
"unit_value_mismatch": "error",
|
||||
"unresolved_variable": "error",
|
||||
"wire_dangling": "error"
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"pinned_footprint_libs": [],
|
||||
"pinned_symbol_libs": []
|
||||
},
|
||||
"meta": {
|
||||
"filename": "watch-watchkicad_pro.kicad_pro",
|
||||
"version": 3
|
||||
},
|
||||
"net_settings": {
|
||||
"classes": [
|
||||
{
|
||||
"bus_width": 12,
|
||||
"clearance": 0.2,
|
||||
"diff_pair_gap": 0.25,
|
||||
"diff_pair_via_gap": 0.25,
|
||||
"diff_pair_width": 0.2,
|
||||
"line_style": 0,
|
||||
"microvia_diameter": 0.3,
|
||||
"microvia_drill": 0.1,
|
||||
"name": "Default",
|
||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||
"priority": 2147483647,
|
||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||
"track_width": 0.2,
|
||||
"via_diameter": 0.6,
|
||||
"via_drill": 0.3,
|
||||
"wire_width": 6
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"version": 4
|
||||
},
|
||||
"net_colors": null,
|
||||
"netclass_assignments": null,
|
||||
"netclass_patterns": []
|
||||
},
|
||||
"pcbnew": {
|
||||
"last_paths": {
|
||||
"gencad": "",
|
||||
"idf": "",
|
||||
"netlist": "",
|
||||
"plot": "",
|
||||
"pos_files": "",
|
||||
"specctra_dsn": "",
|
||||
"step": "",
|
||||
"svg": "",
|
||||
"vrml": ""
|
||||
},
|
||||
"page_layout_descr_file": ""
|
||||
},
|
||||
"schematic": {
|
||||
"annotate_start_num": 0,
|
||||
"bom_export_filename": "${PROJECTNAME}.csv",
|
||||
"bom_fmt_presets": [],
|
||||
"bom_fmt_settings": {
|
||||
"field_delimiter": ",",
|
||||
"keep_line_breaks": false,
|
||||
"keep_tabs": false,
|
||||
"name": "CSV",
|
||||
"ref_delimiter": ",",
|
||||
"ref_range_delimiter": "",
|
||||
"string_delimiter": "\""
|
||||
},
|
||||
"bom_presets": [],
|
||||
"bom_settings": {
|
||||
"exclude_dnp": false,
|
||||
"fields_ordered": [
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "Reference",
|
||||
"name": "Reference",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "Qty",
|
||||
"name": "${QUANTITY}",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"group_by": true,
|
||||
"label": "Value",
|
||||
"name": "Value",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"group_by": true,
|
||||
"label": "DNP",
|
||||
"name": "${DNP}",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"group_by": true,
|
||||
"label": "Exclude from BOM",
|
||||
"name": "${EXCLUDE_FROM_BOM}",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"group_by": true,
|
||||
"label": "Exclude from Board",
|
||||
"name": "${EXCLUDE_FROM_BOARD}",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"group_by": true,
|
||||
"label": "Footprint",
|
||||
"name": "Footprint",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "Datasheet",
|
||||
"name": "Datasheet",
|
||||
"show": true
|
||||
}
|
||||
],
|
||||
"filter_string": "",
|
||||
"group_symbols": true,
|
||||
"include_excluded_from_bom": true,
|
||||
"name": "Default Editing",
|
||||
"sort_asc": true,
|
||||
"sort_field": "Налаштування"
|
||||
},
|
||||
"connection_grid_size": 50.0,
|
||||
"drawing": {
|
||||
"dashed_lines_dash_length_ratio": 12.0,
|
||||
"dashed_lines_gap_length_ratio": 3.0,
|
||||
"default_line_thickness": 6.0,
|
||||
"default_text_size": 50.0,
|
||||
"field_names": [],
|
||||
"intersheets_ref_own_page": false,
|
||||
"intersheets_ref_prefix": "",
|
||||
"intersheets_ref_short": false,
|
||||
"intersheets_ref_show": false,
|
||||
"intersheets_ref_suffix": "",
|
||||
"junction_size_choice": 3,
|
||||
"label_size_ratio": 0.375,
|
||||
"operating_point_overlay_i_precision": 3,
|
||||
"operating_point_overlay_i_range": "~A",
|
||||
"operating_point_overlay_v_precision": 3,
|
||||
"operating_point_overlay_v_range": "~V",
|
||||
"overbar_offset_ratio": 1.23,
|
||||
"pin_symbol_size": 25.0,
|
||||
"text_offset_ratio": 0.15
|
||||
},
|
||||
"legacy_lib_dir": "",
|
||||
"legacy_lib_list": [],
|
||||
"meta": {
|
||||
"version": 1
|
||||
},
|
||||
"net_format_name": "",
|
||||
"page_layout_descr_file": "",
|
||||
"plot_directory": "",
|
||||
"space_save_all_events": true,
|
||||
"spice_current_sheet_as_root": false,
|
||||
"spice_external_command": "spice \"%I\"",
|
||||
"spice_model_current_sheet_as_root": true,
|
||||
"spice_save_all_currents": false,
|
||||
"spice_save_all_dissipations": false,
|
||||
"spice_save_all_voltages": false,
|
||||
"subpart_first_id": 65,
|
||||
"subpart_id_separator": 0
|
||||
},
|
||||
"sheets": [
|
||||
[
|
||||
"e717a214-aafd-4c38-81fe-477ca8e64d07",
|
||||
"Root"
|
||||
]
|
||||
],
|
||||
"text_variables": {}
|
||||
}
|
||||
6810
kicad/watch-watchkicad_pro/watch-watchkicad_pro.kicad_sch
Normal file
6810
kicad/watch-watchkicad_pro/watch-watchkicad_pro.kicad_sch
Normal file
File diff suppressed because it is too large
Load Diff
BIN
kicad/watch-watchkicad_pro/watch-watchkicad_pro.pdf
Normal file
BIN
kicad/watch-watchkicad_pro/watch-watchkicad_pro.pdf
Normal file
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
"dcdc_controller.c"
|
||||
"usb_cdc_cli.c"
|
||||
"usb_cdc_log.c"
|
||||
"ws2812_status.c"
|
||||
"ina226_monitor.c"
|
||||
"uart_mux.c"
|
||||
|
||||
@@ -1,5 +1,34 @@
|
||||
menu "Налаштування watch-watch"
|
||||
|
||||
menu "DC/DC контролер"
|
||||
|
||||
config WATCH_DCDC_EN_GPIO_0
|
||||
int "GPIO EN каналу 0"
|
||||
range 0 48
|
||||
default 2
|
||||
|
||||
config WATCH_DCDC_EN_GPIO_1
|
||||
int "GPIO EN каналу 1"
|
||||
range 0 48
|
||||
default 4
|
||||
|
||||
config WATCH_DCDC_EN_GPIO_2
|
||||
int "GPIO EN каналу 2"
|
||||
range 0 48
|
||||
default 5
|
||||
|
||||
config WATCH_DCDC_EN_GPIO_3
|
||||
int "GPIO EN каналу 3"
|
||||
range 0 48
|
||||
default 18
|
||||
|
||||
config WATCH_DCDC_EN_GPIO_4
|
||||
int "GPIO EN каналу 4"
|
||||
range 0 48
|
||||
default 19
|
||||
|
||||
endmenu
|
||||
|
||||
config WATCH_WS2812_LED_COUNT
|
||||
int "Кількість статусних світлодіодів WS2812"
|
||||
range 1 30
|
||||
@@ -2,15 +2,32 @@
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static const char *TAG = "dcdc";
|
||||
|
||||
#ifndef CONFIG_WATCH_DCDC_EN_GPIO_0
|
||||
#define CONFIG_WATCH_DCDC_EN_GPIO_0 2
|
||||
#endif
|
||||
#ifndef CONFIG_WATCH_DCDC_EN_GPIO_1
|
||||
#define CONFIG_WATCH_DCDC_EN_GPIO_1 4
|
||||
#endif
|
||||
#ifndef CONFIG_WATCH_DCDC_EN_GPIO_2
|
||||
#define CONFIG_WATCH_DCDC_EN_GPIO_2 5
|
||||
#endif
|
||||
#ifndef CONFIG_WATCH_DCDC_EN_GPIO_3
|
||||
#define CONFIG_WATCH_DCDC_EN_GPIO_3 18
|
||||
#endif
|
||||
#ifndef CONFIG_WATCH_DCDC_EN_GPIO_4
|
||||
#define CONFIG_WATCH_DCDC_EN_GPIO_4 19
|
||||
#endif
|
||||
|
||||
static const gpio_num_t s_dcdc_gpio_map[DCDC_CHANNEL_COUNT] = {
|
||||
GPIO_NUM_2,
|
||||
GPIO_NUM_4,
|
||||
GPIO_NUM_5,
|
||||
GPIO_NUM_18,
|
||||
GPIO_NUM_19,
|
||||
(gpio_num_t)CONFIG_WATCH_DCDC_EN_GPIO_0,
|
||||
(gpio_num_t)CONFIG_WATCH_DCDC_EN_GPIO_1,
|
||||
(gpio_num_t)CONFIG_WATCH_DCDC_EN_GPIO_2,
|
||||
(gpio_num_t)CONFIG_WATCH_DCDC_EN_GPIO_3,
|
||||
(gpio_num_t)CONFIG_WATCH_DCDC_EN_GPIO_4,
|
||||
};
|
||||
|
||||
static bool s_initialized;
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/*
|
||||
* Developed by TComLab
|
||||
* Version: v0.1
|
||||
* Date: 2025-12-15
|
||||
*/
|
||||
|
||||
#include "ina226_monitor.h"
|
||||
|
||||
#include <math.h>
|
||||
@@ -50,6 +56,8 @@ static uint8_t s_address = CONFIG_WATCH_INA226_ADDR;
|
||||
static ina226_reading_t s_last_reading;
|
||||
#endif
|
||||
|
||||
// Ініціалізує контролер INA226: налаштовує I2C, записує конфігурацію та
|
||||
// калібрувальні значення, а також зберігає початковий стан вимірювань.
|
||||
esp_err_t ina226_monitor_init(void)
|
||||
{
|
||||
#if !CONFIG_WATCH_INA226_ENABLED
|
||||
@@ -103,6 +111,7 @@ esp_err_t ina226_monitor_init(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Дозволяє швидко перевірити, чи був модуль INA226 успішно ініціалізований.
|
||||
bool ina226_monitor_ready(void)
|
||||
{
|
||||
#if CONFIG_WATCH_INA226_ENABLED
|
||||
@@ -112,12 +121,14 @@ bool ina226_monitor_ready(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
// INA226 вимірює єдиний канал живлення, тому повертаємо 1.
|
||||
size_t ina226_monitor_channel_count(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if CONFIG_WATCH_INA226_ENABLED
|
||||
// Зчитує 16-бітний регістр INA226, використовуючи транзакцію write-then-read.
|
||||
static esp_err_t ina226_read_register(uint8_t reg, uint16_t *out_value)
|
||||
{
|
||||
uint8_t value[2];
|
||||
@@ -132,6 +143,7 @@ static esp_err_t ina226_read_register(uint8_t reg, uint16_t *out_value)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Виконує одне вимірювання напруги/струму через INA226 та кешує результат.
|
||||
esp_err_t ina226_monitor_sample(ina226_reading_t *out_reading)
|
||||
{
|
||||
#if !CONFIG_WATCH_INA226_ENABLED
|
||||
@@ -162,6 +174,7 @@ esp_err_t ina226_monitor_sample(ina226_reading_t *out_reading)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Повертає останній виміряний набір даних без нового звернення до шини I2C.
|
||||
const ina226_reading_t *ina226_monitor_get_last(void)
|
||||
{
|
||||
#if CONFIG_WATCH_INA226_ENABLED
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/*
|
||||
* Developed by TComLab
|
||||
* Version: v0.1
|
||||
* Date: 2025-12-15
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
@@ -11,8 +17,13 @@ typedef struct {
|
||||
float power_mw;
|
||||
} ina226_reading_t;
|
||||
|
||||
// Ініціалізує INA226: конфігурує I2C та калібрує вимірювач.
|
||||
esp_err_t ina226_monitor_init(void);
|
||||
// true, якщо драйвер вже ініціалізований.
|
||||
bool ina226_monitor_ready(void);
|
||||
// INA226 підтримує один канал, але інтерфейс залишається узагальненим.
|
||||
size_t ina226_monitor_channel_count(void);
|
||||
// Зчитує нові дані; out_reading може бути NULL, якщо дані не потрібні.
|
||||
esp_err_t ina226_monitor_sample(ina226_reading_t *out_reading);
|
||||
// Повертає кеш останнього вимірювання або NULL, якщо модуль неактивний.
|
||||
const ina226_reading_t *ina226_monitor_get_last(void);
|
||||
|
||||
26
main/main.c
26
main/main.c
@@ -1,3 +1,9 @@
|
||||
/*
|
||||
* Developed by TComLab
|
||||
* Version: v0.1
|
||||
* Date: 2025-12-15
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
@@ -7,13 +13,21 @@
|
||||
#include "dcdc_controller.h"
|
||||
#include "ina226_monitor.h"
|
||||
#include "uart_mux.h"
|
||||
#include "usb_cdc_cli.h"
|
||||
#include "usb_cdc_log.h"
|
||||
#include "ws2812_status.h"
|
||||
|
||||
static const char *TAG = "watch-watch";
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
if (usb_cdc_log_init() != ESP_OK) {
|
||||
ESP_LOGW(TAG, "USB CDC лог недоступний");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "USB CDC лог активовано");
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(2000)); // Затримка для стабілізації живлення після перезавантаження
|
||||
ESP_LOGI(TAG, "Запуск watch-watch systems");
|
||||
if (dcdc_init() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Помилка ініціалізації DCDC контролера");
|
||||
ws2812_status_init();
|
||||
@@ -23,6 +37,10 @@ void app_main(void)
|
||||
|
||||
if (ws2812_status_init() == ESP_OK) {
|
||||
ws2812_status_refresh_from_dcdc();
|
||||
esp_err_t anim_err = ws2812_status_play_bringup_animation(2, 120);
|
||||
if (anim_err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Анімація WS2812 недоступна: %s", esp_err_to_name(anim_err));
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "WS2812 статусний індикатор недоступний");
|
||||
}
|
||||
@@ -40,11 +58,7 @@ void app_main(void)
|
||||
ESP_LOGW(TAG, "UART мультиплексор недоступний");
|
||||
}
|
||||
|
||||
if (usb_cdc_cli_init() != ESP_OK) {
|
||||
ESP_LOGW(TAG, "USB CDC CLI недоступний");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "USB CDC CLI запущено");
|
||||
}
|
||||
|
||||
|
||||
ESP_LOGI(TAG, "Початок послідовного ввімкнення каналів з інтервалом 4 с");
|
||||
const TickType_t on_time = pdMS_TO_TICKS(4000);
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/*
|
||||
* Developed by TComLab
|
||||
* Version: v0.1
|
||||
* Date: 2025-12-15
|
||||
*/
|
||||
|
||||
#include "uart_mux.h"
|
||||
|
||||
#include <string.h>
|
||||
@@ -38,6 +44,8 @@ static bool s_initialized;
|
||||
static int64_t s_last_heartbeat_us[UART_MUX_MAX_CHANNELS];
|
||||
static TaskHandle_t s_watchdog_task;
|
||||
|
||||
// Перемикає апаратний мультиплексор на вказаний канал під захистом мьютекса,
|
||||
// оновлюючи таймстемп останнього heartbeat для контролю watchdog.
|
||||
static esp_err_t uart_mux_select_locked(size_t channel)
|
||||
{
|
||||
if (channel >= UART_MUX_MAX_CHANNELS) {
|
||||
@@ -56,6 +64,8 @@ static esp_err_t uart_mux_select_locked(size_t channel)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// Періодично опитує всі канали, щоб зчитати heartbeat та перезапускає DCDC,
|
||||
// якщо канал «мовчить» довше за CONFIG_WATCH_UART_HEARTBEAT_TIMEOUT_SEC.
|
||||
static void uart_mux_watchdog_task(void *arg)
|
||||
{
|
||||
const TickType_t poll_interval = pdMS_TO_TICKS(1000);
|
||||
@@ -94,6 +104,8 @@ static void uart_mux_watchdog_task(void *arg)
|
||||
|
||||
#endif // CONFIG_WATCH_UART_MUX_ENABLED
|
||||
|
||||
// Налаштовує GPIO-вибірники, драйвер UART та створює watchdog-задачу для
|
||||
// мультиплексора; повторний виклик просто повертає ESP_OK.
|
||||
esp_err_t uart_mux_init(void)
|
||||
{
|
||||
#if !CONFIG_WATCH_UART_MUX_ENABLED
|
||||
@@ -156,6 +168,7 @@ esp_err_t uart_mux_init(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Повертає ознаку ініціалізації модулю UART мультиплексора.
|
||||
bool uart_mux_ready(void)
|
||||
{
|
||||
#if CONFIG_WATCH_UART_MUX_ENABLED
|
||||
@@ -165,11 +178,14 @@ bool uart_mux_ready(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Кількість доступних каналів, визначених у конфігурації.
|
||||
size_t uart_mux_channel_count(void)
|
||||
{
|
||||
return CONFIG_WATCH_UART_MUX_CHANNELS;
|
||||
}
|
||||
|
||||
// Перемикається на канал, передає буфер даних через загальний UART та
|
||||
// захищає доступ до шини мьютексом, щоб уникнути гонок між задачами.
|
||||
esp_err_t uart_mux_write(size_t channel, const uint8_t *data, size_t length, TickType_t timeout)
|
||||
{
|
||||
#if !CONFIG_WATCH_UART_MUX_ENABLED
|
||||
@@ -199,6 +215,8 @@ esp_err_t uart_mux_write(size_t channel, const uint8_t *data, size_t length, Tic
|
||||
#endif
|
||||
}
|
||||
|
||||
// Читає дані з вказаного каналу, оновлюючи heartbeat під час успішного
|
||||
// зчитування, і повертає кількість байтів через out_length.
|
||||
esp_err_t uart_mux_read(size_t channel, uint8_t *buffer, size_t buffer_size, size_t *out_length, TickType_t timeout)
|
||||
{
|
||||
#if !CONFIG_WATCH_UART_MUX_ENABLED
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
/*
|
||||
* Developed by TComLab
|
||||
* Version: v0.1
|
||||
* Date: 2025-12-15
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
@@ -5,8 +11,13 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
// Ініціалізує апаратний мультиплексор UART: GPIO, UART драйвер та watchdog.
|
||||
esp_err_t uart_mux_init(void);
|
||||
// Повертає true, якщо драйвер готовий приймати виклики.
|
||||
bool uart_mux_ready(void);
|
||||
// Кількість доступних каналів мультиплексора.
|
||||
size_t uart_mux_channel_count(void);
|
||||
// Відправляє буфер даних на вказаний канал з тайм-аутом очікування мьютекса.
|
||||
esp_err_t uart_mux_write(size_t channel, const uint8_t *data, size_t length, TickType_t timeout);
|
||||
// Зчитує дані з каналу, повертаючи кількість байтів через out_length.
|
||||
esp_err_t uart_mux_read(size_t channel, uint8_t *buffer, size_t buffer_size, size_t *out_length, TickType_t timeout);
|
||||
|
||||
98
main/usb_cdc_log.c
Normal file
98
main/usb_cdc_log.c
Normal file
@@ -0,0 +1,98 @@
|
||||
#include "usb_cdc_log.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "tinyusb.h"
|
||||
#include "tusb_cdc_acm.h"
|
||||
|
||||
static const char *TAG = "usb_log";
|
||||
|
||||
static bool s_initialized;
|
||||
static bool s_host_ready;
|
||||
static vprintf_like_t s_prev_vprintf;
|
||||
|
||||
static int usb_cdc_vprintf(const char *fmt, va_list args)
|
||||
{
|
||||
if (s_host_ready) {
|
||||
char buffer[256];
|
||||
va_list args_copy;
|
||||
va_copy(args_copy, args);
|
||||
int len = vsnprintf(buffer, sizeof(buffer), fmt, args_copy);
|
||||
va_end(args_copy);
|
||||
if (len > 0) {
|
||||
if (len >= (int)sizeof(buffer)) {
|
||||
len = sizeof(buffer) - 1;
|
||||
}
|
||||
if (tinyusb_cdcacm_write_queue(TINYUSB_CDC_ACM_0, (const uint8_t *)buffer, len) == ESP_OK) {
|
||||
tinyusb_cdcacm_write_flush(TINYUSB_CDC_ACM_0, 0);
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
if (s_prev_vprintf) {
|
||||
va_list args_copy;
|
||||
va_copy(args_copy, args);
|
||||
int ret = s_prev_vprintf(fmt, args_copy);
|
||||
va_end(args_copy);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb_cdc_line_state_changed_callback(int itf, cdcacm_event_t *event)
|
||||
{
|
||||
(void)itf;
|
||||
s_host_ready = event->line_state_changed_data.dtr;
|
||||
if (s_host_ready) {
|
||||
const char banner[] = "\r\nwatch-watch log over USB CDC\r\n";
|
||||
tinyusb_cdcacm_write_queue(TINYUSB_CDC_ACM_0, (const uint8_t *)banner, sizeof(banner) - 1);
|
||||
tinyusb_cdcacm_write_flush(TINYUSB_CDC_ACM_0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool usb_cdc_log_ready(void)
|
||||
{
|
||||
return s_host_ready;
|
||||
}
|
||||
|
||||
esp_err_t usb_cdc_log_init(void)
|
||||
{
|
||||
if (s_initialized) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
const tinyusb_config_t tusb_cfg = {
|
||||
.device_descriptor = NULL,
|
||||
.string_descriptor = NULL,
|
||||
.external_phy = false,
|
||||
#if (TUD_OPT_HIGH_SPEED)
|
||||
.fs_configuration_descriptor = NULL,
|
||||
.hs_configuration_descriptor = NULL,
|
||||
.qualifier_descriptor = NULL,
|
||||
#else
|
||||
.configuration_descriptor = NULL,
|
||||
#endif
|
||||
};
|
||||
|
||||
ESP_RETURN_ON_ERROR(tinyusb_driver_install(&tusb_cfg), TAG, "TinyUSB init failed");
|
||||
|
||||
const tinyusb_config_cdcacm_t acm_cfg = {
|
||||
.usb_dev = TINYUSB_USBDEV_0,
|
||||
.cdc_port = TINYUSB_CDC_ACM_0,
|
||||
.rx_unread_buf_sz = 64,
|
||||
.callback_rx = NULL,
|
||||
.callback_rx_wanted_char = NULL,
|
||||
.callback_line_state_changed = usb_cdc_line_state_changed_callback,
|
||||
.callback_line_coding_changed = NULL,
|
||||
};
|
||||
ESP_RETURN_ON_ERROR(tusb_cdc_acm_init(&acm_cfg), TAG, "CDC init failed");
|
||||
|
||||
s_prev_vprintf = esp_log_set_vprintf(usb_cdc_vprintf);
|
||||
s_initialized = true;
|
||||
ESP_LOGI(TAG, "ESP_LOG перенаправлено в USB CDC");
|
||||
return ESP_OK;
|
||||
}
|
||||
15
main/usb_cdc_log.h
Normal file
15
main/usb_cdc_log.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Ініціалізує TinyUSB CDC та перенаправляє ESP_LOG у USB.
|
||||
*/
|
||||
esp_err_t usb_cdc_log_init(void);
|
||||
|
||||
/**
|
||||
* @brief Чи встановив хост DTR і готовий приймати лог.
|
||||
*/
|
||||
bool usb_cdc_log_ready(void);
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "led_strip.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifndef CONFIG_WATCH_WS2812_LED_COUNT
|
||||
@@ -132,3 +134,62 @@ esp_err_t ws2812_status_refresh_from_dcdc(void)
|
||||
}
|
||||
return ws2812_status_apply();
|
||||
}
|
||||
|
||||
esp_err_t ws2812_status_play_bringup_animation(size_t cycles, uint32_t step_delay_ms)
|
||||
{
|
||||
if (!s_strip) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (cycles == 0) {
|
||||
cycles = 1;
|
||||
}
|
||||
if (step_delay_ms == 0) {
|
||||
step_delay_ms = 150;
|
||||
}
|
||||
|
||||
bool saved_led_state[WS2812_STATUS_LED_COUNT];
|
||||
for (size_t i = 0; i < WS2812_STATUS_LED_COUNT; ++i) {
|
||||
saved_led_state[i] = s_led_state[i];
|
||||
}
|
||||
const bool saved_error = s_error_state;
|
||||
const size_t saved_active = s_active_channel;
|
||||
|
||||
s_error_state = false;
|
||||
s_active_channel = SIZE_MAX;
|
||||
|
||||
const TickType_t delay_ticks = pdMS_TO_TICKS(step_delay_ms);
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
for (size_t cycle = 0; cycle < cycles && err == ESP_OK; ++cycle) {
|
||||
for (size_t led = 0; led < WS2812_STATUS_LED_COUNT; ++led) {
|
||||
for (size_t idx = 0; idx < WS2812_STATUS_LED_COUNT; ++idx) {
|
||||
const uint8_t g = (idx == led) ? 35 : 0;
|
||||
err = led_strip_set_pixel(s_strip, idx, 0, g, 0);
|
||||
if (err != ESP_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
break;
|
||||
}
|
||||
err = led_strip_refresh(s_strip);
|
||||
if (err != ESP_OK) {
|
||||
break;
|
||||
}
|
||||
vTaskDelay(delay_ticks);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < WS2812_STATUS_LED_COUNT; ++i) {
|
||||
s_led_state[i] = saved_led_state[i];
|
||||
}
|
||||
s_error_state = saved_error;
|
||||
s_active_channel = saved_active;
|
||||
|
||||
esp_err_t restore_err = ws2812_status_apply();
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
return restore_err;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "sdkconfig.h"
|
||||
@@ -18,3 +19,4 @@ esp_err_t ws2812_status_mark_active(size_t channel);
|
||||
esp_err_t ws2812_status_clear_active(void);
|
||||
esp_err_t ws2812_status_set_error(bool has_error);
|
||||
esp_err_t ws2812_status_refresh_from_dcdc(void);
|
||||
esp_err_t ws2812_status_play_bringup_animation(size_t cycles, uint32_t step_delay_ms);
|
||||
|
||||
Reference in New Issue
Block a user