新增引用关系图工具 tools/refgraph:解析 #include 生成文件级/模块级引用图,项目变化后重跑更新

This commit is contained in:
2026-09-16 01:45:44 +08:00
parent 1817fe792f
commit ad0ec41385
9 changed files with 46547 additions and 1 deletions
+2 -1
View File
@@ -95,5 +95,6 @@ STM32F407ZGTx @168MHz(HSE 8MHz → PLL M=4/N=168/P=2);**仅 Keil MDK-ARM v
## 文档与图形
- 配置文件 `docs/配置文件设计说明.md`;墙钟 `docs/系统墙钟时间维护说明.md`;代码规范 `docs/代码规范/`;测试说明 `docs/测试说明/`;审计发现 `docs/项目审计改进清单.md`;已知待办 `待处理内容.md`(内存预算)
- 配置文件 `docs/配置文件设计说明.md`;墙钟 `docs/系统墙钟时间维护说明.md`;代码规范 `docs/代码规范/`;测试说明 `docs/测试说明/`;审计发现 `docs/项目审计改进清单.md`;已知待办 `待处理内容.md`(内存预算);引用关系图 `docs/引用关系图说明.md`
- 图形走 **`draw-diagram` skill**:精确布局图(协议帧/分层/屏障)用 `tools/arch_diagram/gen_*.py` 生成器(产物放 `docs/images/`,脚本与 .svg 一并提交);拓扑图(流程/时序/状态机)用 Mermaid;**勿手绘 ASCII 框图**
- **文件引用关系图**走 `tools/refgraph`:`& 'tools\refgraph\gen_refgraph.bat'` 生成文件级 + 模块级引用图(产物 `docs/images/引用关系图.*`,脚本与 .dot/.svg/.json 一并提交,PNG 本地预览不提交);项目文件变化后重跑更新;渲染依赖 Graphviz(winget 可装)
+539
View File
@@ -0,0 +1,539 @@
digraph refgraph_full {
graph [rankdir=LR, bgcolor="white", labelloc=t, label="STM32F4-Base 项目文件引用关系图(项目代码视图)", fontname="Microsoft YaHei", fontsize=18];
node [fontname="Microsoft YaHei", fontsize=10, shape=box, style="rounded,filled"];
edge [fontname="Microsoft YaHei", fontsize=8];
"App/app_cfg.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/app_main.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/app_main.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/cfg_file.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/cfg_file.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/cfg_file_store.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/cfg_file_store_mcu.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/log/sys_log.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/log/sys_log_mcu.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/sys_events.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/task/adc_task.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/task/adc_task.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/task/net_task.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/task/net_task.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/task/rs485_task.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/task/rs485_task.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/task/ui_task.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/task/ui_task.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/time_sync.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/time_sync.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/util/crc.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/util/crc.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/util/ringbuf.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/util/ringbuf.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/util/sys_clock.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/util/sys_clock.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/CH395F/ch395f.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/CH395F/ch395f.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/GD5F2GQ5UE/nand_ftl.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/GD5F2GQ5UE/nand_ftl.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/NET/lftpd/lftpd.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Drivers/BSP/NET/net_config.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/NET/net_select.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/NET/net_select.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/NET/net_socket.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/NET/net_socket.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/NET/net_types.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/NETCFG/net_cfg.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/NETCFG/net_cfg.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/NETCFG/net_cfg_legacy.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/NETCFG/net_cfg_legacy.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/RS485/rs485.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/RS485/rs485.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/SD2506/sd2506.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/SD2506/sd2506.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/TPAFE5160/tpafe5160.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/TPAFE5160/tpafe5160.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_content_page.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_content_page.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_deco.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_deco.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_font_cn_12.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_menu.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_menu.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_menu_tab.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_menu_tab.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_menu_view.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_menu_view.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_net_sink.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_net_sink.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_net_sink_backend.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_net_sink_backend_mcu.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_page_ac.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_page_ac.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_page_dc.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_page_dc.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_page_device_info.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_page_device_info.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_page_net_cfg.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_page_net_cfg.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_page_password.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_page_password.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_page_runlog.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_page_runlog.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_page_selftest.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_page_selftest.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_port.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_port.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_pwd_def.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_standby.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/UI/ui_standby.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/dbg_cfg.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/BSP/dbg_log.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_cortex.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_exti.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_gpio.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_pwr.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rcc.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_spi.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Inc/FreeRTOSConfig.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Inc/dma.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Inc/gpio.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Inc/i2c.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Inc/main.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Inc/spi.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Inc/stm32f4xx_hal_conf.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Inc/stm32f4xx_it.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Inc/usart.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"Lib/FatFs/diskio.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Lib/FatFs/ff.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Lib/dhara/map.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Lib/dhara/nand.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Lib/lvgl/lvgl.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Middlewares/Third_Party/FreeRTOS/Source/include/task.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"Src/dma.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Src/freertos.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Src/gpio.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Src/i2c.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Src/main.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Src/spi.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Src/stm32f4xx_hal_msp.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Src/stm32f4xx_hal_timebase_tim.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Src/stm32f4xx_it.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Src/system_stm32f4xx.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"Src/usart.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"simulator/SDL2/SDL2-2.32.10/include/SDL.h" [fillcolor="#f3f4f6", color="#9ca3af"];
"simulator/dbg_log.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"simulator/lv_conf.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"simulator/main.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"simulator/sim/cfg_file_store_sim.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"simulator/sim/net_socket_sim.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"simulator/sim/sim_port.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"simulator/sim/sim_port.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"simulator/sim/sim_syslog.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"simulator/sim/ui_net_sink_backend_sim.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/ch395f_test.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/ch395f_test_task.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/ch395f_test_task.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/gd5f_test.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/gd5f_test_task.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/net_test_task.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/net_test_task.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/sd2506_test.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/sd2506_test_task.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/storage_test.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/storage_test_task.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/test_config.c" [fillcolor="#dbeafe", color="#1d4ed8"];
"test/test_config.h" [fillcolor="#dbeafe", color="#1d4ed8"];
"外部/系统头文件" [shape=ellipse, fillcolor="#fef3c7", color="#d97706", fontsize=12];
"App/app_main.c" -> "App/app_cfg.h" [color="#2563eb", penwidth=1.0];
"App/app_main.c" -> "App/app_main.h" [color="#2563eb", penwidth=1.0];
"App/app_main.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
"App/app_main.c" -> "App/util/sys_clock.h" [color="#2563eb", penwidth=1.0];
"App/app_main.c" -> "Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h" [color="#2563eb", penwidth=1.0];
"App/app_main.c" -> "Drivers/BSP/RS485/rs485.h" [color="#2563eb", penwidth=1.0];
"App/app_main.c" -> "Drivers/BSP/SD2506/sd2506.h" [color="#2563eb", penwidth=1.0];
"App/app_main.c" -> "Drivers/BSP/TPAFE5160/tpafe5160.h" [color="#2563eb", penwidth=1.0];
"App/app_main.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"App/app_main.c" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"App/app_main.c" -> "Inc/usart.h" [color="#2563eb", penwidth=1.0];
"App/app_main.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/cfg_file.c" -> "App/cfg_file.h" [color="#2563eb", penwidth=1.0];
"App/cfg_file.c" -> "App/cfg_file_store.h" [color="#2563eb", penwidth=1.0];
"App/cfg_file.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"App/cfg_file.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/cfg_file.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/cfg_file_store.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/cfg_file_store_mcu.c" -> "App/cfg_file_store.h" [color="#2563eb", penwidth=1.0];
"App/cfg_file_store_mcu.c" -> "Lib/FatFs/ff.h" [color="#94a3b8", penwidth=0.7];
"App/cfg_file_store_mcu.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/log/sys_log.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/log/sys_log_mcu.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
"App/log/sys_log_mcu.c" -> "App/util/sys_clock.h" [color="#2563eb", penwidth=1.0];
"App/log/sys_log_mcu.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"App/log/sys_log_mcu.c" -> "Lib/FatFs/ff.h" [color="#94a3b8", penwidth=0.7];
"App/log/sys_log_mcu.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"App/log/sys_log_mcu.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/sys_events.h" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.h" [color="#94a3b8", penwidth=0.7];
"App/task/adc_task.c" -> "App/task/adc_task.h" [color="#2563eb", penwidth=1.0];
"App/task/adc_task.c" -> "Drivers/BSP/TPAFE5160/tpafe5160.h" [color="#2563eb", penwidth=1.0];
"App/task/adc_task.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"App/task/adc_task.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"App/task/net_task.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
"App/task/net_task.c" -> "App/sys_events.h" [color="#2563eb", penwidth=1.0];
"App/task/net_task.c" -> "App/task/net_task.h" [color="#2563eb", penwidth=1.0];
"App/task/net_task.c" -> "Drivers/BSP/CH395F/ch395f.h" [color="#2563eb", penwidth=1.0];
"App/task/net_task.c" -> "Drivers/BSP/NET/net_select.h" [color="#2563eb", penwidth=1.0];
"App/task/net_task.c" -> "Drivers/BSP/NET/net_socket.h" [color="#2563eb", penwidth=1.0];
"App/task/net_task.c" -> "Drivers/BSP/NETCFG/net_cfg.h" [color="#2563eb", penwidth=1.0];
"App/task/net_task.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"App/task/net_task.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"App/task/net_task.c" -> "test/test_config.h" [color="#2563eb", penwidth=1.0];
"App/task/net_task.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/task/rs485_task.c" -> "App/task/rs485_task.h" [color="#2563eb", penwidth=1.0];
"App/task/rs485_task.c" -> "Drivers/BSP/RS485/rs485.h" [color="#2563eb", penwidth=1.0];
"App/task/rs485_task.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"App/task/rs485_task.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"App/task/ui_task.c" -> "App/sys_events.h" [color="#2563eb", penwidth=1.0];
"App/task/ui_task.c" -> "App/task/ui_task.h" [color="#2563eb", penwidth=1.0];
"App/task/ui_task.c" -> "App/util/sys_clock.h" [color="#2563eb", penwidth=1.0];
"App/task/ui_task.c" -> "Drivers/BSP/UI/ui_menu.h" [color="#2563eb", penwidth=1.0];
"App/task/ui_task.c" -> "Drivers/BSP/UI/ui_net_sink.h" [color="#2563eb", penwidth=1.0];
"App/task/ui_task.c" -> "Drivers/BSP/UI/ui_port.h" [color="#2563eb", penwidth=1.0];
"App/task/ui_task.c" -> "Drivers/BSP/UI/ui_standby.h" [color="#2563eb", penwidth=1.0];
"App/task/ui_task.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"App/task/ui_task.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"App/task/ui_task.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/time_sync.c" -> "App/sys_events.h" [color="#2563eb", penwidth=1.0];
"App/time_sync.c" -> "App/time_sync.h" [color="#2563eb", penwidth=1.0];
"App/time_sync.c" -> "App/util/sys_clock.h" [color="#2563eb", penwidth=1.0];
"App/time_sync.c" -> "Drivers/BSP/NET/net_socket.h" [color="#2563eb", penwidth=1.0];
"App/time_sync.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"App/time_sync.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/time_sync.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/util/crc.c" -> "App/util/crc.h" [color="#2563eb", penwidth=1.0];
"App/util/crc.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/util/ringbuf.c" -> "App/util/ringbuf.h" [color="#2563eb", penwidth=1.0];
"App/util/ringbuf.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/util/sys_clock.c" -> "App/util/sys_clock.h" [color="#2563eb", penwidth=1.0];
"App/util/sys_clock.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"App/util/sys_clock.c" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"App/util/sys_clock.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h" [color="#94a3b8", penwidth=0.7];
"App/util/sys_clock.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/task.h" [color="#94a3b8", penwidth=0.7];
"App/util/sys_clock.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"App/util/sys_clock.h" -> "Drivers/BSP/SD2506/sd2506.h" [color="#2563eb", penwidth=1.0];
"App/util/sys_clock.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/CH395F/ch395f.c" -> "Drivers/BSP/CH395F/ch395f.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/CH395F/ch395f.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/CH395F/ch395f.c" -> "Inc/spi.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/CH395F/ch395f.c" -> "Inc/usart.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/CH395F/ch395f.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/CH395F/ch395f.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c" -> "Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/GD5F2GQ5UE/nand_ftl.c" -> "Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/GD5F2GQ5UE/nand_ftl.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/GD5F2GQ5UE/nand_ftl.c" -> "Lib/FatFs/diskio.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/GD5F2GQ5UE/nand_ftl.c" -> "Lib/FatFs/ff.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/GD5F2GQ5UE/nand_ftl.c" -> "Lib/dhara/map.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/GD5F2GQ5UE/nand_ftl.c" -> "Lib/dhara/nand.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/GD5F2GQ5UE/nand_ftl.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/GD5F2GQ5UE/nand_ftl.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/NET/net_select.c" -> "Drivers/BSP/CH395F/ch395f.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NET/net_select.c" -> "Drivers/BSP/NET/net_select.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NET/net_select.c" -> "Drivers/BSP/NET/net_socket.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NET/net_select.c" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NET/net_select.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/NET/net_select.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/NET/net_select.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/task.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/NET/net_select.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/NET/net_select.h" -> "Drivers/BSP/NET/net_config.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NET/net_select.h" -> "Drivers/BSP/NET/net_types.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NET/net_socket.c" -> "Drivers/BSP/CH395F/ch395f.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NET/net_socket.c" -> "Drivers/BSP/NET/net_socket.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NET/net_socket.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NET/net_socket.c" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NET/net_socket.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/NET/net_socket.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/NET/net_socket.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/task.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/NET/net_socket.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/NET/net_socket.h" -> "Drivers/BSP/NET/net_types.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NET/net_socket.h" -> "Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/NET/net_socket.h" -> "Middlewares/Third_Party/FreeRTOS/Source/include/task.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/NET/net_types.h" -> "Drivers/BSP/NET/net_config.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NET/net_types.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/NETCFG/net_cfg.c" -> "App/cfg_file.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NETCFG/net_cfg.c" -> "Drivers/BSP/NETCFG/net_cfg.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NETCFG/net_cfg.c" -> "Drivers/BSP/NETCFG/net_cfg_legacy.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NETCFG/net_cfg.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NETCFG/net_cfg.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/NETCFG/net_cfg.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/NETCFG/net_cfg_legacy.c" -> "App/cfg_file.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NETCFG/net_cfg_legacy.c" -> "App/cfg_file_store.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NETCFG/net_cfg_legacy.c" -> "Drivers/BSP/NETCFG/net_cfg.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NETCFG/net_cfg_legacy.c" -> "Drivers/BSP/NETCFG/net_cfg_legacy.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NETCFG/net_cfg_legacy.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/NETCFG/net_cfg_legacy.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/RS485/rs485.c" -> "Drivers/BSP/RS485/rs485.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/RS485/rs485.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/SD2506/sd2506.c" -> "Drivers/BSP/SD2506/sd2506.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/SD2506/sd2506.c" -> "Inc/i2c.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/SD2506/sd2506.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/SD2506/sd2506.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/TPAFE5160/tpafe5160.c" -> "Drivers/BSP/TPAFE5160/tpafe5160.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/TPAFE5160/tpafe5160.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/TPAFE5160/tpafe5160.c" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/TPAFE5160/tpafe5160.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/UI/ui_content_page.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/UI/ui_deco.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/UI/ui_menu_view.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/UI/ui_page_ac.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/UI/ui_page_dc.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/UI/ui_page_device_info.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/UI/ui_page_net_cfg.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/UI/ui_page_password.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/UI/ui_page_runlog.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/UI/ui_page_selftest.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/UI/ui_pwd_def.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/UI/ui_standby.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_content_page.c" -> "Lib/lvgl/lvgl.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/UI/ui_content_page.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_content_page.h" -> "Lib/lvgl/lvgl.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/UI/ui_content_page.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_deco.c" -> "Drivers/BSP/UI/ui_deco.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_deco.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_deco.h" -> "Lib/lvgl/lvgl.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/UI/ui_font_cn_12.c" -> "Lib/lvgl/lvgl.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/UI/ui_menu.c" -> "Drivers/BSP/UI/ui_content_page.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_menu.c" -> "Drivers/BSP/UI/ui_menu.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_menu.c" -> "Drivers/BSP/UI/ui_menu_tab.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_menu.c" -> "Drivers/BSP/UI/ui_menu_view.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_menu.c" -> "Drivers/BSP/UI/ui_page_password.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_menu.c" -> "Drivers/BSP/UI/ui_pwd_def.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_menu.c" -> "Drivers/BSP/UI/ui_standby.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_menu.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_menu.c" -> "Lib/lvgl/lvgl.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/UI/ui_menu.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_menu_tab.c" -> "Drivers/BSP/UI/ui_menu_tab.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_menu_tab.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_menu_view.c" -> "Drivers/BSP/UI/ui_deco.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_menu_view.c" -> "Drivers/BSP/UI/ui_menu_tab.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_menu_view.c" -> "Drivers/BSP/UI/ui_menu_view.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_menu_view.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_menu_view.c" -> "Lib/lvgl/lvgl.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/UI/ui_menu_view.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_menu_view.h" -> "Lib/lvgl/lvgl.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/UI/ui_menu_view.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_net_sink.c" -> "Drivers/BSP/NET/net_socket.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_net_sink.c" -> "Drivers/BSP/NET/net_types.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_net_sink.c" -> "Drivers/BSP/UI/ui_net_sink.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_net_sink.c" -> "Drivers/BSP/UI/ui_net_sink_backend.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_net_sink.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_net_sink.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_net_sink_backend.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_net_sink_backend_mcu.c" -> "Drivers/BSP/UI/ui_net_sink_backend.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_net_sink_backend_mcu.c" -> "Drivers/BSP/UI/ui_port.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_net_sink_backend_mcu.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_page_ac.c" -> "Drivers/BSP/UI/ui_page_ac.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_ac.h" -> "Drivers/BSP/UI/ui_content_page.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_dc.c" -> "Drivers/BSP/UI/ui_page_dc.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_dc.h" -> "Drivers/BSP/UI/ui_content_page.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_device_info.c" -> "Drivers/BSP/UI/ui_page_device_info.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_device_info.h" -> "Drivers/BSP/UI/ui_content_page.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_net_cfg.c" -> "Drivers/BSP/NETCFG/net_cfg.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_net_cfg.c" -> "Drivers/BSP/UI/ui_page_net_cfg.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_net_cfg.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_page_net_cfg.h" -> "Drivers/BSP/UI/ui_content_page.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_password.c" -> "Drivers/BSP/UI/ui_page_password.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_password.c" -> "Drivers/BSP/UI/ui_pwd_def.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_password.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_page_password.h" -> "Drivers/BSP/UI/ui_content_page.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_runlog.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_runlog.c" -> "Drivers/BSP/UI/ui_page_runlog.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_runlog.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_page_runlog.h" -> "Drivers/BSP/UI/ui_content_page.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_selftest.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_selftest.c" -> "Drivers/BSP/UI/ui_page_selftest.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_page_selftest.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_page_selftest.h" -> "Drivers/BSP/UI/ui_content_page.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_port.c" -> "Drivers/BSP/UI/ui_port.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_port.c" -> "Lib/lvgl/lvgl.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/UI/ui_port.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_port.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_pwd_def.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_standby.c" -> "Drivers/BSP/UI/ui_menu_view.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_standby.c" -> "Drivers/BSP/UI/ui_standby.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_standby.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/UI/ui_standby.c" -> "Lib/lvgl/lvgl.h" [color="#94a3b8", penwidth=0.7];
"Drivers/BSP/UI/ui_standby.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/UI/ui_standby.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Drivers/BSP/dbg_log.h" -> "App/util/sys_clock.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/dbg_log.h" -> "Drivers/BSP/dbg_cfg.h" [color="#2563eb", penwidth=1.0];
"Drivers/BSP/dbg_log.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Inc/FreeRTOSConfig.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Inc/dma.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Inc/gpio.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Inc/i2c.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Inc/main.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h" [color="#94a3b8", penwidth=0.7];
"Inc/spi.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_cortex.h" [color="#94a3b8", penwidth=0.7];
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma.h" [color="#94a3b8", penwidth=0.7];
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_exti.h" [color="#94a3b8", penwidth=0.7];
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_flash.h" [color="#94a3b8", penwidth=0.7];
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_gpio.h" [color="#94a3b8", penwidth=0.7];
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_i2c.h" [color="#94a3b8", penwidth=0.7];
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_pwr.h" [color="#94a3b8", penwidth=0.7];
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_rcc.h" [color="#94a3b8", penwidth=0.7];
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_spi.h" [color="#94a3b8", penwidth=0.7];
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim.h" [color="#94a3b8", penwidth=0.7];
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h" [color="#94a3b8", penwidth=0.7];
"Inc/stm32f4xx_hal_conf.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Inc/usart.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Src/dma.c" -> "Inc/dma.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "App/cfg_file.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "App/sys_events.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "App/task/net_task.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "App/time_sync.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "Drivers/BSP/CH395F/ch395f.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "Drivers/BSP/NET/lftpd/lftpd.h" [color="#94a3b8", penwidth=0.7];
"Src/freertos.c" -> "Drivers/BSP/NET/net_socket.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "Drivers/BSP/NETCFG/net_cfg.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "Inc/usart.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "Lib/FatFs/ff.h" [color="#94a3b8", penwidth=0.7];
"Src/freertos.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"Src/freertos.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h" [color="#94a3b8", penwidth=0.7];
"Src/freertos.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/task.h" [color="#94a3b8", penwidth=0.7];
"Src/freertos.c" -> "test/ch395f_test.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "test/ch395f_test_task.h" [color="#2563eb", penwidth=1.0];
"Src/freertos.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Src/gpio.c" -> "Inc/gpio.h" [color="#2563eb", penwidth=1.0];
"Src/i2c.c" -> "Inc/i2c.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "App/app_main.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "App/util/sys_clock.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Drivers/BSP/CH395F/ch395f.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Drivers/BSP/NET/net_select.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Drivers/BSP/NET/net_socket.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Drivers/BSP/RS485/rs485.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Drivers/BSP/SD2506/sd2506.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Drivers/BSP/TPAFE5160/tpafe5160.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Inc/dma.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Inc/gpio.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Inc/i2c.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Inc/spi.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Inc/usart.h" [color="#2563eb", penwidth=1.0];
"Src/main.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"Src/main.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"Src/spi.c" -> "Inc/spi.h" [color="#2563eb", penwidth=1.0];
"Src/stm32f4xx_hal_msp.c" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Src/stm32f4xx_hal_timebase_tim.c" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h" [color="#94a3b8", penwidth=0.7];
"Src/stm32f4xx_hal_timebase_tim.c" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim.h" [color="#94a3b8", penwidth=0.7];
"Src/stm32f4xx_it.c" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"Src/stm32f4xx_it.c" -> "Inc/stm32f4xx_it.h" [color="#2563eb", penwidth=1.0];
"Src/system_stm32f4xx.c" -> "Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h" [color="#94a3b8", penwidth=0.7];
"Src/usart.c" -> "Inc/usart.h" [color="#2563eb", penwidth=1.0];
"Src/usart.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"simulator/dbg_log.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"simulator/main.c" -> "App/cfg_file.h" [color="#2563eb", penwidth=1.0];
"simulator/main.c" -> "App/cfg_file_store.h" [color="#2563eb", penwidth=1.0];
"simulator/main.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
"simulator/main.c" -> "Drivers/BSP/NETCFG/net_cfg.h" [color="#2563eb", penwidth=1.0];
"simulator/main.c" -> "Drivers/BSP/UI/ui_menu.h" [color="#2563eb", penwidth=1.0];
"simulator/main.c" -> "Drivers/BSP/UI/ui_net_sink.h" [color="#2563eb", penwidth=1.0];
"simulator/main.c" -> "Drivers/BSP/UI/ui_standby.h" [color="#2563eb", penwidth=1.0];
"simulator/main.c" -> "Lib/lvgl/lvgl.h" [color="#94a3b8", penwidth=0.7];
"simulator/main.c" -> "simulator/SDL2/SDL2-2.32.10/include/SDL.h" [color="#94a3b8", penwidth=0.7];
"simulator/main.c" -> "simulator/sim/sim_port.h" [color="#2563eb", penwidth=1.0];
"simulator/main.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"simulator/sim/cfg_file_store_sim.c" -> "App/cfg_file_store.h" [color="#2563eb", penwidth=1.0];
"simulator/sim/cfg_file_store_sim.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"simulator/sim/net_socket_sim.c" -> "Drivers/BSP/NET/net_socket.h" [color="#2563eb", penwidth=1.0];
"simulator/sim/net_socket_sim.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"simulator/sim/sim_port.c" -> "Lib/lvgl/lvgl.h" [color="#94a3b8", penwidth=0.7];
"simulator/sim/sim_port.c" -> "simulator/SDL2/SDL2-2.32.10/include/SDL.h" [color="#94a3b8", penwidth=0.7];
"simulator/sim/sim_port.c" -> "simulator/sim/sim_port.h" [color="#2563eb", penwidth=1.0];
"simulator/sim/sim_port.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"simulator/sim/sim_syslog.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
"simulator/sim/sim_syslog.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"simulator/sim/ui_net_sink_backend_sim.c" -> "Drivers/BSP/UI/ui_net_sink_backend.h" [color="#2563eb", penwidth=1.0];
"simulator/sim/ui_net_sink_backend_sim.c" -> "Drivers/BSP/UI/ui_port.h" [color="#2563eb", penwidth=1.0];
"simulator/sim/ui_net_sink_backend_sim.c" -> "Lib/lvgl/lvgl.h" [color="#94a3b8", penwidth=0.7];
"simulator/sim/ui_net_sink_backend_sim.c" -> "simulator/sim/sim_port.h" [color="#2563eb", penwidth=1.0];
"test/ch395f_test.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/ch395f_test_task.c" -> "App/sys_events.h" [color="#2563eb", penwidth=1.0];
"test/ch395f_test_task.c" -> "App/task/net_task.h" [color="#2563eb", penwidth=1.0];
"test/ch395f_test_task.c" -> "Drivers/BSP/CH395F/ch395f.h" [color="#2563eb", penwidth=1.0];
"test/ch395f_test_task.c" -> "Drivers/BSP/NET/net_socket.h" [color="#2563eb", penwidth=1.0];
"test/ch395f_test_task.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"test/ch395f_test_task.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"test/ch395f_test_task.c" -> "test/ch395f_test.h" [color="#2563eb", penwidth=1.0];
"test/ch395f_test_task.c" -> "test/ch395f_test_task.h" [color="#2563eb", penwidth=1.0];
"test/ch395f_test_task.c" -> "test/gd5f_test.h" [color="#2563eb", penwidth=1.0];
"test/ch395f_test_task.c" -> "test/net_test_task.h" [color="#2563eb", penwidth=1.0];
"test/ch395f_test_task.c" -> "test/sd2506_test.h" [color="#2563eb", penwidth=1.0];
"test/ch395f_test_task.c" -> "test/storage_test.h" [color="#2563eb", penwidth=1.0];
"test/ch395f_test_task.c" -> "test/test_config.h" [color="#2563eb", penwidth=1.0];
"test/ch395f_test_task.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/gd5f_test.h" -> "Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h" [color="#2563eb", penwidth=1.0];
"test/gd5f_test.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/gd5f_test_task.c" -> "Drivers/BSP/GD5F2GQ5UE/nand_ftl.h" [color="#2563eb", penwidth=1.0];
"test/gd5f_test_task.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"test/gd5f_test_task.c" -> "Lib/FatFs/ff.h" [color="#94a3b8", penwidth=0.7];
"test/gd5f_test_task.c" -> "test/gd5f_test.h" [color="#2563eb", penwidth=1.0];
"test/gd5f_test_task.c" -> "test/test_config.h" [color="#2563eb", penwidth=1.0];
"test/gd5f_test_task.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/net_test_task.c" -> "Drivers/BSP/NET/net_select.h" [color="#2563eb", penwidth=1.0];
"test/net_test_task.c" -> "Drivers/BSP/NET/net_socket.h" [color="#2563eb", penwidth=1.0];
"test/net_test_task.c" -> "Drivers/BSP/NET/net_types.h" [color="#2563eb", penwidth=1.0];
"test/net_test_task.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"test/net_test_task.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"test/net_test_task.c" -> "test/ch395f_test.h" [color="#2563eb", penwidth=1.0];
"test/net_test_task.c" -> "test/ch395f_test_task.h" [color="#2563eb", penwidth=1.0];
"test/net_test_task.c" -> "test/net_test_task.h" [color="#2563eb", penwidth=1.0];
"test/net_test_task.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/sd2506_test.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/sd2506_test_task.c" -> "Drivers/BSP/SD2506/sd2506.h" [color="#2563eb", penwidth=1.0];
"test/sd2506_test_task.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"test/sd2506_test_task.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"test/sd2506_test_task.c" -> "test/sd2506_test.h" [color="#2563eb", penwidth=1.0];
"test/sd2506_test_task.c" -> "test/test_config.h" [color="#2563eb", penwidth=1.0];
"test/sd2506_test_task.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/storage_test.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/storage_test_task.c" -> "Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h" [color="#2563eb", penwidth=1.0];
"test/storage_test_task.c" -> "Drivers/BSP/GD5F2GQ5UE/nand_ftl.h" [color="#2563eb", penwidth=1.0];
"test/storage_test_task.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"test/storage_test_task.c" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
"test/storage_test_task.c" -> "Lib/FatFs/diskio.h" [color="#94a3b8", penwidth=0.7];
"test/storage_test_task.c" -> "Lib/FatFs/ff.h" [color="#94a3b8", penwidth=0.7];
"test/storage_test_task.c" -> "test/storage_test.h" [color="#2563eb", penwidth=1.0];
"test/storage_test_task.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
"test/test_config.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
"test/test_config.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
"test/test_config.c" -> "test/ch395f_test_task.h" [color="#2563eb", penwidth=1.0];
"test/test_config.c" -> "test/gd5f_test.h" [color="#2563eb", penwidth=1.0];
"test/test_config.c" -> "test/sd2506_test.h" [color="#2563eb", penwidth=1.0];
"test/test_config.c" -> "test/storage_test.h" [color="#2563eb", penwidth=1.0];
"test/test_config.c" -> "test/test_config.h" [color="#2563eb", penwidth=1.0];
"test/test_config.h" -> "test/ch395f_test.h" [color="#2563eb", penwidth=1.0];
"test/test_config.h" -> "test/gd5f_test.h" [color="#2563eb", penwidth=1.0];
"test/test_config.h" -> "test/sd2506_test.h" [color="#2563eb", penwidth=1.0];
"test/test_config.h" -> "test/storage_test.h" [color="#2563eb", penwidth=1.0];
"test/test_config.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 287 KiB

+156
View File
@@ -0,0 +1,156 @@
digraph refgraph_module {
graph [rankdir=LR, bgcolor="white", labelloc=t, label="STM32F4-Base 模块引用概览", fontname="Microsoft YaHei", fontsize=18];
node [fontname="Microsoft YaHei", fontsize=12, shape=box, style="rounded,filled"];
edge [fontname="Microsoft YaHei", fontsize=10, fontcolor="#334155"];
"App" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/log" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/task" [fillcolor="#dbeafe", color="#1d4ed8"];
"App/util" [fillcolor="#dbeafe", color="#1d4ed8"];
"BSP(公共)" [fillcolor="#dbeafe", color="#1d4ed8"];
"BSP/CH395F" [fillcolor="#dbeafe", color="#1d4ed8"];
"BSP/GD5F2GQ5UE" [fillcolor="#dbeafe", color="#1d4ed8"];
"BSP/NET" [fillcolor="#dbeafe", color="#1d4ed8"];
"BSP/NETCFG" [fillcolor="#dbeafe", color="#1d4ed8"];
"BSP/RS485" [fillcolor="#dbeafe", color="#1d4ed8"];
"BSP/SD2506" [fillcolor="#dbeafe", color="#1d4ed8"];
"BSP/TPAFE5160" [fillcolor="#dbeafe", color="#1d4ed8"];
"BSP/UI" [fillcolor="#dbeafe", color="#1d4ed8"];
"CMSIS" [fillcolor="#f3f4f6", color="#9ca3af"];
"FatFs" [fillcolor="#f3f4f6", color="#9ca3af"];
"FreeRTOS" [fillcolor="#f3f4f6", color="#9ca3af"];
"HAL" [fillcolor="#f3f4f6", color="#9ca3af"];
"LVGL" [fillcolor="#f3f4f6", color="#9ca3af"];
"SDL2" [fillcolor="#f3f4f6", color="#9ca3af"];
"Src/Inc (CubeMX)" [fillcolor="#dbeafe", color="#1d4ed8"];
"dhara" [fillcolor="#f3f4f6", color="#9ca3af"];
"lftpd" [fillcolor="#f3f4f6", color="#9ca3af"];
"simulator" [fillcolor="#dbeafe", color="#1d4ed8"];
"test" [fillcolor="#dbeafe", color="#1d4ed8"];
"其他(第三方)" [fillcolor="#f3f4f6", color="#9ca3af"];
"外部/系统头文件" [shape=ellipse, fillcolor="#fef3c7", color="#d97706"];
"App" -> "App/log" [color="#2563eb", penwidth=1.2, label="×1"];
"App" -> "App/util" [color="#2563eb", penwidth=1.2, label="×2"];
"App" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×3"];
"App" -> "BSP/GD5F2GQ5UE" [color="#2563eb", penwidth=1.2, label="×1"];
"App" -> "BSP/NET" [color="#2563eb", penwidth=1.2, label="×1"];
"App" -> "BSP/RS485" [color="#2563eb", penwidth=1.2, label="×1"];
"App" -> "BSP/SD2506" [color="#2563eb", penwidth=1.2, label="×1"];
"App" -> "BSP/TPAFE5160" [color="#2563eb", penwidth=1.2, label="×1"];
"App" -> "FatFs" [color="#2563eb", penwidth=1.2, label="×1"];
"App" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×1"];
"App" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×2"];
"App" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×7"];
"App/log" -> "App/util" [color="#2563eb", penwidth=1.2, label="×1"];
"App/log" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×1"];
"App/log" -> "FatFs" [color="#2563eb", penwidth=1.2, label="×1"];
"App/log" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×1"];
"App/log" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×2"];
"App/task" -> "App" [color="#2563eb", penwidth=1.2, label="×2"];
"App/task" -> "App/log" [color="#2563eb", penwidth=1.2, label="×1"];
"App/task" -> "App/util" [color="#2563eb", penwidth=1.2, label="×1"];
"App/task" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×4"];
"App/task" -> "BSP/CH395F" [color="#2563eb", penwidth=1.2, label="×1"];
"App/task" -> "BSP/NET" [color="#2563eb", penwidth=1.2, label="×2"];
"App/task" -> "BSP/NETCFG" [color="#2563eb", penwidth=1.2, label="×1"];
"App/task" -> "BSP/RS485" [color="#2563eb", penwidth=1.2, label="×1"];
"App/task" -> "BSP/TPAFE5160" [color="#2563eb", penwidth=1.2, label="×1"];
"App/task" -> "BSP/UI" [color="#2563eb", penwidth=1.2, label="×4"];
"App/task" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×4"];
"App/task" -> "test" [color="#2563eb", penwidth=1.2, label="×1"];
"App/task" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×2"];
"App/util" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×1"];
"App/util" -> "BSP/SD2506" [color="#2563eb", penwidth=1.2, label="×1"];
"App/util" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×2"];
"App/util" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×1"];
"App/util" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×4"];
"BSP(公共)" -> "App/util" [color="#2563eb", penwidth=1.2, label="×1"];
"BSP(公共)" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×1"];
"BSP/CH395F" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×1"];
"BSP/CH395F" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×3"];
"BSP/CH395F" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×1"];
"BSP/GD5F2GQ5UE" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×2"];
"BSP/GD5F2GQ5UE" -> "FatFs" [color="#2563eb", penwidth=1.2, label="×2"];
"BSP/GD5F2GQ5UE" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×1"];
"BSP/GD5F2GQ5UE" -> "dhara" [color="#2563eb", penwidth=1.2, label="×2"];
"BSP/GD5F2GQ5UE" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×4"];
"BSP/NET" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×1"];
"BSP/NET" -> "BSP/CH395F" [color="#2563eb", penwidth=1.2, label="×2"];
"BSP/NET" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×8"];
"BSP/NET" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×2"];
"BSP/NET" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×3"];
"BSP/NETCFG" -> "App" [color="#2563eb", penwidth=1.2, label="×3"];
"BSP/NETCFG" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×2"];
"BSP/NETCFG" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×3"];
"BSP/RS485" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×1"];
"BSP/SD2506" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×2"];
"BSP/SD2506" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×1"];
"BSP/TPAFE5160" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×1"];
"BSP/TPAFE5160" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×2"];
"BSP/UI" -> "App/log" [color="#2563eb", penwidth=1.2, label="×2"];
"BSP/UI" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×4"];
"BSP/UI" -> "BSP/NET" [color="#2563eb", penwidth=1.2, label="×2"];
"BSP/UI" -> "BSP/NETCFG" [color="#2563eb", penwidth=1.2, label="×1"];
"BSP/UI" -> "LVGL" [color="#2563eb", penwidth=1.2, label="×9"];
"BSP/UI" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×20"];
"CMSIS" -> "HAL" [color="#94a3b8", penwidth=0.7, label="×1"];
"CMSIS" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×22"];
"FatFs" -> "App/util" [color="#94a3b8", penwidth=0.7, label="×1"];
"FatFs" -> "FreeRTOS" [color="#94a3b8", penwidth=0.7, label="×1"];
"FatFs" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×2"];
"FreeRTOS" -> "CMSIS" [color="#94a3b8", penwidth=0.7, label="×1"];
"FreeRTOS" -> "Src/Inc (CubeMX)" [color="#94a3b8", penwidth=0.7, label="×1"];
"FreeRTOS" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×14"];
"HAL" -> "CMSIS" [color="#94a3b8", penwidth=0.7, label="×13"];
"HAL" -> "Src/Inc (CubeMX)" [color="#94a3b8", penwidth=0.7, label="×1"];
"HAL" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×1"];
"LVGL" -> "FatFs" [color="#94a3b8", penwidth=0.7, label="×1"];
"LVGL" -> "FreeRTOS" [color="#94a3b8", penwidth=0.7, label="×6"];
"LVGL" -> "SDL2" [color="#94a3b8", penwidth=0.7, label="×1"];
"LVGL" -> "其他(第三方)" [color="#94a3b8", penwidth=0.7, label="×1"];
"LVGL" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×204"];
"SDL2" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×36"];
"Src/Inc (CubeMX)" -> "App" [color="#2563eb", penwidth=1.2, label="×4"];
"Src/Inc (CubeMX)" -> "App/log" [color="#2563eb", penwidth=1.2, label="×1"];
"Src/Inc (CubeMX)" -> "App/task" [color="#2563eb", penwidth=1.2, label="×1"];
"Src/Inc (CubeMX)" -> "App/util" [color="#2563eb", penwidth=1.2, label="×1"];
"Src/Inc (CubeMX)" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×2"];
"Src/Inc (CubeMX)" -> "BSP/CH395F" [color="#2563eb", penwidth=1.2, label="×2"];
"Src/Inc (CubeMX)" -> "BSP/GD5F2GQ5UE" [color="#2563eb", penwidth=1.2, label="×2"];
"Src/Inc (CubeMX)" -> "BSP/NET" [color="#2563eb", penwidth=1.2, label="×3"];
"Src/Inc (CubeMX)" -> "BSP/NETCFG" [color="#2563eb", penwidth=1.2, label="×1"];
"Src/Inc (CubeMX)" -> "BSP/RS485" [color="#2563eb", penwidth=1.2, label="×1"];
"Src/Inc (CubeMX)" -> "BSP/SD2506" [color="#2563eb", penwidth=1.2, label="×1"];
"Src/Inc (CubeMX)" -> "BSP/TPAFE5160" [color="#2563eb", penwidth=1.2, label="×1"];
"Src/Inc (CubeMX)" -> "CMSIS" [color="#2563eb", penwidth=1.2, label="×1"];
"Src/Inc (CubeMX)" -> "FatFs" [color="#2563eb", penwidth=1.2, label="×1"];
"Src/Inc (CubeMX)" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×4"];
"Src/Inc (CubeMX)" -> "HAL" [color="#2563eb", penwidth=1.2, label="×14"];
"Src/Inc (CubeMX)" -> "lftpd" [color="#2563eb", penwidth=1.2, label="×1"];
"Src/Inc (CubeMX)" -> "test" [color="#2563eb", penwidth=1.2, label="×2"];
"Src/Inc (CubeMX)" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×5"];
"dhara" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×5"];
"lftpd" -> "BSP(公共)" [color="#94a3b8", penwidth=0.7, label="×3"];
"lftpd" -> "BSP/NET" [color="#94a3b8", penwidth=0.7, label="×3"];
"lftpd" -> "FatFs" [color="#94a3b8", penwidth=0.7, label="×2"];
"lftpd" -> "FreeRTOS" [color="#94a3b8", penwidth=0.7, label="×2"];
"lftpd" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×8"];
"simulator" -> "App" [color="#2563eb", penwidth=1.2, label="×3"];
"simulator" -> "App/log" [color="#2563eb", penwidth=1.2, label="×2"];
"simulator" -> "BSP/NET" [color="#2563eb", penwidth=1.2, label="×1"];
"simulator" -> "BSP/NETCFG" [color="#2563eb", penwidth=1.2, label="×1"];
"simulator" -> "BSP/UI" [color="#2563eb", penwidth=1.2, label="×5"];
"simulator" -> "LVGL" [color="#2563eb", penwidth=1.2, label="×3"];
"simulator" -> "SDL2" [color="#2563eb", penwidth=1.2, label="×2"];
"simulator" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×6"];
"test" -> "App" [color="#2563eb", penwidth=1.2, label="×1"];
"test" -> "App/task" [color="#2563eb", penwidth=1.2, label="×1"];
"test" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×6"];
"test" -> "BSP/CH395F" [color="#2563eb", penwidth=1.2, label="×1"];
"test" -> "BSP/GD5F2GQ5UE" [color="#2563eb", penwidth=1.2, label="×4"];
"test" -> "BSP/NET" [color="#2563eb", penwidth=1.2, label="×4"];
"test" -> "BSP/SD2506" [color="#2563eb", penwidth=1.2, label="×1"];
"test" -> "FatFs" [color="#2563eb", penwidth=1.2, label="×3"];
"test" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×4"];
"test" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×1"];
"test" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×10"];
}
File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 94 KiB

+102
View File
@@ -0,0 +1,102 @@
# 项目文件引用关系图(tools/refgraph)
> 生成并维护 STM32F4-Base 的**文件级引用关系图**(`#include` 引用)。
> 工具:`tools/refgraph/gen_refgraph.py`(纯标准库)+ 成熟渲染引擎 Graphviz。
> 产物:`docs/images/引用关系图.*`(本目录图 + `.dot` + `.json`)。
## 1. 为什么自写工具(调研结论)
| 成熟工具 | 能力 | 对本需求的差距 |
|---|---|---|
| **Doxygen**(开源,C 文档标准工具) | 每文件的 include 依赖图、每函数的调用图、类协作图 | 输出按文件/函数**分散**,无单一整工程文件引用图;需配置解析全量源码 |
| **Graphviz**(开源,图布局渲染引擎 `dot`) | 渲染任意 DOT 图(分层布局) | 只做布局渲染、不解析源码 —— **本工具用它出图** |
| **cflow**(binutils) | 函数级调用图 | 粒度是函数不是文件;依赖汇编/编译产物 |
| **SciTools Understand**(商业) | 依赖图/调用树/引用映射 | 重量级付费 IDE,不可脚本化、不入构建流程 |
结论:**没有现成成熟工具能直接输出"单一、整工程、可重跑更新"的文件引用关系图**,
故按"没有则自写"原则自写解析/建模工具;布局渲染这一难点交给成熟引擎 Graphviz。
本机已通过 winget 安装 Graphviz 16.1.0(`C:\Program Files\Graphviz`)。
## 2. 生成 / 更新(一条命令)
```powershell
# 方式一:bat(任意位置可运行)
& 'tools\refgraph\gen_refgraph.bat'
# 方式二:python 直跑(等效)
& '.venv\Scripts\python.exe' tools/refgraph/gen_refgraph.py
```
**项目文件有增删改后,重跑上式即可**:产物全量重新生成并覆盖
`docs/images/引用关系图.*`,对照 `引用关系图.json` 的文本 diff 即可看出引用面变化,
然后按仓库惯例把(工具 + 产物)一并提交。
可选参数:
| 参数 | 默认 | 说明 |
|---|---|---|
| `--views full,module` | 两者 | 只出文件级 / 只出模块级 |
| `--edge-scope project\|all` | `project` | project=仅第一方代码发起的引用边(清晰);all=含第三方内部引用(完整但密集) |
| `--no-render` | 关 | 只出 `.dot`/`.json`,不调 Graphviz |
| `--quiet` | 关 | 精简控制台输出 |
## 3. 产物与图例
| 文件 | 说明 | 是否提交 |
|---|---|---|
| `引用关系图.svg` / `.dot` | **文件级引用图**(项目代码视图) | 是 |
| `引用关系图_模块.svg` / `.dot` | **模块级概览图**(目录/库聚合,边上 ×n=引用条数) | 是 |
| `引用关系图.json` | 结构化数据:全部节点/边/未解析 include 明细 | 是 |
| `引用关系图.png` | 文件级图位图预览(大,~5 MB) | 否(本地预览,可随时重出) |
图例(文件级):
- 节点:**蓝=第一方**(App/、Inc/、Src/、test/、simulator/〔除 SDL2、build〕、
Drivers/BSP/〔除 NET/lftpd〕);**灰=第三方**(Lib/、Middlewares/、
Drivers/CMSIS、HAL、lftpd、SDL2);**橙=外部/系统头文件**聚合节点。
- 边:`蓝实线` 第一方→第一方;`灰实线` 第一方→第三方;
`橙虚线` →外部/系统头文件(stdio.h 等编译器提供);
`all` 模式下另有淡点线=第三方内部引用。
模块级图把第一方按目录模块聚合(App、App/task、BSP/UI、Src/Inc (CubeMX)…)、
第三方按库聚合(LVGL、FreeRTOS、CMSIS、HAL、FatFs、dhara、lftpd、SDL2)。
## 4. 解析原理(与编译器行为对齐)
1. 扫描仓库全部 `.c/.h`(跳过 `.git`/`.venv`/`MDK-ARM`/`docs`/`simulator/build`);
2. 提取每条 `#include`(处理行尾反斜杠续行;编码按 UTF-8→GBK→Latin-1 兜底);
3. 解析顺序与编译器一致:**所在文件目录 → Keil 工程包含路径(解析自
`MDK-ARM/STM32F407-Demo.uvprojx`,自动跟随)→ 模拟器 CMake 包含路径
(`simulator/CMakeLists.txt`,脚本内 `SIM_INCLUDE_DIRS` 需手动同步)**;
4. 解析到仓库内文件 → 成边;解析不到 → 归"外部/系统头文件"(明细在 JSON
`unresolved`),与编译器查系统目录的行为一致。
5. **刻意不做"基名全库兜底"**:仓库内存在同名系统头(rapidjson 自带
`msinttypes/stdint.h`),兜底会把各处 `<stdint.h>` 误连到库内部文件产生假边
(曾产生 100+ 条假边,已验证并移除)。
## 5. 语义与已知限制
- **文本层引用**:`#if 0` 内、MCU/模拟器平台条件下的引用均计入(完整呈现项目引用面);
不评估 `#if` 条件 —— 未激活条件内的引用(如 `LV_USE_DRAW_VG_LITE=0` 时的
`vg_lite.h`)会显示为"未解析→外部",属预期。
- 仅**文件级 `#include` 引用**;不含函数级调用关系(如需,可另行用 Doxygen/cflow 补充)。
- 双端(Keil MCU / CMake 模拟器)包含路径合并解析,个别引用是"另一端视角"
(如 LVGL 的 SDL2 后端引用),属项目级引用面的如实呈现。
- 第一方/第三方划分规则见脚本头部 `classify()`;lftpd 为移植的第三方组件
(与 AGENTS.md pre-commit 排除名单一致)。
## 6. 维护
- 新增/移动第一方目录 → 改脚本 `classify()`、`FP_MODULES`;
新增第三方库 → 改 `TP_LIBS`(模块级聚合用)。
- Keil 工程包含路径变化:**自动跟随**(每次运行解析 uvprojx)。
- 模拟器包含路径变化:同步脚本 `SIM_INCLUDE_DIRS` 常量。
- 换机:`winget install Graphviz.Graphviz`(渲染依赖;缺失时工具自动跳过渲染,
仍产出 `.dot`)。
## 7. 当前数据(2026-09-16 首版)
索引 1396 个 `.c/.h`;解析 include 5588 条(解析成功 4539,外部/系统 1049,
353 种);第一方文件 126 个;去重边 4823 条。
被引用最多的第一方文件:`Drivers/BSP/dbg_log.h`(31)、`Inc/main.h`(20)、
`Drivers/BSP/NET/net_socket.h`(12)……(完整 Top10 见运行报告)。
+8
View File
@@ -0,0 +1,8 @@
@echo off
rem ============================================================
rem 重新生成项目文件引用关系图
rem 产物: docs\images\引用关系图.* (.dot/.svg/.png/.json)
rem 项目文件有增删改后,在仓库任意位置运行本脚本即可更新。
rem ============================================================
"%~dp0..\..\.venv\Scripts\python.exe" "%~dp0gen_refgraph.py" %*
exit /b %errorlevel%
+652
View File
@@ -0,0 +1,652 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
gen_refgraph.py — STM32F4-Base 项目文件引用关系图生成器
=====================================================================
功能:
扫描仓库内全部 C 源文件(.c/.h),解析 #include 指令,按 Keil 工程
(MDK-ARM/STM32F407-Demo.uvprojx) 与 LVGL 模拟器 (simulator/CMakeLists.txt)
的包含路径将引用解析到具体文件,构建文件级引用关系图,输出 Graphviz
DOT / SVG / PNG 与结构化 JSON 数据。
产物(默认输出到 docs/images/,随脚本一并提交,项目变化后重跑更新):
引用关系图.dot / .svg / .png —— 全量文件级引用图(一手指方+第三方)
引用关系图_模块.dot / .svg —— 模块级概览图(目录/库聚合)
引用关系图.json —— 结构化数据(节点/边/未解析引用)
用法(仓库根目录):
& '.venv\\Scripts\\python.exe' tools/refgraph/gen_refgraph.py
或双击/运行 tools/refgraph/gen_refgraph.bat
选项:
--root PATH 仓库根目录(默认:脚本上两级目录)
--outdir PATH 产物目录(默认 <root>/docs/images)
--views a,b 要生成的视图,可选 full / module(默认两者)
--edge-scope S project = 仅第一方代码发起的引用边(默认,图最清晰);
all = 含第三方内部引用边(完整但密集,淡显)
--no-render 只生成 .dot/.json,不调用 Graphviz 渲染
--quiet 只输出关键行
引用解析规则(与编译器搜索顺序一致):
1. "..." 引用优先按所在文件目录解析,再按包含路径顺序查找;
2. <...> 引用按包含路径顺序查找;
3. 仍解析不到 → 归入“外部/系统头文件”(如 stdio.h/stdint.h),
明细见 JSON 的 unresolved 字段。
注:刻意不做“基名全库兜底”——仓库内存在同名系统头文件
(rapidjson 自带 msinttypes/stdint.h)时会把 <stdint.h> 误连到
库内部文件产生假边;编译器的系统目录不在仓库内,统一归外部。
说明:
- 纯标准库实现,无第三方依赖;渲染依赖 Graphviz(dot 可执行文件),
未安装时自动跳过渲染(仍产出 .dot,可用任意 Graphviz 渲染)。
- 文本层解析(不预编译):#if 0 内的引用、MCU/模拟器双端平台差异
引用均按“文件存在引用”计入,完整呈现项目级引用面。
- 第一方代码 = App/、Inc/、Src/、test/、simulator/(SDL2 与 build 除外)、
Drivers/BSP/(NET/lftpd 除外,其为移植的第三方组件);
其余(Lib/、Middlewares/、Drivers/CMSIS、HAL、lftpd、SDL2)= 第三方。
维护:
simulator/CMakeLists.txt 的 include_directories 若变化,请同步下方
SIM_INCLUDE_DIRS;Keil 工程包含路径变化则自动跟随(解析自 uvprojx)。
"""
from __future__ import annotations
import argparse
import datetime as _dt
import json
import os
import re
import shutil
import subprocess
import sys
# ---------------------------------------------------------------------------
# 常量:第一方判定 / 排除目录 / 模块与库划分
# ---------------------------------------------------------------------------
# 文件索引时整体跳过的目录(按相对路径前缀,'/' 分隔)
EXCLUDE_PREFIXES = ("MDK-ARM", "docs", "simulator/build")
# 按目录名跳过(任意层级)
EXCLUDE_DIRNAMES = (".git", ".venv", "node_modules")
# simulator/CMakeLists.txt 的 include_directories(相对仓库根;保持同步)
SIM_INCLUDE_DIRS = (
"simulator",
"simulator/sim",
"Lib/lvgl",
"Lib/lvgl/src",
"Drivers/BSP/UI",
"Drivers/BSP/NET",
"Drivers/BSP/NETCFG",
"App",
"App/log",
"Drivers/BSP",
"simulator/SDL2/SDL2-2.32.10/include",
)
# 模块级视图:第一方模块(长前缀优先匹配)
FP_MODULES = (
("App/log", "App/log"),
("App/task", "App/task"),
("App/util", "App/util"),
("App", "App"),
("test", "test"),
("simulator", "simulator"),
("Drivers/BSP/CH395F", "BSP/CH395F"),
("Drivers/BSP/GD5F2GQ5UE", "BSP/GD5F2GQ5UE"),
("Drivers/BSP/NETCFG", "BSP/NETCFG"),
("Drivers/BSP/NET", "BSP/NET"),
("Drivers/BSP/RS485", "BSP/RS485"),
("Drivers/BSP/SD2506", "BSP/SD2506"),
("Drivers/BSP/TPAFE5160", "BSP/TPAFE5160"),
("Drivers/BSP/UI", "BSP/UI"),
("Drivers/BSP", "BSP(公共)"),
# Src/ 与 Inc/ 为 CubeMX 配对生成(main.c↔main.h 等),模块级合并
("Src", "Src/Inc (CubeMX)"),
("Inc", "Src/Inc (CubeMX)"),
)
# 模块级视图:第三方库(长前缀优先匹配)
TP_LIBS = (
("Lib/lvgl", "LVGL"),
("Middlewares/Third_Party/FreeRTOS", "FreeRTOS"),
("Drivers/CMSIS", "CMSIS"),
("Drivers/STM32F4xx_HAL_Driver", "HAL"),
("Lib/FatFs", "FatFs"),
("Lib/dhara", "dhara"),
("Drivers/BSP/NET/lftpd", "lftpd"),
("simulator/SDL2", "SDL2"),
)
EXT_NODE = "外部/系统头文件"
# 颜色方案
C_FP, C_FP_BORDER = "#dbeafe", "#1d4ed8"
C_TP, C_TP_BORDER = "#f3f4f6", "#9ca3af"
C_EXT, C_EXT_BORDER = "#fef3c7", "#d97706"
E_FPFP, E_FPFP_W = "#2563eb", 1.0
E_FPTP, E_FPTP_W = "#94a3b8", 0.7
E_TPTP, E_TPTP_W = "#e2e8f0", 0.5
E_EXT, E_EXT_W = "#f59e0b", 0.6
# ---------------------------------------------------------------------------
# 读取 / 编码
# ---------------------------------------------------------------------------
def read_text(path: str) -> str:
"""按项目约定读文本:UTF-8(含 BOM)→ GBK → Latin-1 兜底。"""
with open(path, "rb") as f:
data = f.read()
if data.startswith(b"\xef\xbb\xbf"):
data = data[3:]
for enc in ("utf-8", "gbk", "latin-1"):
try:
return data.decode(enc)
except UnicodeDecodeError:
continue
return data.decode("utf-8", errors="replace") # 理论不可达
# ---------------------------------------------------------------------------
# 工程信息:包含路径 / 文件索引 / 分类
# ---------------------------------------------------------------------------
def classify(rel: str) -> str:
"""rel 为 '/' 分隔相对路径;返回 'fp'(第一方) 或 'tp'(第三方)。"""
if rel.startswith(("App/", "Inc/", "Src/", "test/")):
return "fp"
if rel.startswith("simulator/"):
if rel.startswith(("simulator/SDL2/", "simulator/build/")):
return "tp"
return "fp"
if rel.startswith("Drivers/BSP/"):
if rel.startswith("Drivers/BSP/NET/lftpd/"):
return "tp"
return "fp"
return "tp"
def load_include_dirs(root: str) -> list[str]:
"""合并 Keil 工程(uvprojx)与模拟器的包含目录,按序去重。"""
dirs: list[str] = []
seen: set[str] = set()
def add(p: str) -> None:
ap = os.path.normpath(p)
if ap not in seen and os.path.isdir(ap):
seen.add(ap)
dirs.append(ap)
uvprojx = os.path.join(root, "MDK-ARM", "STM32F407-Demo.uvprojx")
if os.path.isfile(uvprojx):
text = read_text(uvprojx)
for m in re.finditer(r"<IncludePath>(.*?)</IncludePath>", text, re.S):
for part in m.group(1).replace("\\", "/").split(";"):
part = part.strip()
if part:
add(os.path.join(root, "MDK-ARM", part))
for part in SIM_INCLUDE_DIRS:
add(os.path.join(root, *part.split("/")))
return dirs
def build_index(root: str) -> list[tuple[str, str]]:
"""收集仓库内全部 .c/.h 文件 → [(绝对路径, 相对路径)]。"""
out: list[tuple[str, str]] = []
for dirpath, dirnames, filenames in os.walk(root):
rel_dir = os.path.relpath(dirpath, root).replace(os.sep, "/")
if rel_dir == ".":
rel_dir = ""
if any(seg in EXCLUDE_DIRNAMES for seg in rel_dir.split("/")):
dirnames[:] = []
continue
if any(rel_dir == p or rel_dir.startswith(p + "/") for p in EXCLUDE_PREFIXES):
dirnames[:] = []
continue
for fn in sorted(filenames):
if fn.lower().endswith((".c", ".h")):
out.append((os.path.join(dirpath, fn),
f"{rel_dir}/{fn}" if rel_dir else fn))
return out
class Resolver:
"""#include 名称 → 仓库内文件 的解析器(顺序与编译器一致)。
仅按“文件目录 + 包含路径”解析(编译器实际使用的搜索顺序)。
刻意不做“基名全库兜底”:仓库内恰好存在同名的系统头文件
(如 rapidjson 自带的 msinttypes/stdint.h)时会把 <stdint.h>
之类误连到库内部文件,产生虚假引用边。解析不到的 include
一律归入“外部/系统头文件”,与编译器的系统目录行为一致。
"""
def __init__(self, root: str, files: list[tuple[str, str]], inc_dirs: list[str]):
self.root = root
self.inc_dirs = inc_dirs
# (包含目录, 相对名小写) → 绝对路径
self.by_increl: dict[tuple[str, str], str] = {}
for d in inc_dirs:
dl = d.lower()
for ap, _ in files:
apl = ap.lower()
if apl.startswith(dl + os.sep):
rel = ap[len(d):].lstrip(os.sep).replace(os.sep, "/")
key = (d, rel.lower())
self.by_increl.setdefault(key, ap)
def resolve(self, name: str, from_file: str, quoted: bool) -> str | None:
name = name.strip()
if not name:
return None
fname = name.replace("/", os.sep)
# 1) 所在文件目录("..." 标准行为;<...> 亦允许相对,如 "../x.h")
if os.path.isabs(name):
return None
cand = os.path.normpath(os.path.join(os.path.dirname(from_file), fname))
if os.path.isfile(cand):
return cand
# 2) 包含路径顺序查找(精确相对名;Windows 不区分大小写)
for d in self.inc_dirs:
cand = os.path.normpath(os.path.join(d, fname))
if os.path.isfile(cand):
return cand
hit = self.by_increl.get((d, name.lower()))
if hit:
return hit
# 3) 仓库根
cand = os.path.normpath(os.path.join(self.root, fname))
if os.path.isfile(cand):
return cand
return None
# ---------------------------------------------------------------------------
# #include 解析
# ---------------------------------------------------------------------------
INC_RE = re.compile(r'^\s*#\s*include\s*(?:"(?P<q>[^"\r\n]*)"|<(?P<a>[^>\r\n]+)>)')
def parse_includes(path: str) -> list[tuple[str, bool, int]]:
"""返回 [(include名, 是否引号式, 行号)];处理行尾反斜杠续行。"""
text = read_text(path)
lines = text.splitlines()
n = len(lines)
out: list[tuple[str, bool, int]] = []
i = 0
while i < n:
line = lines[i]
if line.lstrip()[:1] != "#":
i += 1
continue
m = INC_RE.match(line)
if not m:
i += 1
continue
# 续行拼接后再匹配
logical, j = line, i
while logical.rstrip().endswith("\\") and j + 1 < n:
logical = logical.rstrip()[:-1] + lines[j + 1]
j += 1
m = INC_RE.match(logical)
if m:
quoted = m.group("q") is not None
name = (m.group("q") if quoted else m.group("a") or "").strip()
if name:
out.append((name, quoted, i + 1))
i = j + 1
return out
# ---------------------------------------------------------------------------
# DOT 输出
# ---------------------------------------------------------------------------
def dot_escape(s: str) -> str:
return s.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")
def file_module(rel: str) -> str:
for prefix, label in FP_MODULES:
if rel == prefix or rel.startswith(prefix + "/"):
return label
return "其他(第一方)"
def file_lib(rel: str) -> str:
for prefix, label in TP_LIBS:
if rel == prefix or rel.startswith(prefix + "/"):
return label
return "其他(第三方)"
class Graph:
def __init__(self) -> None:
self.nodes: dict[str, dict] = {} # rel -> {cls, label, ...}
self.edges: dict[tuple[str, str], dict] = {} # (from,to) -> {kind,...}
self.edge_list: list[dict] = [] # JSON 用(含 include 明细)
def add_node(self, rel: str, cls: str) -> None:
if rel not in self.nodes:
self.nodes[rel] = {"path": rel, "class": cls}
def add_edge(self, src: str, dst: str, kind: str, include: str | None = None) -> None:
key = (src, dst)
if key not in self.edges:
self.edges[key] = {"kind": kind}
self.edge_list.append({"from": src, "to": dst, "kind": kind, "include": include})
# ---- 全量文件级视图 ----
def emit_dot_full(self, title: str, edge_scope: str) -> str:
# project 模式:只显示第一方文件发起的边(第一方 → 任意),
# 隐藏第三方内部引用网(tp→tp / tp→外部),节点随之收敛。
fp_nodes = {r for r, nd in self.nodes.items() if nd["class"] == "fp"}
if edge_scope == "project":
vis_edges = {k: v for k, v in self.edges.items() if k[0] in fp_nodes}
vis_nodes = set(fp_nodes) | {d for (_, d) in vis_edges}
else:
vis_edges, vis_nodes = self.edges, set(self.nodes)
L: list[str] = []
L.append("digraph refgraph_full {")
L.append(
' graph [rankdir=LR, bgcolor="white", labelloc=t, '
f'label="{dot_escape(title)}", fontname="Microsoft YaHei", fontsize=18];'
)
L.append(' node [fontname="Microsoft YaHei", fontsize=10, shape=box, style="rounded,filled"];')
L.append(" edge [fontname=\"Microsoft YaHei\", fontsize=8];")
for rel in sorted(vis_nodes):
nd = self.nodes[rel]
cls = nd["class"]
if cls == "fp":
fill, border = C_FP, C_FP_BORDER
elif cls == "ext":
fill, border = C_EXT, C_EXT_BORDER
L.append(f' "{dot_escape(EXT_NODE)}" [shape=ellipse, fillcolor="{fill}", color="{border}", fontsize=12];')
continue
else:
fill, border = C_TP, C_TP_BORDER
L.append(f' "{dot_escape(rel)}" [fillcolor="{fill}", color="{border}"];')
# 边
for (src, dst), ed in sorted(vis_edges.items()):
kind = ed["kind"]
if kind == "fp-fp":
spec = f'color="{E_FPFP}", penwidth={E_FPFP_W}'
elif kind == "fp-tp":
spec = f'color="{E_FPTP}", penwidth={E_FPTP_W}'
elif kind == "fp-ext":
spec = f'color="{E_EXT}", penwidth={E_EXT_W}, style=dashed'
elif kind == "tp-tp":
spec = f'color="{E_TPTP}", penwidth={E_TPTP_W}, style=dotted'
else: # tp-ext
spec = f'color="{E_EXT}", penwidth={E_EXT_W * 0.7}, style=dashed'
dst_q = dot_escape(EXT_NODE) if dst == EXT_NODE else dot_escape(dst)
L.append(f' "{dot_escape(src)}" -> "{dst_q}" [{spec}];')
L.append("}")
return "\n".join(L) + "\n"
# ---- 模块级视图 ----
def emit_dot_module(self, title: str) -> str:
mod_edges: dict[tuple[str, str], dict] = {}
mod_nodes: dict[str, str] = {} # label -> cls
for rel, nd in self.nodes.items():
if nd["class"] == "fp":
mod_nodes.setdefault(file_module(rel), "fp")
elif nd["class"] == "tp":
mod_nodes.setdefault(file_lib(rel), "tp")
if EXT_NODE in self.nodes:
mod_nodes[EXT_NODE] = "ext"
for (src, dst), ed in self.edges.items():
if dst == EXT_NODE:
msrc = file_module(src) if self.nodes[src]["class"] == "fp" else file_lib(src)
key = (msrc, EXT_NODE)
else:
sc = self.nodes[src]["class"]
msrc = file_module(src) if sc == "fp" else file_lib(src)
mc = self.nodes[dst]["class"]
mdst = file_module(dst) if mc == "fp" else file_lib(dst)
key = (msrc, mdst)
if key[0] == key[1]:
continue
e = mod_edges.setdefault(key, {"n": 0, "kind": ed["kind"]})
e["n"] += 1
L: list[str] = []
L.append("digraph refgraph_module {")
L.append(
' graph [rankdir=LR, bgcolor="white", labelloc=t, '
f'label="{dot_escape(title)}", fontname="Microsoft YaHei", fontsize=18];'
)
L.append(' node [fontname="Microsoft YaHei", fontsize=12, shape=box, style="rounded,filled"];')
L.append(" edge [fontname=\"Microsoft YaHei\", fontsize=10, fontcolor=\"#334155\"];")
for label, cls in sorted(mod_nodes.items()):
if cls == "fp":
fill, border = C_FP, C_FP_BORDER
elif cls == "ext":
fill, border = C_EXT, C_EXT_BORDER
L.append(f' "{dot_escape(label)}" [shape=ellipse, fillcolor="{fill}", color="{border}"];')
continue
else:
fill, border = C_TP, C_TP_BORDER
L.append(f' "{dot_escape(label)}" [fillcolor="{fill}", color="{border}"];')
for (s, d), e in sorted(mod_edges.items()):
strong = e["kind"] in ("fp-fp", "fp-tp")
color = "#2563eb" if strong else "#94a3b8"
w = 1.2 if strong else 0.7
lbl = f"×{e['n']}"
ds = dot_escape(EXT_NODE) if d == EXT_NODE else dot_escape(d)
L.append(f' "{dot_escape(s)}" -> "{ds}" [color="{color}", penwidth={w}, label="{dot_escape(lbl)}"];')
L.append("}")
return "\n".join(L) + "\n"
# ---------------------------------------------------------------------------
# Graphviz 渲染
# ---------------------------------------------------------------------------
def find_dot() -> str | None:
p = shutil.which("dot")
if p:
return p
for c in (r"C:\Program Files\Graphviz\bin\dot.exe",
r"C:\Program Files (x86)\Graphviz\bin\dot.exe"):
if os.path.isfile(c):
return c
return None
def render(dot: str, dotfile: str, outfiles: dict[str, str]) -> bool:
"""outfiles: {格式: 输出路径},如 {'svg': ..., 'png': ...}"""
ok = True
for fmt, outp in outfiles.items():
argv = [dot, "-T" + fmt]
if fmt == "png":
argv += ["-Gdpi=130"]
argv += [dotfile, "-o", outp]
r = subprocess.run(argv, capture_output=True, text=True)
if r.returncode != 0:
ok = False
print(f"[refgraph] 渲染失败 {fmt}: {r.stderr.strip()[:300]}", file=sys.stderr)
return ok
# ---------------------------------------------------------------------------
# 主流程
# ---------------------------------------------------------------------------
def build(root: str) -> tuple[Graph, dict]:
files = build_index(root)
inc_dirs = load_include_dirs(root)
resolver = Resolver(root, files, inc_dirs)
g = Graph()
unresolved: dict[str, list[str]] = {}
stats = {
"files_indexed": len(files),
"includes_parsed": 0,
"resolved": 0,
"unresolved": 0,
"nodes_fp": 0,
"nodes_tp": 0,
"ext_names": 0,
}
ext_names: set[str] = set()
# 先登记全部第一方文件为节点(含无引用的孤立文件)
for ap, rel in files:
if classify(rel) == "fp":
g.add_node(rel, "fp")
stats["nodes_fp"] += 1
for ap, rel in files:
src_cls = classify(rel)
for name, quoted, lineno in parse_includes(ap):
stats["includes_parsed"] += 1
target = resolver.resolve(name, ap, quoted)
if target:
# 相对路径
trel = os.path.relpath(target, root).replace(os.sep, "/")
tcls = classify(trel)
g.add_node(rel, src_cls)
g.add_node(trel, tcls)
kind = ("fp-fp" if (src_cls == "fp" and tcls == "fp")
else "fp-tp" if (src_cls == "fp" and tcls == "tp")
else "tp-tp")
g.add_edge(rel, trel, kind, name)
stats["resolved"] += 1
else:
stats["unresolved"] += 1
ext_names.add(name)
g.add_node(rel, src_cls)
g.add_node(EXT_NODE, "ext")
g.add_edge(rel, EXT_NODE, "fp-ext" if src_cls == "fp" else "tp-ext", name)
unresolved.setdefault(rel, []).append(name)
# 节点计数修正(tp 节点 = 实际出现的第三方文件节点)
stats["nodes_tp"] = sum(1 for nd in g.nodes.values()
if nd["class"] == "tp") if EXT_NODE not in g.nodes else \
sum(1 for r, nd in g.nodes.items() if nd["class"] == "tp")
stats["ext_names"] = len(ext_names)
stats["include_dirs"] = [os.path.relpath(d, root).replace(os.sep, "/") for d in inc_dirs]
meta = {
"unresolved_by_file": {k: sorted(set(v)) for k, v in sorted(unresolved.items())},
"ext_names_sorted": sorted(ext_names),
}
return g, {**stats, **meta}
def main() -> int:
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
sys.stderr.reconfigure(encoding="utf-8", errors="replace")
here = os.path.dirname(os.path.abspath(__file__))
ap = argparse.ArgumentParser(description="STM32F4-Base 文件引用关系图生成器")
ap.add_argument("--root", default=os.path.dirname(os.path.dirname(here)),
help="仓库根目录(默认:脚本上两级目录)")
ap.add_argument("--outdir", default=None, help="产物目录(默认 <root>/docs/images)")
ap.add_argument("--views", default="full,module", help="full / module,逗号分隔")
ap.add_argument("--edge-scope", choices=("project", "all"), default="project",
help="project=仅第一方发起的引用边(默认);all=含第三方内部引用边")
ap.add_argument("--no-render", action="store_true", help="不调用 Graphviz 渲染")
ap.add_argument("--quiet", action="store_true", help="精简输出")
args = ap.parse_args()
root = os.path.abspath(args.root)
outdir = os.path.abspath(args.outdir or os.path.join(root, "docs", "images"))
os.makedirs(outdir, exist_ok=True)
views = [v.strip() for v in args.views.split(",") if v.strip()]
g, stats = build(root)
title = ("STM32F4-Base 项目文件引用关系图(项目代码视图)"
if args.edge_scope == "project"
else "STM32F4-Base 项目文件引用关系图(全量视图)")
written: list[str] = []
if "full" in views:
dot_full = g.emit_dot_full(title, args.edge_scope)
pf = os.path.join(outdir, "引用关系图.dot")
with open(pf, "w", encoding="utf-8", newline="\n") as f:
f.write(dot_full)
written.append(pf)
if "module" in views:
dm = g.emit_dot_module("STM32F4-Base 模块引用概览")
pm = os.path.join(outdir, "引用关系图_模块.dot")
with open(pm, "w", encoding="utf-8", newline="\n") as f:
f.write(dm)
written.append(pm)
# JSON 数据
pj = os.path.join(outdir, "引用关系图.json")
payload = {
"title": title,
"nodes": sorted(g.nodes.values(), key=lambda x: x["path"]),
"edges": g.edge_list,
"unresolved": stats["unresolved_by_file"],
"stats": {k: v for k, v in stats.items()
if k not in ("unresolved_by_file", "ext_names_sorted", "include_dirs")},
"include_dirs": stats["include_dirs"],
}
with open(pj, "w", encoding="utf-8", newline="\n") as f:
json.dump(payload, f, ensure_ascii=False, indent=1)
written.append(pj)
# 渲染
if not args.no_render:
dot = find_dot()
if dot is None:
print("[refgraph] 未找到 Graphviz(dot),跳过渲染;.dot 已生成,"
"安装 Graphviz 后重跑即可出图。", file=sys.stderr)
else:
if "full" in views:
render(dot, written[0] if written and written[0].endswith(".dot") else
os.path.join(outdir, "引用关系图.dot"),
{"svg": os.path.join(outdir, "引用关系图.svg"),
"png": os.path.join(outdir, "引用关系图.png")})
if "module" in views:
pm = os.path.join(outdir, "引用关系图_模块.dot")
render(dot, pm, {"svg": os.path.join(outdir, "引用关系图_模块.svg")})
# 报告
n_edges = len(g.edges)
k = lambda s: print(s) if not args.quiet else None
k("=" * 62)
k("STM32F4-Base 文件引用关系图 生成报告")
k(f" 生成时间 : {_dt.datetime.now():%Y-%m-%d %H:%M:%S}")
k(f" 索引文件 : {stats['files_indexed']} 个 .c/.h")
k(f" 解析 include : {stats['includes_parsed']} 条(解析成功 {stats['resolved']},"
f"外部/系统 {stats['unresolved']})")
k(f" 节点 : 第一方 {stats['nodes_fp']} + 第三方 {stats['nodes_tp']}"
+ (f" + 外部聚合 1" if EXT_NODE in g.nodes else ""))
k(f" 边(去重) : {n_edges} 条(含边明细 {len(g.edge_list)} 条)")
k(f" 外部头文件 : {stats['ext_names']} 种,如 "
+ ", ".join(stats["ext_names_sorted"][:8]))
k("-" * 62)
k(" 产物:")
for w in written:
k(f" {os.path.relpath(w, root)}")
if not args.no_render:
for name in ("引用关系图.svg", "引用关系图.png", "引用关系图_模块.svg"):
p = os.path.join(outdir, name)
if os.path.isfile(p):
k(f" {os.path.relpath(p, root)} ({os.path.getsize(p)//1024} KB)")
k("=" * 62)
# 被引用最多的第一方文件 Top10(概览用)
ref_cnt: dict[str, int] = {}
for (s, d) in g.edges:
if g.nodes.get(d, {}).get("class") == "fp":
ref_cnt[d] = ref_cnt.get(d, 0) + 1
top = sorted(ref_cnt.items(), key=lambda x: -x[1])[:10]
if top and not args.quiet:
k(" 被引用最多的第一方文件(Top10):")
for rel, c in top:
k(f" {c:4d} {rel}")
k("=" * 62)
return 0
if __name__ == "__main__":
raise SystemExit(main())