测试流程除了gpio都可以执行下去。
authorSnickerSun <snickersun@163.com>
Fri, 28 Nov 2025 16:22:40 +0000 (00:22 +0800)
committerSnickerSun <snickersun@163.com>
Fri, 28 Nov 2025 16:22:40 +0000 (00:22 +0800)
17 files changed:
HiBTMacWriteTool.pro
build/CMakeFiles/3.30.2/CMakeRCCompiler.cmake [new file with mode: 0644]
build/CMakeFiles/3.30.2/CMakeSystem.cmake [new file with mode: 0644]
build/CMakeFiles/3.30.2/CompilerIdCXX/CMakeCXXCompilerId.cpp [new file with mode: 0644]
build/CMakeFiles/3.30.2/CompilerIdCXX/a.out [new file with mode: 0644]
build/CMakeFiles/CMakeConfigureLog.yaml [new file with mode: 0644]
build/CMakeFiles/cmake.check_cache [new file with mode: 0644]
json_settings.cpp [new file with mode: 0644]
json_settings.h [new file with mode: 0644]
mainwindow.cpp
mainwindow.h
mainwindow.ui
settings.h
settings.json [new file with mode: 0644]
test_port_controller.cpp
test_port_controller.h
测试流程指令顺序分析.md [new file with mode: 0644]

index 8b97794..d209f58 100644 (file)
@@ -21,7 +21,8 @@ SOURCES += main.cpp\
     sqldbmanager.cpp \
     settings.cpp \
     dialogsettings.cpp \
-    test_port_controller.cpp
+    test_port_controller.cpp \
+    json_settings.cpp
 
 HEADERS  += mainwindow.h \
     mythread.h \
@@ -32,7 +33,8 @@ HEADERS  += mainwindow.h \
     sqldbmanager.h \
     settings.h \
     dialogsettings.h \
-    test_port_controller.h
+    test_port_controller.h \
+    json_settings.h
 
 #HEADERS  +=  ui_mac_settings.h \
 #    ui_mainwindow.h
diff --git a/build/CMakeFiles/3.30.2/CMakeRCCompiler.cmake b/build/CMakeFiles/3.30.2/CMakeRCCompiler.cmake
new file mode 100644 (file)
index 0000000..f7f4557
--- /dev/null
@@ -0,0 +1,6 @@
+set(CMAKE_RC_COMPILER "D:/mingw64/bin/windres.exe")\r
+set(CMAKE_RC_COMPILER_ARG1 "")\r
+set(CMAKE_RC_COMPILER_LOADED 1)\r
+set(CMAKE_RC_SOURCE_FILE_EXTENSIONS rc;RC)\r
+set(CMAKE_RC_OUTPUT_EXTENSION .obj)\r
+set(CMAKE_RC_COMPILER_ENV_VAR "RC")\r
diff --git a/build/CMakeFiles/3.30.2/CMakeSystem.cmake b/build/CMakeFiles/3.30.2/CMakeSystem.cmake
new file mode 100644 (file)
index 0000000..306e632
--- /dev/null
@@ -0,0 +1,15 @@
+set(CMAKE_HOST_SYSTEM "Windows-10.0.22631")\r
+set(CMAKE_HOST_SYSTEM_NAME "Windows")\r
+set(CMAKE_HOST_SYSTEM_VERSION "10.0.22631")\r
+set(CMAKE_HOST_SYSTEM_PROCESSOR "AMD64")\r
+\r
+\r
+\r
+set(CMAKE_SYSTEM "Windows-10.0.22631")\r
+set(CMAKE_SYSTEM_NAME "Windows")\r
+set(CMAKE_SYSTEM_VERSION "10.0.22631")\r
+set(CMAKE_SYSTEM_PROCESSOR "AMD64")\r
+\r
+set(CMAKE_CROSSCOMPILING "FALSE")\r
+\r
+set(CMAKE_SYSTEM_LOADED 1)\r
diff --git a/build/CMakeFiles/3.30.2/CompilerIdCXX/CMakeCXXCompilerId.cpp b/build/CMakeFiles/3.30.2/CompilerIdCXX/CMakeCXXCompilerId.cpp
new file mode 100644 (file)
index 0000000..bfb90d1
--- /dev/null
@@ -0,0 +1,919 @@
+/* This source file must have a .cpp extension so that all C++ compilers\r
+   recognize the extension without flags.  Borland does not know .cxx for\r
+   example.  */\r
+#ifndef __cplusplus\r
+# error "A C compiler has been selected for C++."\r
+#endif\r
+\r
+#if !defined(__has_include)\r
+/* If the compiler does not have __has_include, pretend the answer is\r
+   always no.  */\r
+#  define __has_include(x) 0\r
+#endif\r
+\r
+\r
+/* Version number components: V=Version, R=Revision, P=Patch\r
+   Version date components:   YYYY=Year, MM=Month,   DD=Day  */\r
+\r
+#if defined(__INTEL_COMPILER) || defined(__ICC)\r
+# define COMPILER_ID "Intel"\r
+# if defined(_MSC_VER)\r
+#  define SIMULATE_ID "MSVC"\r
+# endif\r
+# if defined(__GNUC__)\r
+#  define SIMULATE_ID "GNU"\r
+# endif\r
+  /* __INTEL_COMPILER = VRP prior to 2021, and then VVVV for 2021 and later,\r
+     except that a few beta releases use the old format with V=2021.  */\r
+# if __INTEL_COMPILER < 2021 || __INTEL_COMPILER == 202110 || __INTEL_COMPILER == 202111\r
+#  define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100)\r
+#  define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10)\r
+#  if defined(__INTEL_COMPILER_UPDATE)\r
+#   define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE)\r
+#  else\r
+#   define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER   % 10)\r
+#  endif\r
+# else\r
+#  define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER)\r
+#  define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER_UPDATE)\r
+   /* The third version component from --version is an update index,\r
+      but no macro is provided for it.  */\r
+#  define COMPILER_VERSION_PATCH DEC(0)\r
+# endif\r
+# if defined(__INTEL_COMPILER_BUILD_DATE)\r
+   /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */\r
+#  define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE)\r
+# endif\r
+# if defined(_MSC_VER)\r
+   /* _MSC_VER = VVRR */\r
+#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)\r
+#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)\r
+# endif\r
+# if defined(__GNUC__)\r
+#  define SIMULATE_VERSION_MAJOR DEC(__GNUC__)\r
+# elif defined(__GNUG__)\r
+#  define SIMULATE_VERSION_MAJOR DEC(__GNUG__)\r
+# endif\r
+# if defined(__GNUC_MINOR__)\r
+#  define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)\r
+# endif\r
+# if defined(__GNUC_PATCHLEVEL__)\r
+#  define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)\r
+# endif\r
+\r
+#elif (defined(__clang__) && defined(__INTEL_CLANG_COMPILER)) || defined(__INTEL_LLVM_COMPILER)\r
+# define COMPILER_ID "IntelLLVM"\r
+#if defined(_MSC_VER)\r
+# define SIMULATE_ID "MSVC"\r
+#endif\r
+#if defined(__GNUC__)\r
+# define SIMULATE_ID "GNU"\r
+#endif\r
+/* __INTEL_LLVM_COMPILER = VVVVRP prior to 2021.2.0, VVVVRRPP for 2021.2.0 and\r
+ * later.  Look for 6 digit vs. 8 digit version number to decide encoding.\r
+ * VVVV is no smaller than the current year when a version is released.\r
+ */\r
+#if __INTEL_LLVM_COMPILER < 1000000L\r
+# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/100)\r
+# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/10 % 10)\r
+# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER    % 10)\r
+#else\r
+# define COMPILER_VERSION_MAJOR DEC(__INTEL_LLVM_COMPILER/10000)\r
+# define COMPILER_VERSION_MINOR DEC(__INTEL_LLVM_COMPILER/100 % 100)\r
+# define COMPILER_VERSION_PATCH DEC(__INTEL_LLVM_COMPILER     % 100)\r
+#endif\r
+#if defined(_MSC_VER)\r
+  /* _MSC_VER = VVRR */\r
+# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)\r
+# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)\r
+#endif\r
+#if defined(__GNUC__)\r
+# define SIMULATE_VERSION_MAJOR DEC(__GNUC__)\r
+#elif defined(__GNUG__)\r
+# define SIMULATE_VERSION_MAJOR DEC(__GNUG__)\r
+#endif\r
+#if defined(__GNUC_MINOR__)\r
+# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)\r
+#endif\r
+#if defined(__GNUC_PATCHLEVEL__)\r
+# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)\r
+#endif\r
+\r
+#elif defined(__PATHCC__)\r
+# define COMPILER_ID "PathScale"\r
+# define COMPILER_VERSION_MAJOR DEC(__PATHCC__)\r
+# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__)\r
+# if defined(__PATHCC_PATCHLEVEL__)\r
+#  define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__)\r
+# endif\r
+\r
+#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__)\r
+# define COMPILER_ID "Embarcadero"\r
+# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF)\r
+# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF)\r
+# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__     & 0xFFFF)\r
+\r
+#elif defined(__BORLANDC__)\r
+# define COMPILER_ID "Borland"\r
+  /* __BORLANDC__ = 0xVRR */\r
+# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8)\r
+# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF)\r
+\r
+#elif defined(__WATCOMC__) && __WATCOMC__ < 1200\r
+# define COMPILER_ID "Watcom"\r
+   /* __WATCOMC__ = VVRR */\r
+# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100)\r
+# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)\r
+# if (__WATCOMC__ % 10) > 0\r
+#  define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)\r
+# endif\r
+\r
+#elif defined(__WATCOMC__)\r
+# define COMPILER_ID "OpenWatcom"\r
+   /* __WATCOMC__ = VVRP + 1100 */\r
+# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100)\r
+# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10)\r
+# if (__WATCOMC__ % 10) > 0\r
+#  define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10)\r
+# endif\r
+\r
+#elif defined(__SUNPRO_CC)\r
+# define COMPILER_ID "SunPro"\r
+# if __SUNPRO_CC >= 0x5100\r
+   /* __SUNPRO_CC = 0xVRRP */\r
+#  define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12)\r
+#  define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF)\r
+#  define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC    & 0xF)\r
+# else\r
+   /* __SUNPRO_CC = 0xVRP */\r
+#  define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8)\r
+#  define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF)\r
+#  define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC    & 0xF)\r
+# endif\r
+\r
+#elif defined(__HP_aCC)\r
+# define COMPILER_ID "HP"\r
+  /* __HP_aCC = VVRRPP */\r
+# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000)\r
+# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100)\r
+# define COMPILER_VERSION_PATCH DEC(__HP_aCC     % 100)\r
+\r
+#elif defined(__DECCXX)\r
+# define COMPILER_ID "Compaq"\r
+  /* __DECCXX_VER = VVRRTPPPP */\r
+# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000)\r
+# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000  % 100)\r
+# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER         % 10000)\r
+\r
+#elif defined(__IBMCPP__) && defined(__COMPILER_VER__)\r
+# define COMPILER_ID "zOS"\r
+  /* __IBMCPP__ = VRP */\r
+# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)\r
+# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)\r
+# define COMPILER_VERSION_PATCH DEC(__IBMCPP__    % 10)\r
+\r
+#elif defined(__open_xl__) && defined(__clang__)\r
+# define COMPILER_ID "IBMClang"\r
+# define COMPILER_VERSION_MAJOR DEC(__open_xl_version__)\r
+# define COMPILER_VERSION_MINOR DEC(__open_xl_release__)\r
+# define COMPILER_VERSION_PATCH DEC(__open_xl_modification__)\r
+# define COMPILER_VERSION_TWEAK DEC(__open_xl_ptf_fix_level__)\r
+\r
+\r
+#elif defined(__ibmxl__) && defined(__clang__)\r
+# define COMPILER_ID "XLClang"\r
+# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__)\r
+# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__)\r
+# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__)\r
+# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__)\r
+\r
+\r
+#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800\r
+# define COMPILER_ID "XL"\r
+  /* __IBMCPP__ = VRP */\r
+# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)\r
+# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)\r
+# define COMPILER_VERSION_PATCH DEC(__IBMCPP__    % 10)\r
+\r
+#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800\r
+# define COMPILER_ID "VisualAge"\r
+  /* __IBMCPP__ = VRP */\r
+# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100)\r
+# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10)\r
+# define COMPILER_VERSION_PATCH DEC(__IBMCPP__    % 10)\r
+\r
+#elif defined(__NVCOMPILER)\r
+# define COMPILER_ID "NVHPC"\r
+# define COMPILER_VERSION_MAJOR DEC(__NVCOMPILER_MAJOR__)\r
+# define COMPILER_VERSION_MINOR DEC(__NVCOMPILER_MINOR__)\r
+# if defined(__NVCOMPILER_PATCHLEVEL__)\r
+#  define COMPILER_VERSION_PATCH DEC(__NVCOMPILER_PATCHLEVEL__)\r
+# endif\r
+\r
+#elif defined(__PGI)\r
+# define COMPILER_ID "PGI"\r
+# define COMPILER_VERSION_MAJOR DEC(__PGIC__)\r
+# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__)\r
+# if defined(__PGIC_PATCHLEVEL__)\r
+#  define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__)\r
+# endif\r
+\r
+#elif defined(__clang__) && defined(__cray__)\r
+# define COMPILER_ID "CrayClang"\r
+# define COMPILER_VERSION_MAJOR DEC(__cray_major__)\r
+# define COMPILER_VERSION_MINOR DEC(__cray_minor__)\r
+# define COMPILER_VERSION_PATCH DEC(__cray_patchlevel__)\r
+# define COMPILER_VERSION_INTERNAL_STR __clang_version__\r
+\r
+\r
+#elif defined(_CRAYC)\r
+# define COMPILER_ID "Cray"\r
+# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR)\r
+# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR)\r
+\r
+#elif defined(__TI_COMPILER_VERSION__)\r
+# define COMPILER_ID "TI"\r
+  /* __TI_COMPILER_VERSION__ = VVVRRRPPP */\r
+# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000)\r
+# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000   % 1000)\r
+# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__        % 1000)\r
+\r
+#elif defined(__CLANG_FUJITSU)\r
+# define COMPILER_ID "FujitsuClang"\r
+# define COMPILER_VERSION_MAJOR DEC(__FCC_major__)\r
+# define COMPILER_VERSION_MINOR DEC(__FCC_minor__)\r
+# define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)\r
+# define COMPILER_VERSION_INTERNAL_STR __clang_version__\r
+\r
+\r
+#elif defined(__FUJITSU)\r
+# define COMPILER_ID "Fujitsu"\r
+# if defined(__FCC_version__)\r
+#   define COMPILER_VERSION __FCC_version__\r
+# elif defined(__FCC_major__)\r
+#   define COMPILER_VERSION_MAJOR DEC(__FCC_major__)\r
+#   define COMPILER_VERSION_MINOR DEC(__FCC_minor__)\r
+#   define COMPILER_VERSION_PATCH DEC(__FCC_patchlevel__)\r
+# endif\r
+# if defined(__fcc_version)\r
+#   define COMPILER_VERSION_INTERNAL DEC(__fcc_version)\r
+# elif defined(__FCC_VERSION)\r
+#   define COMPILER_VERSION_INTERNAL DEC(__FCC_VERSION)\r
+# endif\r
+\r
+\r
+#elif defined(__ghs__)\r
+# define COMPILER_ID "GHS"\r
+/* __GHS_VERSION_NUMBER = VVVVRP */\r
+# ifdef __GHS_VERSION_NUMBER\r
+# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100)\r
+# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10)\r
+# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER      % 10)\r
+# endif\r
+\r
+#elif defined(__TASKING__)\r
+# define COMPILER_ID "Tasking"\r
+  # define COMPILER_VERSION_MAJOR DEC(__VERSION__/1000)\r
+  # define COMPILER_VERSION_MINOR DEC(__VERSION__ % 100)\r
+# define COMPILER_VERSION_INTERNAL DEC(__VERSION__)\r
+\r
+#elif defined(__ORANGEC__)\r
+# define COMPILER_ID "OrangeC"\r
+# define COMPILER_VERSION_MAJOR DEC(__ORANGEC_MAJOR__)\r
+# define COMPILER_VERSION_MINOR DEC(__ORANGEC_MINOR__)\r
+# define COMPILER_VERSION_PATCH DEC(__ORANGEC_PATCHLEVEL__)\r
+\r
+#elif defined(__SCO_VERSION__)\r
+# define COMPILER_ID "SCO"\r
+\r
+#elif defined(__ARMCC_VERSION) && !defined(__clang__)\r
+# define COMPILER_ID "ARMCC"\r
+#if __ARMCC_VERSION >= 1000000\r
+  /* __ARMCC_VERSION = VRRPPPP */\r
+  # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000)\r
+  # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100)\r
+  # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION     % 10000)\r
+#else\r
+  /* __ARMCC_VERSION = VRPPPP */\r
+  # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000)\r
+  # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10)\r
+  # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION    % 10000)\r
+#endif\r
+\r
+\r
+#elif defined(__clang__) && defined(__apple_build_version__)\r
+# define COMPILER_ID "AppleClang"\r
+# if defined(_MSC_VER)\r
+#  define SIMULATE_ID "MSVC"\r
+# endif\r
+# define COMPILER_VERSION_MAJOR DEC(__clang_major__)\r
+# define COMPILER_VERSION_MINOR DEC(__clang_minor__)\r
+# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)\r
+# if defined(_MSC_VER)\r
+   /* _MSC_VER = VVRR */\r
+#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)\r
+#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)\r
+# endif\r
+# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__)\r
+\r
+#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION)\r
+# define COMPILER_ID "ARMClang"\r
+  # define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000)\r
+  # define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100)\r
+  # define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION/100   % 100)\r
+# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION)\r
+\r
+#elif defined(__clang__) && defined(__ti__)\r
+# define COMPILER_ID "TIClang"\r
+  # define COMPILER_VERSION_MAJOR DEC(__ti_major__)\r
+  # define COMPILER_VERSION_MINOR DEC(__ti_minor__)\r
+  # define COMPILER_VERSION_PATCH DEC(__ti_patchlevel__)\r
+# define COMPILER_VERSION_INTERNAL DEC(__ti_version__)\r
+\r
+#elif defined(__clang__)\r
+# define COMPILER_ID "Clang"\r
+# if defined(_MSC_VER)\r
+#  define SIMULATE_ID "MSVC"\r
+# endif\r
+# define COMPILER_VERSION_MAJOR DEC(__clang_major__)\r
+# define COMPILER_VERSION_MINOR DEC(__clang_minor__)\r
+# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__)\r
+# if defined(_MSC_VER)\r
+   /* _MSC_VER = VVRR */\r
+#  define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100)\r
+#  define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100)\r
+# endif\r
+\r
+#elif defined(__LCC__) && (defined(__GNUC__) || defined(__GNUG__) || defined(__MCST__))\r
+# define COMPILER_ID "LCC"\r
+# define COMPILER_VERSION_MAJOR DEC(__LCC__ / 100)\r
+# define COMPILER_VERSION_MINOR DEC(__LCC__ % 100)\r
+# if defined(__LCC_MINOR__)\r
+#  define COMPILER_VERSION_PATCH DEC(__LCC_MINOR__)\r
+# endif\r
+# if defined(__GNUC__) && defined(__GNUC_MINOR__)\r
+#  define SIMULATE_ID "GNU"\r
+#  define SIMULATE_VERSION_MAJOR DEC(__GNUC__)\r
+#  define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__)\r
+#  if defined(__GNUC_PATCHLEVEL__)\r
+#   define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)\r
+#  endif\r
+# endif\r
+\r
+#elif defined(__GNUC__) || defined(__GNUG__)\r
+# define COMPILER_ID "GNU"\r
+# if defined(__GNUC__)\r
+#  define COMPILER_VERSION_MAJOR DEC(__GNUC__)\r
+# else\r
+#  define COMPILER_VERSION_MAJOR DEC(__GNUG__)\r
+# endif\r
+# if defined(__GNUC_MINOR__)\r
+#  define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__)\r
+# endif\r
+# if defined(__GNUC_PATCHLEVEL__)\r
+#  define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__)\r
+# endif\r
+\r
+#elif defined(_MSC_VER)\r
+# define COMPILER_ID "MSVC"\r
+  /* _MSC_VER = VVRR */\r
+# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100)\r
+# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100)\r
+# if defined(_MSC_FULL_VER)\r
+#  if _MSC_VER >= 1400\r
+    /* _MSC_FULL_VER = VVRRPPPPP */\r
+#   define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000)\r
+#  else\r
+    /* _MSC_FULL_VER = VVRRPPPP */\r
+#   define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000)\r
+#  endif\r
+# endif\r
+# if defined(_MSC_BUILD)\r
+#  define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD)\r
+# endif\r
+\r
+#elif defined(_ADI_COMPILER)\r
+# define COMPILER_ID "ADSP"\r
+#if defined(__VERSIONNUM__)\r
+  /* __VERSIONNUM__ = 0xVVRRPPTT */\r
+#  define COMPILER_VERSION_MAJOR DEC(__VERSIONNUM__ >> 24 & 0xFF)\r
+#  define COMPILER_VERSION_MINOR DEC(__VERSIONNUM__ >> 16 & 0xFF)\r
+#  define COMPILER_VERSION_PATCH DEC(__VERSIONNUM__ >> 8 & 0xFF)\r
+#  define COMPILER_VERSION_TWEAK DEC(__VERSIONNUM__ & 0xFF)\r
+#endif\r
+\r
+#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)\r
+# define COMPILER_ID "IAR"\r
+# if defined(__VER__) && defined(__ICCARM__)\r
+#  define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000)\r
+#  define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000)\r
+#  define COMPILER_VERSION_PATCH DEC((__VER__) % 1000)\r
+#  define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)\r
+# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__) || defined(__ICCSTM8__))\r
+#  define COMPILER_VERSION_MAJOR DEC((__VER__) / 100)\r
+#  define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100))\r
+#  define COMPILER_VERSION_PATCH DEC(__SUBVERSION__)\r
+#  define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__)\r
+# endif\r
+\r
+\r
+/* These compilers are either not known or too old to define an\r
+  identification macro.  Try to identify the platform and guess that\r
+  it is the native compiler.  */\r
+#elif defined(__hpux) || defined(__hpua)\r
+# define COMPILER_ID "HP"\r
+\r
+#else /* unknown compiler */\r
+# define COMPILER_ID ""\r
+#endif\r
+\r
+/* Construct the string literal in pieces to prevent the source from\r
+   getting matched.  Store it in a pointer rather than an array\r
+   because some compilers will just produce instructions to fill the\r
+   array rather than assigning a pointer to a static array.  */\r
+char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]";\r
+#ifdef SIMULATE_ID\r
+char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]";\r
+#endif\r
+\r
+#ifdef __QNXNTO__\r
+char const* qnxnto = "INFO" ":" "qnxnto[]";\r
+#endif\r
+\r
+#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)\r
+char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]";\r
+#endif\r
+\r
+#define STRINGIFY_HELPER(X) #X\r
+#define STRINGIFY(X) STRINGIFY_HELPER(X)\r
+\r
+/* Identify known platforms by name.  */\r
+#if defined(__linux) || defined(__linux__) || defined(linux)\r
+# define PLATFORM_ID "Linux"\r
+\r
+#elif defined(__MSYS__)\r
+# define PLATFORM_ID "MSYS"\r
+\r
+#elif defined(__CYGWIN__)\r
+# define PLATFORM_ID "Cygwin"\r
+\r
+#elif defined(__MINGW32__)\r
+# define PLATFORM_ID "MinGW"\r
+\r
+#elif defined(__APPLE__)\r
+# define PLATFORM_ID "Darwin"\r
+\r
+#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)\r
+# define PLATFORM_ID "Windows"\r
+\r
+#elif defined(__FreeBSD__) || defined(__FreeBSD)\r
+# define PLATFORM_ID "FreeBSD"\r
+\r
+#elif defined(__NetBSD__) || defined(__NetBSD)\r
+# define PLATFORM_ID "NetBSD"\r
+\r
+#elif defined(__OpenBSD__) || defined(__OPENBSD)\r
+# define PLATFORM_ID "OpenBSD"\r
+\r
+#elif defined(__sun) || defined(sun)\r
+# define PLATFORM_ID "SunOS"\r
+\r
+#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__)\r
+# define PLATFORM_ID "AIX"\r
+\r
+#elif defined(__hpux) || defined(__hpux__)\r
+# define PLATFORM_ID "HP-UX"\r
+\r
+#elif defined(__HAIKU__)\r
+# define PLATFORM_ID "Haiku"\r
+\r
+#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS)\r
+# define PLATFORM_ID "BeOS"\r
+\r
+#elif defined(__QNX__) || defined(__QNXNTO__)\r
+# define PLATFORM_ID "QNX"\r
+\r
+#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__)\r
+# define PLATFORM_ID "Tru64"\r
+\r
+#elif defined(__riscos) || defined(__riscos__)\r
+# define PLATFORM_ID "RISCos"\r
+\r
+#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__)\r
+# define PLATFORM_ID "SINIX"\r
+\r
+#elif defined(__UNIX_SV__)\r
+# define PLATFORM_ID "UNIX_SV"\r
+\r
+#elif defined(__bsdos__)\r
+# define PLATFORM_ID "BSDOS"\r
+\r
+#elif defined(_MPRAS) || defined(MPRAS)\r
+# define PLATFORM_ID "MP-RAS"\r
+\r
+#elif defined(__osf) || defined(__osf__)\r
+# define PLATFORM_ID "OSF1"\r
+\r
+#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)\r
+# define PLATFORM_ID "SCO_SV"\r
+\r
+#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX)\r
+# define PLATFORM_ID "ULTRIX"\r
+\r
+#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX)\r
+# define PLATFORM_ID "Xenix"\r
+\r
+#elif defined(__WATCOMC__)\r
+# if defined(__LINUX__)\r
+#  define PLATFORM_ID "Linux"\r
+\r
+# elif defined(__DOS__)\r
+#  define PLATFORM_ID "DOS"\r
+\r
+# elif defined(__OS2__)\r
+#  define PLATFORM_ID "OS2"\r
+\r
+# elif defined(__WINDOWS__)\r
+#  define PLATFORM_ID "Windows3x"\r
+\r
+# elif defined(__VXWORKS__)\r
+#  define PLATFORM_ID "VxWorks"\r
+\r
+# else /* unknown platform */\r
+#  define PLATFORM_ID\r
+# endif\r
+\r
+#elif defined(__INTEGRITY)\r
+# if defined(INT_178B)\r
+#  define PLATFORM_ID "Integrity178"\r
+\r
+# else /* regular Integrity */\r
+#  define PLATFORM_ID "Integrity"\r
+# endif\r
+\r
+# elif defined(_ADI_COMPILER)\r
+#  define PLATFORM_ID "ADSP"\r
+\r
+#else /* unknown platform */\r
+# define PLATFORM_ID\r
+\r
+#endif\r
+\r
+/* For windows compilers MSVC and Intel we can determine\r
+   the architecture of the compiler being used.  This is because\r
+   the compilers do not have flags that can change the architecture,\r
+   but rather depend on which compiler is being used\r
+*/\r
+#if defined(_WIN32) && defined(_MSC_VER)\r
+# if defined(_M_IA64)\r
+#  define ARCHITECTURE_ID "IA64"\r
+\r
+# elif defined(_M_ARM64EC)\r
+#  define ARCHITECTURE_ID "ARM64EC"\r
+\r
+# elif defined(_M_X64) || defined(_M_AMD64)\r
+#  define ARCHITECTURE_ID "x64"\r
+\r
+# elif defined(_M_IX86)\r
+#  define ARCHITECTURE_ID "X86"\r
+\r
+# elif defined(_M_ARM64)\r
+#  define ARCHITECTURE_ID "ARM64"\r
+\r
+# elif defined(_M_ARM)\r
+#  if _M_ARM == 4\r
+#   define ARCHITECTURE_ID "ARMV4I"\r
+#  elif _M_ARM == 5\r
+#   define ARCHITECTURE_ID "ARMV5I"\r
+#  else\r
+#   define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM)\r
+#  endif\r
+\r
+# elif defined(_M_MIPS)\r
+#  define ARCHITECTURE_ID "MIPS"\r
+\r
+# elif defined(_M_SH)\r
+#  define ARCHITECTURE_ID "SHx"\r
+\r
+# else /* unknown architecture */\r
+#  define ARCHITECTURE_ID ""\r
+# endif\r
+\r
+#elif defined(__WATCOMC__)\r
+# if defined(_M_I86)\r
+#  define ARCHITECTURE_ID "I86"\r
+\r
+# elif defined(_M_IX86)\r
+#  define ARCHITECTURE_ID "X86"\r
+\r
+# else /* unknown architecture */\r
+#  define ARCHITECTURE_ID ""\r
+# endif\r
+\r
+#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC)\r
+# if defined(__ICCARM__)\r
+#  define ARCHITECTURE_ID "ARM"\r
+\r
+# elif defined(__ICCRX__)\r
+#  define ARCHITECTURE_ID "RX"\r
+\r
+# elif defined(__ICCRH850__)\r
+#  define ARCHITECTURE_ID "RH850"\r
+\r
+# elif defined(__ICCRL78__)\r
+#  define ARCHITECTURE_ID "RL78"\r
+\r
+# elif defined(__ICCRISCV__)\r
+#  define ARCHITECTURE_ID "RISCV"\r
+\r
+# elif defined(__ICCAVR__)\r
+#  define ARCHITECTURE_ID "AVR"\r
+\r
+# elif defined(__ICC430__)\r
+#  define ARCHITECTURE_ID "MSP430"\r
+\r
+# elif defined(__ICCV850__)\r
+#  define ARCHITECTURE_ID "V850"\r
+\r
+# elif defined(__ICC8051__)\r
+#  define ARCHITECTURE_ID "8051"\r
+\r
+# elif defined(__ICCSTM8__)\r
+#  define ARCHITECTURE_ID "STM8"\r
+\r
+# else /* unknown architecture */\r
+#  define ARCHITECTURE_ID ""\r
+# endif\r
+\r
+#elif defined(__ghs__)\r
+# if defined(__PPC64__)\r
+#  define ARCHITECTURE_ID "PPC64"\r
+\r
+# elif defined(__ppc__)\r
+#  define ARCHITECTURE_ID "PPC"\r
+\r
+# elif defined(__ARM__)\r
+#  define ARCHITECTURE_ID "ARM"\r
+\r
+# elif defined(__x86_64__)\r
+#  define ARCHITECTURE_ID "x64"\r
+\r
+# elif defined(__i386__)\r
+#  define ARCHITECTURE_ID "X86"\r
+\r
+# else /* unknown architecture */\r
+#  define ARCHITECTURE_ID ""\r
+# endif\r
+\r
+#elif defined(__clang__) && defined(__ti__)\r
+# if defined(__ARM_ARCH)\r
+#  define ARCHITECTURE_ID "Arm"\r
+\r
+# else /* unknown architecture */\r
+#  define ARCHITECTURE_ID ""\r
+# endif\r
+\r
+#elif defined(__TI_COMPILER_VERSION__)\r
+# if defined(__TI_ARM__)\r
+#  define ARCHITECTURE_ID "ARM"\r
+\r
+# elif defined(__MSP430__)\r
+#  define ARCHITECTURE_ID "MSP430"\r
+\r
+# elif defined(__TMS320C28XX__)\r
+#  define ARCHITECTURE_ID "TMS320C28x"\r
+\r
+# elif defined(__TMS320C6X__) || defined(_TMS320C6X)\r
+#  define ARCHITECTURE_ID "TMS320C6x"\r
+\r
+# else /* unknown architecture */\r
+#  define ARCHITECTURE_ID ""\r
+# endif\r
+\r
+# elif defined(__ADSPSHARC__)\r
+#  define ARCHITECTURE_ID "SHARC"\r
+\r
+# elif defined(__ADSPBLACKFIN__)\r
+#  define ARCHITECTURE_ID "Blackfin"\r
+\r
+#elif defined(__TASKING__)\r
+\r
+# if defined(__CTC__) || defined(__CPTC__)\r
+#  define ARCHITECTURE_ID "TriCore"\r
+\r
+# elif defined(__CMCS__)\r
+#  define ARCHITECTURE_ID "MCS"\r
+\r
+# elif defined(__CARM__)\r
+#  define ARCHITECTURE_ID "ARM"\r
+\r
+# elif defined(__CARC__)\r
+#  define ARCHITECTURE_ID "ARC"\r
+\r
+# elif defined(__C51__)\r
+#  define ARCHITECTURE_ID "8051"\r
+\r
+# elif defined(__CPCP__)\r
+#  define ARCHITECTURE_ID "PCP"\r
+\r
+# else\r
+#  define ARCHITECTURE_ID ""\r
+# endif\r
+\r
+#else\r
+#  define ARCHITECTURE_ID\r
+#endif\r
+\r
+/* Convert integer to decimal digit literals.  */\r
+#define DEC(n)                   \\r
+  ('0' + (((n) / 10000000)%10)), \\r
+  ('0' + (((n) / 1000000)%10)),  \\r
+  ('0' + (((n) / 100000)%10)),   \\r
+  ('0' + (((n) / 10000)%10)),    \\r
+  ('0' + (((n) / 1000)%10)),     \\r
+  ('0' + (((n) / 100)%10)),      \\r
+  ('0' + (((n) / 10)%10)),       \\r
+  ('0' +  ((n) % 10))\r
+\r
+/* Convert integer to hex digit literals.  */\r
+#define HEX(n)             \\r
+  ('0' + ((n)>>28 & 0xF)), \\r
+  ('0' + ((n)>>24 & 0xF)), \\r
+  ('0' + ((n)>>20 & 0xF)), \\r
+  ('0' + ((n)>>16 & 0xF)), \\r
+  ('0' + ((n)>>12 & 0xF)), \\r
+  ('0' + ((n)>>8  & 0xF)), \\r
+  ('0' + ((n)>>4  & 0xF)), \\r
+  ('0' + ((n)     & 0xF))\r
+\r
+/* Construct a string literal encoding the version number. */\r
+#ifdef COMPILER_VERSION\r
+char const* info_version = "INFO" ":" "compiler_version[" COMPILER_VERSION "]";\r
+\r
+/* Construct a string literal encoding the version number components. */\r
+#elif defined(COMPILER_VERSION_MAJOR)\r
+char const info_version[] = {\r
+  'I', 'N', 'F', 'O', ':',\r
+  'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[',\r
+  COMPILER_VERSION_MAJOR,\r
+# ifdef COMPILER_VERSION_MINOR\r
+  '.', COMPILER_VERSION_MINOR,\r
+#  ifdef COMPILER_VERSION_PATCH\r
+   '.', COMPILER_VERSION_PATCH,\r
+#   ifdef COMPILER_VERSION_TWEAK\r
+    '.', COMPILER_VERSION_TWEAK,\r
+#   endif\r
+#  endif\r
+# endif\r
+  ']','\0'};\r
+#endif\r
+\r
+/* Construct a string literal encoding the internal version number. */\r
+#ifdef COMPILER_VERSION_INTERNAL\r
+char const info_version_internal[] = {\r
+  'I', 'N', 'F', 'O', ':',\r
+  'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_',\r
+  'i','n','t','e','r','n','a','l','[',\r
+  COMPILER_VERSION_INTERNAL,']','\0'};\r
+#elif defined(COMPILER_VERSION_INTERNAL_STR)\r
+char const* info_version_internal = "INFO" ":" "compiler_version_internal[" COMPILER_VERSION_INTERNAL_STR "]";\r
+#endif\r
+\r
+/* Construct a string literal encoding the version number components. */\r
+#ifdef SIMULATE_VERSION_MAJOR\r
+char const info_simulate_version[] = {\r
+  'I', 'N', 'F', 'O', ':',\r
+  's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[',\r
+  SIMULATE_VERSION_MAJOR,\r
+# ifdef SIMULATE_VERSION_MINOR\r
+  '.', SIMULATE_VERSION_MINOR,\r
+#  ifdef SIMULATE_VERSION_PATCH\r
+   '.', SIMULATE_VERSION_PATCH,\r
+#   ifdef SIMULATE_VERSION_TWEAK\r
+    '.', SIMULATE_VERSION_TWEAK,\r
+#   endif\r
+#  endif\r
+# endif\r
+  ']','\0'};\r
+#endif\r
+\r
+/* Construct the string literal in pieces to prevent the source from\r
+   getting matched.  Store it in a pointer rather than an array\r
+   because some compilers will just produce instructions to fill the\r
+   array rather than assigning a pointer to a static array.  */\r
+char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";\r
+char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";\r
+\r
+\r
+\r
+#define CXX_STD_98 199711L\r
+#define CXX_STD_11 201103L\r
+#define CXX_STD_14 201402L\r
+#define CXX_STD_17 201703L\r
+#define CXX_STD_20 202002L\r
+#define CXX_STD_23 202302L\r
+\r
+#if defined(__INTEL_COMPILER) && defined(_MSVC_LANG)\r
+#  if _MSVC_LANG > CXX_STD_17\r
+#    define CXX_STD _MSVC_LANG\r
+#  elif _MSVC_LANG == CXX_STD_17 && defined(__cpp_aggregate_paren_init)\r
+#    define CXX_STD CXX_STD_20\r
+#  elif _MSVC_LANG > CXX_STD_14 && __cplusplus > CXX_STD_17\r
+#    define CXX_STD CXX_STD_20\r
+#  elif _MSVC_LANG > CXX_STD_14\r
+#    define CXX_STD CXX_STD_17\r
+#  elif defined(__INTEL_CXX11_MODE__) && defined(__cpp_aggregate_nsdmi)\r
+#    define CXX_STD CXX_STD_14\r
+#  elif defined(__INTEL_CXX11_MODE__)\r
+#    define CXX_STD CXX_STD_11\r
+#  else\r
+#    define CXX_STD CXX_STD_98\r
+#  endif\r
+#elif defined(_MSC_VER) && defined(_MSVC_LANG)\r
+#  if _MSVC_LANG > __cplusplus\r
+#    define CXX_STD _MSVC_LANG\r
+#  else\r
+#    define CXX_STD __cplusplus\r
+#  endif\r
+#elif defined(__NVCOMPILER)\r
+#  if __cplusplus == CXX_STD_17 && defined(__cpp_aggregate_paren_init)\r
+#    define CXX_STD CXX_STD_20\r
+#  else\r
+#    define CXX_STD __cplusplus\r
+#  endif\r
+#elif defined(__INTEL_COMPILER) || defined(__PGI)\r
+#  if __cplusplus == CXX_STD_11 && defined(__cpp_namespace_attributes)\r
+#    define CXX_STD CXX_STD_17\r
+#  elif __cplusplus == CXX_STD_11 && defined(__cpp_aggregate_nsdmi)\r
+#    define CXX_STD CXX_STD_14\r
+#  else\r
+#    define CXX_STD __cplusplus\r
+#  endif\r
+#elif (defined(__IBMCPP__) || defined(__ibmxl__)) && defined(__linux__)\r
+#  if __cplusplus == CXX_STD_11 && defined(__cpp_aggregate_nsdmi)\r
+#    define CXX_STD CXX_STD_14\r
+#  else\r
+#    define CXX_STD __cplusplus\r
+#  endif\r
+#elif __cplusplus == 1 && defined(__GXX_EXPERIMENTAL_CXX0X__)\r
+#  define CXX_STD CXX_STD_11\r
+#else\r
+#  define CXX_STD __cplusplus\r
+#endif\r
+\r
+const char* info_language_standard_default = "INFO" ":" "standard_default["\r
+#if CXX_STD > CXX_STD_23\r
+  "26"\r
+#elif CXX_STD > CXX_STD_20\r
+  "23"\r
+#elif CXX_STD > CXX_STD_17\r
+  "20"\r
+#elif CXX_STD > CXX_STD_14\r
+  "17"\r
+#elif CXX_STD > CXX_STD_11\r
+  "14"\r
+#elif CXX_STD >= CXX_STD_11\r
+  "11"\r
+#else\r
+  "98"\r
+#endif\r
+"]";\r
+\r
+const char* info_language_extensions_default = "INFO" ":" "extensions_default["\r
+#if (defined(__clang__) || defined(__GNUC__) || defined(__xlC__) ||           \\r
+     defined(__TI_COMPILER_VERSION__)) &&                                     \\r
+  !defined(__STRICT_ANSI__)\r
+  "ON"\r
+#else\r
+  "OFF"\r
+#endif\r
+"]";\r
+\r
+/*--------------------------------------------------------------------------*/\r
+\r
+int main(int argc, char* argv[])\r
+{\r
+  int require = 0;\r
+  require += info_compiler[argc];\r
+  require += info_platform[argc];\r
+  require += info_arch[argc];\r
+#ifdef COMPILER_VERSION_MAJOR\r
+  require += info_version[argc];\r
+#endif\r
+#ifdef COMPILER_VERSION_INTERNAL\r
+  require += info_version_internal[argc];\r
+#endif\r
+#ifdef SIMULATE_ID\r
+  require += info_simulate[argc];\r
+#endif\r
+#ifdef SIMULATE_VERSION_MAJOR\r
+  require += info_simulate_version[argc];\r
+#endif\r
+#if defined(__CRAYXT_COMPUTE_LINUX_TARGET)\r
+  require += info_cray[argc];\r
+#endif\r
+  require += info_language_standard_default[argc];\r
+  require += info_language_extensions_default[argc];\r
+  (void)argv;\r
+  return require;\r
+}\r
diff --git a/build/CMakeFiles/3.30.2/CompilerIdCXX/a.out b/build/CMakeFiles/3.30.2/CompilerIdCXX/a.out
new file mode 100644 (file)
index 0000000..d7c1609
Binary files /dev/null and b/build/CMakeFiles/3.30.2/CompilerIdCXX/a.out differ
diff --git a/build/CMakeFiles/CMakeConfigureLog.yaml b/build/CMakeFiles/CMakeConfigureLog.yaml
new file mode 100644 (file)
index 0000000..0f033ba
--- /dev/null
@@ -0,0 +1,133 @@
+\r
+---\r
+events:\r
+  -\r
+    kind: "message-v1"\r
+    backtrace:\r
+      - "D:/esp32-tools/tools/cmake/3.30.2/share/cmake-3.30/Modules/CMakeDetermineSystem.cmake:205 (message)"\r
+      - "CMakeLists.txt:3 (project)"\r
+    message: |\r
+      The system is: Windows - 10.0.22631 - AMD64\r
+  -\r
+    kind: "message-v1"\r
+    backtrace:\r
+      - "D:/esp32-tools/tools/cmake/3.30.2/share/cmake-3.30/Modules/CMakeDetermineCompilerId.cmake:17 (message)"\r
+      - "D:/esp32-tools/tools/cmake/3.30.2/share/cmake-3.30/Modules/CMakeDetermineCompilerId.cmake:64 (__determine_compiler_id_test)"\r
+      - "D:/esp32-tools/tools/cmake/3.30.2/share/cmake-3.30/Modules/CMakeDetermineCXXCompiler.cmake:126 (CMAKE_DETERMINE_COMPILER_ID)"\r
+      - "CMakeLists.txt:3 (project)"\r
+    message: |\r
+      Compiling the CXX compiler identification source file "CMakeCXXCompilerId.cpp" succeeded.\r
+      Compiler: D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/clang++.exe \r
+      Build flags: \r
+      Id flags:  \r
+      \r
+      The output was:\r
+      0\r
+      \r
+      \r
+      Compilation of the CXX compiler identification source "CMakeCXXCompilerId.cpp" produced "a.out"\r
+      \r
+      The CXX compiler identification is Clang, found in:\r
+        D:/workspace/fd230_source_win/HiBTMacWriteTool/build/CMakeFiles/3.30.2/CompilerIdCXX/a.out\r
+      \r
+  -\r
+    kind: "try_compile-v1"\r
+    backtrace:\r
+      - "D:/esp32-tools/tools/cmake/3.30.2/share/cmake-3.30/Modules/CMakeDetermineCompilerABI.cmake:74 (try_compile)"\r
+      - "D:/esp32-tools/tools/cmake/3.30.2/share/cmake-3.30/Modules/CMakeTestCXXCompiler.cmake:26 (CMAKE_DETERMINE_COMPILER_ABI)"\r
+      - "CMakeLists.txt:3 (project)"\r
+    checks:\r
+      - "Detecting CXX compiler ABI info"\r
+    directories:\r
+      source: "D:/workspace/fd230_source_win/HiBTMacWriteTool/build/CMakeFiles/CMakeScratch/TryCompile-j5rkd9"\r
+      binary: "D:/workspace/fd230_source_win/HiBTMacWriteTool/build/CMakeFiles/CMakeScratch/TryCompile-j5rkd9"\r
+    cmakeVariables:\r
+      CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS: "CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS-NOTFOUND"\r
+      CMAKE_CXX_FLAGS: ""\r
+      CMAKE_CXX_SCAN_FOR_MODULES: "OFF"\r
+      CMAKE_EXE_LINKER_FLAGS: ""\r
+    buildResult:\r
+      variable: "CMAKE_CXX_ABI_COMPILED"\r
+      cached: true\r
+      stdout: |\r
+        Change Dir: 'D:/workspace/fd230_source_win/HiBTMacWriteTool/build/CMakeFiles/CMakeScratch/TryCompile-j5rkd9'\r
+        \r
+        Run Build Command(s): D:/esp32-tools/tools/ninja/1.12.1/ninja.exe -v cmTC_86c92\r
+        [1/2] D:\\esp32-tools\\tools\\esp-clang\\esp-19.1.2_20250312\\esp-clang\\bin\\clang++.exe   -v -MD -MT CMakeFiles/cmTC_86c92.dir/CMakeCXXCompilerABI.cpp.obj -MF CMakeFiles\\cmTC_86c92.dir\\CMakeCXXCompilerABI.cpp.obj.d -o CMakeFiles/cmTC_86c92.dir/CMakeCXXCompilerABI.cpp.obj -c D:/esp32-tools/tools/cmake/3.30.2/share/cmake-3.30/Modules/CMakeCXXCompilerABI.cpp\r
+        clang version 19.1.2 (https://github.com/espressif/llvm-project.git esp-19.1.2_20250312)\r
+        Target: riscv32-esp-unknown-elf\r
+        Thread model: posix\r
+        InstalledDir: D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin\r
+         (in-process)\r
+         "D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/clang++.exe" -cc1 -triple riscv32-esp-unknown-elf -emit-obj -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name CMakeCXXCompilerABI.cpp -mrelocation-model static -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -nostdsysteminc -target-cpu generic-rv32 -target-feature +m -target-feature +a -target-feature +c -target-feature +zmmul -target-feature -b -target-feature -d -target-feature -e -target-feature -f -target-feature -h -target-feature -shcounterenw -target-feature -shgatpa -target-feature -shtvala -target-feature -shvsatpa -target-feature -shvstvala -target-feature -shvstvecd -target-feature -smaia -target-feature -smcdeleg -target-feature -smcsrind -target-feature -smepmp -target-feature -smstateen -target-feature -ssaia -target-feature -ssccfg -target-feature -ssccptr -target-feature -sscofpmf -target-feature -sscounterenw -target-feature -sscsrind -target-feature -ssstateen -target-feature -ssstrict -target-feature -sstc -target-feature -sstvala -target-feature -sstvecd -target-feature -ssu64xl -target-feature -svade -target-feature -svadu -target-feature -svbare -target-feature -svinval -target-feature -svnapot -target-feature -svpbmt -target-feature -v -target-feature -xcvalu -target-feature -xcvbi -target-feature -xcvbitmanip -target-feature -xcvelw -target-feature -xcvmac -target-feature -xcvmem -target-feature -xcvsimd -target-feature -xesppie -target-feature -xsfcease -target-feature -xsfvcp -target-feature -xsfvfnrclipxfqf -target-feature -xsfvfwmaccqqq -target-feature -xsfvqmaccdod -target-feature -xsfvqmaccqoq -target-feature -xsifivecdiscarddlone -target-feature -xsifivecflushdlone -target-feature -xtheadba -target-feature -xtheadbb -target-feature -xtheadbs -target-feature -xtheadcmo -target-feature -xtheadcondmov -target-feature -xtheadfmemidx -target-feature -xtheadmac -target-feature -xtheadmemidx -target-feature -xtheadmempair -target-feature -xtheadsync -target-feature -xtheadvdot -target-feature -xventanacondops -target-feature -xwchc -target-feature -za128rs -target-feature -za64rs -target-feature -zaamo -target-feature -zabha -target-feature -zalrsc -target-feature -zama16b -target-feature -zawrs -target-feature -zba -target-feature -zbb -target-feature -zbc -target-feature -zbkb -target-feature -zbkc -target-feature -zbkx -target-feature -zbs -target-feature -zca -target-feature -zcb -target-feature -zcd -target-feature -zce -target-feature -zcf -target-feature -zcmop -target-feature -zcmp -target-feature -zcmt -target-feature -zdinx -target-feature -zfa -target-feature -zfbfmin -target-feature -zfh -target-feature -zfhmin -target-feature -zfinx -target-feature -zhinx -target-feature -zhinxmin -target-feature -zic64b -target-feature -zicbom -target-feature -zicbop -target-feature -zicboz -target-feature -ziccamoa -target-feature -ziccif -target-feature -zicclsm -target-feature -ziccrse -target-feature -zicntr -target-feature -zicond -target-feature -zicsr -target-feature -zifencei -target-feature -zihintntl -target-feature -zihintpause -target-feature -zihpm -target-feature -zimop -target-feature -zk -target-feature -zkn -target-feature -zknd -target-feature -zkne -target-feature -zknh -target-feature -zkr -target-feature -zks -target-feature -zksed -target-feature -zksh -target-feature -zkt -target-feature -ztso -target-feature -zvbb -target-feature -zvbc -target-feature -zve32f -target-feature -zve32x -target-feature -zve64d -target-feature -zve64f -target-feature -zve64x -target-feature -zvfbfmin -target-feature -zvfbfwma -target-feature -zvfh -target-feature -zvfhmin -target-feature -zvkb -target-feature -zvkg -target-feature -zvkn -target-feature -zvknc -target-feature -zvkned -target-feature -zvkng -target-feature -zvknha -target-feature -zvknhb -target-feature -zvks -target-feature -zvksc -target-feature -zvksed -target-feature -zvksg -target-feature -zvksh -target-feature -zvkt -target-feature -zvl1024b -target-feature -zvl128b -target-feature -zvl16384b -target-feature -zvl2048b -target-feature -zvl256b -target-feature -zvl32768b -target-feature -zvl32b -target-feature -zvl4096b -target-feature -zvl512b -target-feature -zvl64b -target-feature -zvl65536b -target-feature -zvl8192b -target-feature -experimental-smmpm -target-feature -experimental-smnpm -target-feature -experimental-ssnpm -target-feature -experimental-sspm -target-feature -experimental-ssqosid -target-feature -experimental-supm -target-feature -experimental-zacas -target-feature -experimental-zalasr -target-feature -experimental-zicfilp -target-feature -experimental-zicfiss -target-feature +relax -target-abi ilp32 -msmall-data-limit 8 -debugger-tuning=gdb -fdebug-compilation-dir=D:/workspace/fd230_source_win/HiBTMacWriteTool/build/CMakeFiles/CMakeScratch/TryCompile-j5rkd9 -v -fcoverage-compilation-dir=D:/workspace/fd230_source_win/HiBTMacWriteTool/build/CMakeFiles/CMakeScratch/TryCompile-j5rkd9 -resource-dir D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/lib/clang/19 -dependency-file "CMakeFiles\\\\cmTC_86c92.dir\\\\CMakeCXXCompilerABI.cpp.obj.d" -MT CMakeFiles/cmTC_86c92.dir/CMakeCXXCompilerABI.cpp.obj -sys-header-deps -internal-isystem D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/../lib/clang-runtimes/riscv32-esp-unknown-elf/rv32imac-zicsr-zifencei_ilp32/include/c++/14.2.0 -internal-isystem D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/../lib/clang-runtimes/riscv32-esp-unknown-elf/include/c++/14.2.0 -internal-isystem D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/lib/clang/19/include -internal-isystem D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/../lib/clang-runtimes/riscv32-esp-unknown-elf/rv32imac-zicsr-zifencei_ilp32/include -fdeprecated-macro -ferror-limit 19 -fno-signed-char -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o CMakeFiles/cmTC_86c92.dir/CMakeCXXCompilerABI.cpp.obj -x c++ D:/esp32-tools/tools/cmake/3.30.2/share/cmake-3.30/Modules/CMakeCXXCompilerABI.cpp\r
+        clang -cc1 version 19.1.2 based upon LLVM 19.1.2 default target riscv32-esp-elf\r
+        ignoring duplicate directory "D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/lib/clang/19/include"\r
+        #include "..." search starts here:\r
+        #include <...> search starts here:\r
+         D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/../lib/clang-runtimes/riscv32-esp-unknown-elf/rv32imac-zicsr-zifencei_ilp32/include/c++/14.2.0\r
+         D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/../lib/clang-runtimes/riscv32-esp-unknown-elf/include/c++/14.2.0\r
+         D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/lib/clang/19/include\r
+         D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/../lib/clang-runtimes/riscv32-esp-unknown-elf/rv32imac-zicsr-zifencei_ilp32/include\x0d\r
+        End of search list.\x0d\r
+        [2/2] C:\\windows\\system32\\cmd.exe /C "cd . && D:\\esp32-tools\\tools\\esp-clang\\esp-19.1.2_20250312\\esp-clang\\bin\\clang++.exe  -v -Wl,-v CMakeFiles/cmTC_86c92.dir/CMakeCXXCompilerABI.cpp.obj -o cmTC_86c92.exe -Wl,--out-implib,libcmTC_86c92.dll.a -Wl,--major-image-version,0,--minor-image-version,0   && cd ."\r
+        FAILED: cmTC_86c92.exe \r
+        C:\\windows\\system32\\cmd.exe /C "cd . && D:\\esp32-tools\\tools\\esp-clang\\esp-19.1.2_20250312\\esp-clang\\bin\\clang++.exe  -v -Wl,-v CMakeFiles/cmTC_86c92.dir/CMakeCXXCompilerABI.cpp.obj -o cmTC_86c92.exe -Wl,--out-implib,libcmTC_86c92.dll.a -Wl,--major-image-version,0,--minor-image-version,0   && cd ."\r
+        clang version 19.1.2 (https://github.com/espressif/llvm-project.git esp-19.1.2_20250312)\r
+        Target: riscv32-esp-unknown-elf\r
+        Thread model: posix\r
+        InstalledDir: D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin\r
+         "D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/ld.lld" -m elf32lriscv -o cmTC_86c92.exe -X D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/../lib/clang-runtimes/riscv32-esp-unknown-elf/rv32imac-zicsr-zifencei_ilp32/lib/crt0.o -v CMakeFiles/cmTC_86c92.dir/CMakeCXXCompilerABI.cpp.obj --out-implib libcmTC_86c92.dll.a --major-image-version 0 --minor-image-version 0 -LD:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/../lib/clang-runtimes/riscv32-esp-unknown-elf/rv32imac-zicsr-zifencei_ilp32/lib -lstdc++ -lm --start-group -lc -lgloss -lnosys --end-group D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/../lib/clang-runtimes/riscv32-esp-unknown-elf/rv32imac-zicsr-zifencei_ilp32/lib/libclang_rt.builtins.a\r
+        ld.lld: error: unknown argument '--major-image-version'\r
+        ld.lld: error: unknown argument '--minor-image-version'\r
+        LLD 19.1.2 (compatible with GNU linkers)\r
+        ld.lld: error: cannot open 0: No such file or directory\r
+        ld.lld: error: cannot open 0: No such file or directory\x0d\r
+        clang++: error: ld command failed with exit code 1 (use -v to see invocation)\x0d\r
+        ninja: build stopped: subcommand failed.\r
+        \r
+      exitCode: 1\r
+  -\r
+    kind: "try_compile-v1"\r
+    backtrace:\r
+      - "D:/esp32-tools/tools/cmake/3.30.2/share/cmake-3.30/Modules/CMakeTestCXXCompiler.cmake:56 (try_compile)"\r
+      - "CMakeLists.txt:3 (project)"\r
+    checks:\r
+      - "Check for working CXX compiler: D:/esp32-tools/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/clang++.exe"\r
+    directories:\r
+      source: "D:/workspace/fd230_source_win/HiBTMacWriteTool/build/CMakeFiles/CMakeScratch/TryCompile-dsu2ax"\r
+      binary: "D:/workspace/fd230_source_win/HiBTMacWriteTool/build/CMakeFiles/CMakeScratch/TryCompile-dsu2ax"\r
+    cmakeVariables:\r
+      CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS: "CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS-NOTFOUND"\r
+      CMAKE_CXX_FLAGS: ""\r
+      CMAKE_CXX_SCAN_FOR_MODULES: "OFF"\r
+      CMAKE_EXE_LINKER_FLAGS: ""\r
+    buildResult:\r
+      variable: "CMAKE_CXX_COMPILER_WORKS"\r
+      cached: true\r
+      stdout: |\r
+        Change Dir: 'D:/workspace/fd230_source_win/HiBTMacWriteTool/build/CMakeFiles/CMakeScratch/TryCompile-dsu2ax'\r
+        \r
+        Run Build Command(s): D:/esp32-tools/tools/ninja/1.12.1/ninja.exe -v cmTC_110d2\r
+        [1/2] D:\\esp32-tools\\tools\\esp-clang\\esp-19.1.2_20250312\\esp-clang\\bin\\clang++.exe    -MD -MT CMakeFiles/cmTC_110d2.dir/testCXXCompiler.cxx.obj -MF CMakeFiles\\cmTC_110d2.dir\\testCXXCompiler.cxx.obj.d -o CMakeFiles/cmTC_110d2.dir/testCXXCompiler.cxx.obj -c D:/workspace/fd230_source_win/HiBTMacWriteTool/build/CMakeFiles/CMakeScratch/TryCompile-dsu2ax/testCXXCompiler.cxx\r
+        [2/2] C:\\windows\\system32\\cmd.exe /C "cd . && D:\\esp32-tools\\tools\\esp-clang\\esp-19.1.2_20250312\\esp-clang\\bin\\clang++.exe   CMakeFiles/cmTC_110d2.dir/testCXXCompiler.cxx.obj -o cmTC_110d2.exe -Wl,--out-implib,libcmTC_110d2.dll.a -Wl,--major-image-version,0,--minor-image-version,0  -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."\r
+        FAILED: cmTC_110d2.exe \r
+        C:\\windows\\system32\\cmd.exe /C "cd . && D:\\esp32-tools\\tools\\esp-clang\\esp-19.1.2_20250312\\esp-clang\\bin\\clang++.exe   CMakeFiles/cmTC_110d2.dir/testCXXCompiler.cxx.obj -o cmTC_110d2.exe -Wl,--out-implib,libcmTC_110d2.dll.a -Wl,--major-image-version,0,--minor-image-version,0  -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."\r
+        ld.lld: error: unknown argument '--major-image-version'\r
+        ld.lld: error: unknown argument '--minor-image-version'\r
+        ld.lld: error: cannot open 0: No such file or directory\r
+        ld.lld: error: cannot open 0: No such file or directory\r
+        ld.lld: error: unable to find library -lkernel32\r
+        ld.lld: error: unable to find library -luser32\r
+        ld.lld: error: unable to find library -lgdi32\r
+        ld.lld: error: unable to find library -lwinspool\r
+        ld.lld: error: unable to find library -lshell32\r
+        ld.lld: error: unable to find library -lole32\r
+        ld.lld: error: unable to find library -loleaut32\r
+        ld.lld: error: unable to find library -luuid\r
+        ld.lld: error: unable to find library -lcomdlg32\x0d\r
+        ld.lld: error: unable to find library -ladvapi32\x0d\r
+        clang++: error: ld command failed with exit code 1 (use -v to see invocation)\x0d\r
+        ninja: build stopped: subcommand failed.\r
+        \r
+      exitCode: 1\r
+...\r
diff --git a/build/CMakeFiles/cmake.check_cache b/build/CMakeFiles/cmake.check_cache
new file mode 100644 (file)
index 0000000..56c437b
--- /dev/null
@@ -0,0 +1 @@
+# This file is generated by cmake for dependency checking of the CMakeCache.txt file\r
diff --git a/json_settings.cpp b/json_settings.cpp
new file mode 100644 (file)
index 0000000..e278ff9
--- /dev/null
@@ -0,0 +1,400 @@
+#include "json_settings.h"\r
+#include <QFile>\r
+#include <QDir>\r
+#include <QDebug>\r
+#include <QStandardPaths>\r
+#include <QCoreApplication>\r
+\r
+JsonSettings* JsonSettings::instance = nullptr;\r
+\r
+JsonSettings& JsonSettings::getInstance()\r
+{\r
+    if (nullptr == instance) {\r
+        instance = new JsonSettings();\r
+    }\r
+    return *instance;\r
+}\r
+\r
+void JsonSettings::release()\r
+{\r
+    if (instance != nullptr) {\r
+        delete instance;\r
+        instance = nullptr;\r
+    }\r
+}\r
+\r
+JsonSettings::JsonSettings(QObject *parent)\r
+    : QObject(parent)\r
+    , m_config_file_path("settings.json")\r
+    , m_dut_baud_rate(115200)\r
+    , m_dut_baud_index(11)\r
+    , m_log_output_path("./logs")\r
+    , m_boot_verify_log(true)\r
+{\r
+    // 初始化4个串口配置\r
+    for (int i = 0; i < 4; i++) {\r
+        SerialPortConfig config;\r
+        config.port_index = i;\r
+        config.com_name = "None";\r
+        config.rgb_com_name = "None";\r
+        m_serial_port_configs.append(config);\r
+    }\r
+    \r
+    // 加载配置\r
+    loadSettings();\r
+}\r
+\r
+JsonSettings::~JsonSettings()\r
+{\r
+    // 保存配置\r
+    saveSettings();\r
+}\r
+\r
+QString JsonSettings::getConfigFilePath() const\r
+{\r
+    // 返回应用程序工作目录下的配置文件路径\r
+    QString appDir = QCoreApplication::applicationDirPath();\r
+    return QDir(appDir).filePath(m_config_file_path);\r
+}\r
+\r
+bool JsonSettings::loadSettings()\r
+{\r
+    QString filePath = getConfigFilePath();\r
+    QFile file(filePath);\r
+    \r
+    if (!file.exists()) {\r
+        qDebug() << tr("配置文件不存在,创建默认配置:") << filePath;\r
+        // 创建默认配置\r
+        QJsonObject defaultConfig = createDefaultConfig();\r
+        QJsonDocument doc(defaultConfig);\r
+        if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {\r
+            file.write(doc.toJson(QJsonDocument::Indented));\r
+            file.close();\r
+        }\r
+        readFromJson(defaultConfig);\r
+        return true;\r
+    }\r
+    \r
+    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {\r
+        qDebug() << tr("无法打开配置文件:") << filePath;\r
+        return false;\r
+    }\r
+    \r
+    QByteArray data = file.readAll();\r
+    file.close();\r
+    \r
+    QJsonParseError error;\r
+    QJsonDocument doc = QJsonDocument::fromJson(data, &error);\r
+    \r
+    if (error.error != QJsonParseError::NoError) {\r
+        qDebug() << tr("JSON解析错误:") << error.errorString();\r
+        return false;\r
+    }\r
+    \r
+    if (!doc.isObject()) {\r
+        qDebug() << tr("配置文件格式错误,不是有效的JSON对象");\r
+        return false;\r
+    }\r
+    \r
+    readFromJson(doc.object());\r
+    qDebug() << tr("成功加载配置文件:") << filePath;\r
+    return true;\r
+}\r
+\r
+bool JsonSettings::saveSettings()\r
+{\r
+    QString filePath = getConfigFilePath();\r
+    QFile file(filePath);\r
+    \r
+    // 确保目录存在\r
+    QDir dir = QFileInfo(filePath).absoluteDir();\r
+    if (!dir.exists()) {\r
+        dir.mkpath(".");\r
+    }\r
+    \r
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {\r
+        qDebug() << tr("无法写入配置文件:") << filePath;\r
+        return false;\r
+    }\r
+    \r
+    QJsonObject json = writeToJson();\r
+    QJsonDocument doc(json);\r
+    file.write(doc.toJson(QJsonDocument::Indented));\r
+    file.close();\r
+    \r
+    qDebug() << tr("成功保存配置文件:") << filePath;\r
+    return true;\r
+}\r
+\r
+void JsonSettings::readFromJson(const QJsonObject& json)\r
+{\r
+    // 读取串口配置\r
+    if (json.contains("serial_ports") && json["serial_ports"].isObject()) {\r
+        QJsonObject serialPorts = json["serial_ports"].toObject();\r
+        \r
+        // 读取DUT波特率\r
+        if (serialPorts.contains("dut_baud_rate")) {\r
+            m_dut_baud_rate = serialPorts["dut_baud_rate"].toInt(115200);\r
+        }\r
+        if (serialPorts.contains("dut_baud_index")) {\r
+            m_dut_baud_index = serialPorts["dut_baud_index"].toInt(11);\r
+        }\r
+        \r
+        // 读取串口配置\r
+        if (serialPorts.contains("dut_ports") && serialPorts["dut_ports"].isArray()) {\r
+            QJsonArray portsArray = serialPorts["dut_ports"].toArray();\r
+            m_serial_port_configs.clear();\r
+            \r
+            for (int i = 0; i < portsArray.size() && i < 4; i++) {\r
+                QJsonObject portObj = portsArray[i].toObject();\r
+                SerialPortConfig config;\r
+                config.port_index = portObj["port_index"].toInt(i);\r
+                config.com_name = portObj["com_name"].toString("None");\r
+                config.rgb_com_name = portObj["rgb_com_name"].toString("None");\r
+                m_serial_port_configs.append(config);\r
+            }\r
+        }\r
+    }\r
+    \r
+    // 读取日志配置\r
+    if (json.contains("logging") && json["logging"].isObject()) {\r
+        QJsonObject logging = json["logging"].toObject();\r
+        if (logging.contains("log_output_path")) {\r
+            m_log_output_path = logging["log_output_path"].toString("./logs");\r
+        }\r
+        if (logging.contains("boot_verify_log")) {\r
+            m_boot_verify_log = logging["boot_verify_log"].toBool(true);\r
+        }\r
+    }\r
+    \r
+    // 读取测试指令集\r
+    if (json.contains("test_commands") && json["test_commands"].isObject()) {\r
+        QJsonObject testCommands = json["test_commands"].toObject();\r
+        if (testCommands.contains("command_sets") && testCommands["command_sets"].isArray()) {\r
+            QJsonArray setsArray = testCommands["command_sets"].toArray();\r
+            m_test_command_sets.clear();\r
+            \r
+            for (const QJsonValue& value : setsArray) {\r
+                if (value.isObject()) {\r
+                    QJsonObject setObj = value.toObject();\r
+                    TestCommandSet commandSet;\r
+                    commandSet.name = setObj["name"].toString();\r
+                    \r
+                    if (setObj.contains("commands") && setObj["commands"].isArray()) {\r
+                        QJsonArray commandsArray = setObj["commands"].toArray();\r
+                        for (const QJsonValue& cmdValue : commandsArray) {\r
+                            if (cmdValue.isObject()) {\r
+                                QJsonObject cmdObj = cmdValue.toObject();\r
+                                TestCommand cmd;\r
+                                cmd.cmd = cmdObj["cmd"].toString();\r
+                                cmd.keylog = cmdObj["keylog"].toString();\r
+                                commandSet.commands.append(cmd);\r
+                            }\r
+                        }\r
+                    }\r
+                    m_test_command_sets.append(commandSet);\r
+                }\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+QJsonObject JsonSettings::writeToJson() const\r
+{\r
+    QJsonObject json;\r
+    json["version"] = "1.0";\r
+    \r
+    // 串口配置\r
+    QJsonObject serialPorts;\r
+    serialPorts["dut_baud_rate"] = m_dut_baud_rate;\r
+    serialPorts["dut_baud_index"] = m_dut_baud_index;\r
+    \r
+    QJsonArray portsArray;\r
+    for (const SerialPortConfig& config : m_serial_port_configs) {\r
+        QJsonObject portObj;\r
+        portObj["port_index"] = config.port_index;\r
+        portObj["com_name"] = config.com_name;\r
+        portObj["rgb_com_name"] = config.rgb_com_name;\r
+        portsArray.append(portObj);\r
+    }\r
+    serialPorts["dut_ports"] = portsArray;\r
+    json["serial_ports"] = serialPorts;\r
+    \r
+    // 日志配置\r
+    QJsonObject logging;\r
+    logging["log_output_path"] = m_log_output_path;\r
+    logging["boot_verify_log"] = m_boot_verify_log;\r
+    json["logging"] = logging;\r
+    \r
+    // 测试指令集\r
+    QJsonObject testCommands;\r
+    QJsonArray setsArray;\r
+    for (const TestCommandSet& commandSet : m_test_command_sets) {\r
+        QJsonObject setObj;\r
+        setObj["name"] = commandSet.name;\r
+        \r
+        QJsonArray commandsArray;\r
+        for (const TestCommand& cmd : commandSet.commands) {\r
+            QJsonObject cmdObj;\r
+            cmdObj["cmd"] = cmd.cmd;\r
+            cmdObj["keylog"] = cmd.keylog;\r
+            commandsArray.append(cmdObj);\r
+        }\r
+        setObj["commands"] = commandsArray;\r
+        setsArray.append(setObj);\r
+    }\r
+    testCommands["command_sets"] = setsArray;\r
+    json["test_commands"] = testCommands;\r
+    \r
+    return json;\r
+}\r
+\r
+QJsonObject JsonSettings::createDefaultConfig() const\r
+{\r
+    QJsonObject json;\r
+    json["version"] = "1.0";\r
+    \r
+    // 默认串口配置\r
+    QJsonObject serialPorts;\r
+    serialPorts["dut_baud_rate"] = 115200;\r
+    serialPorts["dut_baud_index"] = 11;\r
+    \r
+    QJsonArray portsArray;\r
+    for (int i = 0; i < 4; i++) {\r
+        QJsonObject portObj;\r
+        portObj["port_index"] = i;\r
+        portObj["com_name"] = "None";\r
+        portObj["rgb_com_name"] = "None";\r
+        portsArray.append(portObj);\r
+    }\r
+    serialPorts["dut_ports"] = portsArray;\r
+    json["serial_ports"] = serialPorts;\r
+    \r
+    // 默认日志配置\r
+    QJsonObject logging;\r
+    logging["log_output_path"] = "./logs";\r
+    logging["boot_verify_log"] = true;\r
+    json["logging"] = logging;\r
+    \r
+    // 默认测试指令集\r
+    QJsonObject testCommands;\r
+    QJsonArray setsArray;\r
+    \r
+    QJsonObject defaultSet;\r
+    defaultSet["name"] = "default";\r
+    QJsonArray commandsArray;\r
+    \r
+    // 添加默认AT命令\r
+    QJsonObject cmd1;\r
+    cmd1["cmd"] = "ATCMD_ADD_VOTE";\r
+    cmd1["keylog"] = "MCU WAKEUP SUCCESS";\r
+    commandsArray.append(cmd1);\r
+    \r
+    QJsonObject cmd2;\r
+    cmd2["cmd"] = "ATCMD_GET_MAC";\r
+    cmd2["keylog"] = "MAC:";\r
+    commandsArray.append(cmd2);\r
+    \r
+    QJsonObject cmd3;\r
+    cmd3["cmd"] = "ATCMD_SET_MAC";\r
+    cmd3["keylog"] = "OK";\r
+    commandsArray.append(cmd3);\r
+    \r
+    QJsonObject cmd4;\r
+    cmd4["cmd"] = "ATCMD_GET_CPUID";\r
+    cmd4["keylog"] = "CPUID:";\r
+    commandsArray.append(cmd4);\r
+    \r
+    QJsonObject cmd5;\r
+    cmd5["cmd"] = "ATCMD_POWEROFF";\r
+    cmd5["keylog"] = "power off";\r
+    commandsArray.append(cmd5);\r
+    \r
+    defaultSet["commands"] = commandsArray;\r
+    setsArray.append(defaultSet);\r
+    testCommands["command_sets"] = setsArray;\r
+    json["test_commands"] = testCommands;\r
+    \r
+    return json;\r
+}\r
+\r
+SerialPortConfig JsonSettings::getSerialPortConfig(int port_index) const\r
+{\r
+    if (port_index >= 0 && port_index < m_serial_port_configs.size()) {\r
+        return m_serial_port_configs[port_index];\r
+    }\r
+    SerialPortConfig config;\r
+    config.port_index = port_index;\r
+    config.com_name = "None";\r
+    config.rgb_com_name = "None";\r
+    return config;\r
+}\r
+\r
+void JsonSettings::setSerialPortConfig(int port_index, const QString& dut_com, const QString& rgb_com)\r
+{\r
+    if (port_index >= 0 && port_index < m_serial_port_configs.size()) {\r
+        m_serial_port_configs[port_index].com_name = dut_com;\r
+        m_serial_port_configs[port_index].rgb_com_name = rgb_com;\r
+    }\r
+}\r
+\r
+int JsonSettings::getDutBaudRate() const\r
+{\r
+    return m_dut_baud_rate;\r
+}\r
+\r
+int JsonSettings::getDutBaudIndex() const\r
+{\r
+    return m_dut_baud_index;\r
+}\r
+\r
+void JsonSettings::setDutBaudRate(int baud_rate)\r
+{\r
+    m_dut_baud_rate = baud_rate;\r
+}\r
+\r
+void JsonSettings::setDutBaudIndex(int baud_index)\r
+{\r
+    m_dut_baud_index = baud_index;\r
+}\r
+\r
+QString JsonSettings::getLogOutputPath() const\r
+{\r
+    return m_log_output_path;\r
+}\r
+\r
+void JsonSettings::setLogOutputPath(const QString& path)\r
+{\r
+    m_log_output_path = path;\r
+}\r
+\r
+bool JsonSettings::getBootVerifyLog() const\r
+{\r
+    return m_boot_verify_log;\r
+}\r
+\r
+void JsonSettings::setBootVerifyLog(bool enabled)\r
+{\r
+    m_boot_verify_log = enabled;\r
+}\r
+\r
+QList<TestCommandSet> JsonSettings::getTestCommandSets() const\r
+{\r
+    return m_test_command_sets;\r
+}\r
+\r
+TestCommandSet JsonSettings::getTestCommandSet(const QString& name) const\r
+{\r
+    for (const TestCommandSet& set : m_test_command_sets) {\r
+        if (set.name == name) {\r
+            return set;\r
+        }\r
+    }\r
+    return TestCommandSet();  // 返回空的指令集\r
+}\r
+\r
+void JsonSettings::setTestCommandSets(const QList<TestCommandSet>& command_sets)\r
+{\r
+    m_test_command_sets = command_sets;\r
+}\r
+\r
diff --git a/json_settings.h b/json_settings.h
new file mode 100644 (file)
index 0000000..972d3b2
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef JSON_SETTINGS_H\r
+#define JSON_SETTINGS_H\r
+\r
+#include <QObject>\r
+#include <QString>\r
+#include <QStringList>\r
+#include <QJsonObject>\r
+#include <QJsonDocument>\r
+#include <QJsonArray>\r
+\r
+// 串口配置结构\r
+struct SerialPortConfig {\r
+    int port_index;\r
+    QString com_name;        // DUT串口名称\r
+    QString rgb_com_name;    // RGB串口名称\r
+};\r
+\r
+// 测试指令配置结构\r
+struct TestCommand {\r
+    QString cmd;             // AT命令\r
+    QString keylog;         // 关键日志/响应标识\r
+};\r
+\r
+struct TestCommandSet {\r
+    QString name;            // 指令集名称\r
+    QList<TestCommand> commands;  // 指令列表\r
+};\r
+\r
+// JSON配置管理类\r
+class JsonSettings : public QObject\r
+{\r
+    Q_OBJECT\r
+\r
+public:\r
+    static JsonSettings& getInstance();\r
+    static void release();\r
+\r
+    // 加载和保存配置\r
+    bool loadSettings();\r
+    bool saveSettings();\r
+\r
+    // 串口配置\r
+    SerialPortConfig getSerialPortConfig(int port_index) const;\r
+    void setSerialPortConfig(int port_index, const QString& dut_com, const QString& rgb_com);\r
+    \r
+    // DUT波特率配置\r
+    int getDutBaudRate() const;\r
+    int getDutBaudIndex() const;\r
+    void setDutBaudRate(int baud_rate);\r
+    void setDutBaudIndex(int baud_index);\r
+\r
+    // 日志配置\r
+    QString getLogOutputPath() const;\r
+    void setLogOutputPath(const QString& path);\r
+    bool getBootVerifyLog() const;\r
+    void setBootVerifyLog(bool enabled);\r
+\r
+    // 测试指令集\r
+    QList<TestCommandSet> getTestCommandSets() const;\r
+    TestCommandSet getTestCommandSet(const QString& name) const;\r
+    void setTestCommandSets(const QList<TestCommandSet>& command_sets);\r
+\r
+    // 获取配置文件的完整路径\r
+    QString getConfigFilePath() const;\r
+\r
+private:\r
+    JsonSettings(QObject *parent = nullptr);\r
+    ~JsonSettings();\r
+    \r
+    // 禁止拷贝\r
+    JsonSettings(const JsonSettings&) = delete;\r
+    JsonSettings& operator=(const JsonSettings&) = delete;\r
+\r
+    // 从JSON对象读取配置\r
+    void readFromJson(const QJsonObject& json);\r
+    \r
+    // 写入配置到JSON对象\r
+    QJsonObject writeToJson() const;\r
+\r
+    // 创建默认配置\r
+    QJsonObject createDefaultConfig() const;\r
+\r
+    static JsonSettings* instance;\r
+    QString m_config_file_path;\r
+\r
+    // 配置数据\r
+    QList<SerialPortConfig> m_serial_port_configs;\r
+    int m_dut_baud_rate;\r
+    int m_dut_baud_index;\r
+    QString m_log_output_path;\r
+    bool m_boot_verify_log;\r
+    QList<TestCommandSet> m_test_command_sets;\r
+};\r
+\r
+#endif // JSON_SETTINGS_H\r
+\r
index c01b1a9..d41dd39 100644 (file)
@@ -8,6 +8,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
 {
     ui->setupUi(this);
     
+    // 设置布局比例:4个测试窗口各占2份,控制面板占1份 (8:1)
+    // horizontalLayout_main包含两个item:splitter(索引0)和verticalLayout_2(索引1)
+    ui->horizontalLayout_main->setStretch(0, 8);  // splitter占8份
+    ui->horizontalLayout_main->setStretch(1, 1);   // verticalLayout_2占1份
+    
     // 创建测试端口控制器实例
     port_controller1 = new TestPortController(0, this);
     port_controller2 = new TestPortController(1, this);
@@ -297,42 +302,81 @@ void MainWindow::ui_save_windows()
     QTextStream out(&file); //分行写入文件
     out << ui->txtb_dispaly->toPlainText();  //这里的File_edit就是之前声明的Textedit控件的名字
 }
-// 存储config配置文件
+// 存储config配置文件(使用JSON格式)
 void MainWindow::ui_setting_save()
 {
-    QSettings *settings = new QSettings("Setting.ini", QSettings::IniFormat);
-
-    // 写入第一组数据
-    settings->beginGroup("Uart_setting");
-    settings->setValue("uart_com", ui->cbox_uart_com_select_1->currentText());
-    settings->setValue("uart_baud", ui->cbox_uart_baud_select->currentIndex());
-//    settings->setValue("spp_addr", ui->ledit_spp_addr->text());
-    settings->sync();
-    settings->endGroup();
-    delete settings;
-    settings = nullptr;
+    JsonSettings& jsonSettings = JsonSettings::getInstance();
+    
+    // 保存所有4个端口的串口配置
+    for (int i = 0; i < MAX_SERIAL_PORTS; i++) {
+        UIPortWidgets widgets = getUIPortWidgets(i);
+        QString dut_com = widgets.cbox_uart_com_select ? widgets.cbox_uart_com_select->currentText() : "None";
+        QString rgb_com = widgets.cbox_uart_com_select_rgb ? widgets.cbox_uart_com_select_rgb->currentText() : "None";
+        jsonSettings.setSerialPortConfig(i, dut_com, rgb_com);
+    }
+    
+    // 保存DUT波特率配置
+    int baud_index = ui->cbox_uart_baud_select->currentIndex();
+    jsonSettings.setDutBaudIndex(baud_index);
+    
+    // 获取波特率数值(从索引转换为实际波特率)
+    QString baud_text = ui->cbox_uart_baud_select->currentText();
+    int baud_rate = baud_text.toInt();
+    jsonSettings.setDutBaudRate(baud_rate);
+    
+    // 保存配置到文件
+    jsonSettings.saveSettings();
+    
+    qDebug() << tr("配置已保存到 settings.json");
 }
-// 读取config配置
+// 读取config配置(使用JSON格式)
 void MainWindow::ui_setting_read()
 {
     // 先更新所有串口选择框(包含最新串口列表和None选项)
     uart_com_select();
     
-    QSettings *msettings = new QSettings("Setting.ini", QSettings::IniFormat);
-    QString saved_com = msettings->value("Uart_setting/uart_com").toString();
+    JsonSettings& jsonSettings = JsonSettings::getInstance();
+    
+    // 加载JSON配置
+    jsonSettings.loadSettings();
     
-    // 如果保存的串口存在,则设置为当前选择;否则保持为None
-    if (!saved_com.isEmpty() && saved_com != tr("None") && saved_com != "None") {
-        int index = ui->cbox_uart_com_select_1->findText(saved_com);
-        if (index >= 0) {
-            ui->cbox_uart_com_select_1->setCurrentIndex(index);
+    // 读取所有4个端口的串口配置
+    for (int i = 0; i < MAX_SERIAL_PORTS; i++) {
+        SerialPortConfig config = jsonSettings.getSerialPortConfig(i);
+        UIPortWidgets widgets = getUIPortWidgets(i);
+        
+        // 设置DUT串口
+        if (widgets.cbox_uart_com_select) {
+            if (!config.com_name.isEmpty() && config.com_name != tr("None") && config.com_name != "None") {
+                int index = widgets.cbox_uart_com_select->findText(config.com_name);
+                if (index >= 0) {
+                    widgets.cbox_uart_com_select->setCurrentIndex(index);
+                }
+            }
+        }
+        
+        // 设置RGB串口
+        if (widgets.cbox_uart_com_select_rgb) {
+            if (!config.rgb_com_name.isEmpty() && config.rgb_com_name != tr("None") && config.rgb_com_name != "None") {
+                int index = widgets.cbox_uart_com_select_rgb->findText(config.rgb_com_name);
+                if (index >= 0) {
+                    widgets.cbox_uart_com_select_rgb->setCurrentIndex(index);
+                }
+            }
         }
     }
     
-    ui->cbox_uart_baud_select->setCurrentIndex(msettings->value("Uart_setting/uart_baud").toInt());
+    // 读取DUT波特率配置
+    int baud_index = jsonSettings.getDutBaudIndex();
+    if (baud_index >= 0 && baud_index < ui->cbox_uart_baud_select->count()) {
+        ui->cbox_uart_baud_select->setCurrentIndex(baud_index);
+    }
 
+    // 加载MAC地址设置(保持原有功能)
     settings::getInstance().load_settings();
-    ui->textBrowser_result->setText(settings::getInstance().getmacStatusFull());
+                    ui->textBrowser_result->setText(settings::getInstance().getmacStatusFull());
+    
+    qDebug() << tr("配置已从 settings.json 加载");
 }
 
 
index eb10c3a..2d86878 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "settings.h"
 #include "test_port_controller.h"
+#include "json_settings.h"
 #include <QTextBrowser>
 #include <QLabel>
 #include <QLineEdit>
index b51b7a9..05c3e4e 100644 (file)
     </property>
     <item>
      <widget class="QSplitter" name="splitter">
-      <property name="orientation">
-       <enum>Qt::Horizontal</enum>
-      </property>
       <property name="font">
        <font>
         <family>Arial</family>
         <pointsize>14</pointsize>
        </font>
       </property>
+      <property name="orientation">
+       <enum>Qt::Horizontal</enum>
+      </property>
       <widget class="QWidget" name="verticalLayoutWidget">
        <property name="font">
         <font>
        <layout class="QVBoxLayout" name="verticalLayout">
         <item>
          <layout class="QHBoxLayout" name="horizontalLayout_7">
+          <item>
+           <widget class="QLabel" name="label_2">
+            <property name="text">
+             <string>DUT</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="MyComboBox" name="cbox_uart_com_select_1">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="font">
+             <font>
+              <family>Arial</family>
+              <pointsize>14</pointsize>
+              <weight>50</weight>
+              <bold>false</bold>
+             </font>
+            </property>
+            <item>
+             <property name="text">
+              <string>COM1</string>
+             </property>
+            </item>
+           </widget>
+          </item>
+         </layout>
+        </item>
         <item>
-         <widget class="QLabel" name="label_2">
-          <property name="text">
-           <string>DUT</string>
-          </property>
-         </widget>
+         <layout class="QHBoxLayout" name="horizontalLayout_5">
+          <item>
+           <widget class="QLabel" name="label">
+            <property name="text">
+             <string>RGB</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="MyComboBox" name="cbox_uart_com_select_rgb1">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="font">
+             <font>
+              <family>Arial</family>
+              <pointsize>14</pointsize>
+              <weight>50</weight>
+              <bold>false</bold>
+             </font>
+            </property>
+            <item>
+             <property name="text">
+              <string>COM1</string>
+             </property>
+            </item>
+           </widget>
+          </item>
+         </layout>
         </item>
         <item>
-         <widget class="MyComboBox" name="cbox_uart_com_select_1">
+         <widget class="QPushButton" name="pbtn_spp_reconnect_1">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
           <property name="sizePolicy">
            <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
             <horstretch>0</horstretch>
             <bold>false</bold>
            </font>
           </property>
-          <item>
-           <property name="text">
-            <string>COM1</string>
-           </property>
-          </item>
-         </widget>
-        </item>
-       </layout>
-      </item>
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_5">
-        <item>
-         <widget class="QLabel" name="label">
           <property name="text">
-           <string>RGB</string>
+           <string>开始测试</string>
+          </property>
+          <property name="checkable">
+           <bool>false</bool>
           </property>
          </widget>
         </item>
         <item>
-         <widget class="MyComboBox" name="cbox_uart_com_select_rgb1">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
+         <widget class="QTextBrowser" name="txtb_dispaly">
           <property name="font">
            <font>
             <family>Arial</family>
             <pointsize>14</pointsize>
-            <weight>50</weight>
-            <bold>false</bold>
            </font>
           </property>
-          <item>
-           <property name="text">
-            <string>COM1</string>
-           </property>
-          </item>
-         </widget>
-        </item>
-       </layout>
-      </item>
-      <item>
-       <widget class="QPushButton" name="pbtn_spp_reconnect_1">
-        <property name="enabled">
-         <bool>true</bool>
-        </property>
-        <property name="sizePolicy">
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-          <horstretch>0</horstretch>
-          <verstretch>0</verstretch>
-         </sizepolicy>
-        </property>
-        <property name="font">
-         <font>
-          <family>Arial</family>
-          <pointsize>14</pointsize>
-          <weight>50</weight>
-          <bold>false</bold>
-         </font>
-        </property>
-        <property name="text">
-         <string>开始测试</string>
-        </property>
-        <property name="checkable">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QTextBrowser" name="txtb_dispaly">
-        <property name="font">
-         <font>
-          <family>Arial</family>
-          <pointsize>14</pointsize>
-         </font>
-        </property>
-        <property name="mouseTracking">
-         <bool>true</bool>
-        </property>
-        <property name="styleSheet">
-         <string notr="true">QTextBrowser{background-color:rgb(26, 26, 26);
-                       color:rgb(127, 255, 0)}</string>
-        </property>
-        <property name="lineWidth">
-         <number>1</number>
-        </property>
-        <property name="verticalScrollBarPolicy">
-         <enum>Qt::ScrollBarAlwaysOn</enum>
-        </property>
-        <property name="textInteractionFlags">
-         <set>Qt::TextBrowserInteraction</set>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout">
-        <item>
-         <widget class="QLabel" name="label_result_success1">
-          <property name="autoFillBackground">
-           <bool>false</bool>
+          <property name="mouseTracking">
+           <bool>true</bool>
           </property>
           <property name="styleSheet">
-           <string notr="true">color:rgb(0, 170, 0);
-font: 75 18pt &quot;Agra&quot;;</string>
+           <string notr="true">QTextBrowser{background-color:rgb(26, 26, 26);
+                       color:rgb(127, 255, 0)}</string>
           </property>
           <property name="lineWidth">
-           <number>0</number>
+           <number>1</number>
           </property>
-          <property name="text">
-           <string>成功0</string>
+          <property name="verticalScrollBarPolicy">
+           <enum>Qt::ScrollBarAlwaysOn</enum>
+          </property>
+          <property name="textInteractionFlags">
+           <set>Qt::TextBrowserInteraction</set>
           </property>
          </widget>
         </item>
         <item>
-         <widget class="QLabel" name="label_result_fail1">
-          <property name="autoFillBackground">
-           <bool>false</bool>
-          </property>
-          <property name="styleSheet">
-           <string notr="true">color:rgb(170, 0, 0);
+         <layout class="QHBoxLayout" name="horizontalLayout">
+          <item>
+           <widget class="QLabel" name="label_result_success1">
+            <property name="autoFillBackground">
+             <bool>false</bool>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">color:rgb(0, 170, 0);
 font: 75 18pt &quot;Agra&quot;;</string>
-          </property>
-          <property name="lineWidth">
-           <number>0</number>
-          </property>
+            </property>
+            <property name="lineWidth">
+             <number>0</number>
+            </property>
+            <property name="text">
+             <string>成功0</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLabel" name="label_result_fail1">
+            <property name="autoFillBackground">
+             <bool>false</bool>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">color:rgb(170, 0, 0);
+font: 75 18pt &quot;Agra&quot;;</string>
+            </property>
+            <property name="lineWidth">
+             <number>0</number>
+            </property>
+            <property name="text">
+             <string>失败0</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <widget class="QLabel" name="label_runtime_status1">
           <property name="text">
-           <string>失败0</string>
+           <string>å·²å\81\9cæ­¢æµ\8bè¯\95...</string>
           </property>
          </widget>
         </item>
        </layout>
-      </item>
-      <item>
-       <widget class="QLabel" name="label_runtime_status1">
-        <property name="text">
-         <string>已停止测试...</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
       </widget>
       <widget class="QWidget" name="verticalLayoutWidget_3">
-     <property name="font">
-      <font>
-       <family>Arial</family>
-       <pointsize>14</pointsize>
-      </font>
-     </property>
-     <layout class="QVBoxLayout" name="verticalLayout_3">
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_6">
+       <property name="font">
+        <font>
+         <family>Arial</family>
+         <pointsize>14</pointsize>
+        </font>
+       </property>
+       <layout class="QVBoxLayout" name="verticalLayout_3">
         <item>
-         <widget class="QLabel" name="label_4">
-          <property name="text">
-           <string>DUT</string>
-          </property>
-         </widget>
+         <layout class="QHBoxLayout" name="horizontalLayout_6">
+          <item>
+           <widget class="QLabel" name="label_4">
+            <property name="text">
+             <string>DUT</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="MyComboBox" name="cbox_uart_com_select_2">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="font">
+             <font>
+              <family>Arial</family>
+              <pointsize>14</pointsize>
+              <weight>50</weight>
+              <bold>false</bold>
+             </font>
+            </property>
+            <item>
+             <property name="text">
+              <string>COM1</string>
+             </property>
+            </item>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <layout class="QHBoxLayout" name="horizontalLayout_8">
+          <item>
+           <widget class="QLabel" name="label_3">
+            <property name="text">
+             <string>RGB</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="MyComboBox" name="cbox_uart_com_select_rgb2">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="font">
+             <font>
+              <family>Arial</family>
+              <pointsize>14</pointsize>
+              <weight>50</weight>
+              <bold>false</bold>
+             </font>
+            </property>
+            <item>
+             <property name="text">
+              <string>COM1</string>
+             </property>
+            </item>
+           </widget>
+          </item>
+         </layout>
         </item>
         <item>
-         <widget class="MyComboBox" name="cbox_uart_com_select_2">
+         <widget class="QPushButton" name="pbtn_spp_reconnect_2">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
           <property name="sizePolicy">
            <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
             <horstretch>0</horstretch>
@@ -267,165 +329,165 @@ font: 75 18pt &quot;Agra&quot;;</string>
             <bold>false</bold>
            </font>
           </property>
-          <item>
-           <property name="text">
-            <string>COM1</string>
-           </property>
-          </item>
-         </widget>
-        </item>
-       </layout>
-      </item>
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_8">
-        <item>
-         <widget class="QLabel" name="label_3">
           <property name="text">
-           <string>RGB</string>
+           <string>开始测试</string>
+          </property>
+          <property name="checkable">
+           <bool>false</bool>
           </property>
          </widget>
         </item>
         <item>
-         <widget class="MyComboBox" name="cbox_uart_com_select_rgb2">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
+         <widget class="QTextBrowser" name="txtb_dispaly_2">
           <property name="font">
            <font>
             <family>Arial</family>
             <pointsize>14</pointsize>
-            <weight>50</weight>
-            <bold>false</bold>
            </font>
           </property>
-          <item>
-           <property name="text">
-            <string>COM1</string>
-           </property>
-          </item>
-         </widget>
-        </item>
-       </layout>
-      </item>
-      <item>
-       <widget class="QPushButton" name="pbtn_spp_reconnect_2">
-        <property name="enabled">
-         <bool>true</bool>
-        </property>
-        <property name="sizePolicy">
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-          <horstretch>0</horstretch>
-          <verstretch>0</verstretch>
-         </sizepolicy>
-        </property>
-        <property name="font">
-         <font>
-          <family>Arial</family>
-          <pointsize>14</pointsize>
-          <weight>50</weight>
-          <bold>false</bold>
-         </font>
-        </property>
-        <property name="text">
-         <string>开始测试</string>
-        </property>
-        <property name="checkable">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QTextBrowser" name="txtb_dispaly_2">
-        <property name="font">
-         <font>
-          <family>Arial</family>
-          <pointsize>14</pointsize>
-         </font>
-        </property>
-        <property name="mouseTracking">
-         <bool>true</bool>
-        </property>
-        <property name="styleSheet">
-         <string notr="true">QTextBrowser{background-color:rgb(26, 26, 26);
-                       color:rgb(127, 255, 0)}</string>
-        </property>
-        <property name="verticalScrollBarPolicy">
-         <enum>Qt::ScrollBarAlwaysOn</enum>
-        </property>
-        <property name="textInteractionFlags">
-         <set>Qt::TextBrowserInteraction</set>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_2">
-        <item>
-         <widget class="QLabel" name="label_result_success2">
-          <property name="autoFillBackground">
-           <bool>false</bool>
+          <property name="mouseTracking">
+           <bool>true</bool>
           </property>
           <property name="styleSheet">
-           <string notr="true">color:rgb(0, 170, 0);
-font: 75 18pt &quot;Agra&quot;;</string>
+           <string notr="true">QTextBrowser{background-color:rgb(26, 26, 26);
+                       color:rgb(127, 255, 0)}</string>
           </property>
-          <property name="lineWidth">
-           <number>0</number>
+          <property name="verticalScrollBarPolicy">
+           <enum>Qt::ScrollBarAlwaysOn</enum>
           </property>
-          <property name="text">
-           <string>成功0</string>
+          <property name="textInteractionFlags">
+           <set>Qt::TextBrowserInteraction</set>
           </property>
          </widget>
         </item>
         <item>
-         <widget class="QLabel" name="label_result_fail2">
-          <property name="autoFillBackground">
-           <bool>false</bool>
-          </property>
-          <property name="styleSheet">
-           <string notr="true">color:rgb(170, 0, 0);
+         <layout class="QHBoxLayout" name="horizontalLayout_2">
+          <item>
+           <widget class="QLabel" name="label_result_success2">
+            <property name="autoFillBackground">
+             <bool>false</bool>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">color:rgb(0, 170, 0);
 font: 75 18pt &quot;Agra&quot;;</string>
-          </property>
-          <property name="lineWidth">
-           <number>0</number>
-          </property>
+            </property>
+            <property name="lineWidth">
+             <number>0</number>
+            </property>
+            <property name="text">
+             <string>成功0</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLabel" name="label_result_fail2">
+            <property name="autoFillBackground">
+             <bool>false</bool>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">color:rgb(170, 0, 0);
+font: 75 18pt &quot;Agra&quot;;</string>
+            </property>
+            <property name="lineWidth">
+             <number>0</number>
+            </property>
+            <property name="text">
+             <string>失败0</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <widget class="QLabel" name="label_runtime_status2">
           <property name="text">
-           <string>失败0</string>
+           <string>å·²å\81\9cæ­¢æµ\8bè¯\95...</string>
           </property>
          </widget>
         </item>
        </layout>
-      </item>
-      <item>
-       <widget class="QLabel" name="label_runtime_status2">
-        <property name="text">
-         <string>已停止测试...</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
       </widget>
       <widget class="QWidget" name="verticalLayoutWidget_4">
-     <property name="font">
-      <font>
-       <family>Arial</family>
-       <pointsize>14</pointsize>
-      </font>
-     </property>
-     <layout class="QVBoxLayout" name="verticalLayout_4">
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_9">
+       <property name="font">
+        <font>
+         <family>Arial</family>
+         <pointsize>14</pointsize>
+        </font>
+       </property>
+       <layout class="QVBoxLayout" name="verticalLayout_4">
         <item>
-         <widget class="QLabel" name="label_5">
-          <property name="text">
-           <string>DUT</string>
-          </property>
-         </widget>
+         <layout class="QHBoxLayout" name="horizontalLayout_9">
+          <item>
+           <widget class="QLabel" name="label_5">
+            <property name="text">
+             <string>DUT</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="MyComboBox" name="cbox_uart_com_select_3">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="font">
+             <font>
+              <family>Arial</family>
+              <pointsize>14</pointsize>
+              <weight>50</weight>
+              <bold>false</bold>
+             </font>
+            </property>
+            <item>
+             <property name="text">
+              <string>COM1</string>
+             </property>
+            </item>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <layout class="QHBoxLayout" name="horizontalLayout_10">
+          <item>
+           <widget class="QLabel" name="label_6">
+            <property name="text">
+             <string>RGB</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="MyComboBox" name="cbox_uart_com_select_rgb3">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="font">
+             <font>
+              <family>Arial</family>
+              <pointsize>14</pointsize>
+              <weight>50</weight>
+              <bold>false</bold>
+             </font>
+            </property>
+            <item>
+             <property name="text">
+              <string>COM1</string>
+             </property>
+            </item>
+           </widget>
+          </item>
+         </layout>
         </item>
         <item>
-         <widget class="MyComboBox" name="cbox_uart_com_select_3">
+         <widget class="QPushButton" name="pbtn_spp_reconnect_3">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
           <property name="sizePolicy">
            <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
             <horstretch>0</horstretch>
@@ -440,165 +502,165 @@ font: 75 18pt &quot;Agra&quot;;</string>
             <bold>false</bold>
            </font>
           </property>
-          <item>
-           <property name="text">
-            <string>COM1</string>
-           </property>
-          </item>
-         </widget>
-        </item>
-       </layout>
-      </item>
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_10">
-        <item>
-         <widget class="QLabel" name="label_6">
           <property name="text">
-           <string>RGB</string>
+           <string>开始测试</string>
+          </property>
+          <property name="checkable">
+           <bool>false</bool>
           </property>
          </widget>
         </item>
         <item>
-         <widget class="MyComboBox" name="cbox_uart_com_select_rgb3">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
+         <widget class="QTextBrowser" name="txtb_dispaly_3">
           <property name="font">
            <font>
             <family>Arial</family>
             <pointsize>14</pointsize>
-            <weight>50</weight>
-            <bold>false</bold>
            </font>
           </property>
-          <item>
-           <property name="text">
-            <string>COM1</string>
-           </property>
-          </item>
-         </widget>
-        </item>
-       </layout>
-      </item>
-      <item>
-       <widget class="QPushButton" name="pbtn_spp_reconnect_3">
-        <property name="enabled">
-         <bool>true</bool>
-        </property>
-        <property name="sizePolicy">
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-          <horstretch>0</horstretch>
-          <verstretch>0</verstretch>
-         </sizepolicy>
-        </property>
-        <property name="font">
-         <font>
-          <family>Arial</family>
-          <pointsize>14</pointsize>
-          <weight>50</weight>
-          <bold>false</bold>
-         </font>
-        </property>
-        <property name="text">
-         <string>开始测试</string>
-        </property>
-        <property name="checkable">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QTextBrowser" name="txtb_dispaly_3">
-        <property name="font">
-         <font>
-          <family>Arial</family>
-          <pointsize>14</pointsize>
-         </font>
-        </property>
-        <property name="mouseTracking">
-         <bool>true</bool>
-        </property>
-        <property name="styleSheet">
-         <string notr="true">QTextBrowser{background-color:rgb(26, 26, 26);
-                       color:rgb(127, 255, 0)}</string>
-        </property>
-        <property name="verticalScrollBarPolicy">
-         <enum>Qt::ScrollBarAlwaysOn</enum>
-        </property>
-        <property name="textInteractionFlags">
-         <set>Qt::TextBrowserInteraction</set>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_3">
-        <item>
-         <widget class="QLabel" name="label_result_success3">
-          <property name="autoFillBackground">
-           <bool>false</bool>
+          <property name="mouseTracking">
+           <bool>true</bool>
           </property>
           <property name="styleSheet">
-           <string notr="true">color:rgb(0, 170, 0);
-font: 75 18pt &quot;Agra&quot;;</string>
+           <string notr="true">QTextBrowser{background-color:rgb(26, 26, 26);
+                       color:rgb(127, 255, 0)}</string>
           </property>
-          <property name="lineWidth">
-           <number>0</number>
+          <property name="verticalScrollBarPolicy">
+           <enum>Qt::ScrollBarAlwaysOn</enum>
           </property>
-          <property name="text">
-           <string>成功0</string>
+          <property name="textInteractionFlags">
+           <set>Qt::TextBrowserInteraction</set>
           </property>
          </widget>
         </item>
         <item>
-         <widget class="QLabel" name="label_result_fail3">
-          <property name="autoFillBackground">
-           <bool>false</bool>
-          </property>
-          <property name="styleSheet">
-           <string notr="true">color:rgb(170, 0, 0);
+         <layout class="QHBoxLayout" name="horizontalLayout_3">
+          <item>
+           <widget class="QLabel" name="label_result_success3">
+            <property name="autoFillBackground">
+             <bool>false</bool>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">color:rgb(0, 170, 0);
 font: 75 18pt &quot;Agra&quot;;</string>
-          </property>
-          <property name="lineWidth">
-           <number>0</number>
-          </property>
+            </property>
+            <property name="lineWidth">
+             <number>0</number>
+            </property>
+            <property name="text">
+             <string>成功0</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLabel" name="label_result_fail3">
+            <property name="autoFillBackground">
+             <bool>false</bool>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">color:rgb(170, 0, 0);
+font: 75 18pt &quot;Agra&quot;;</string>
+            </property>
+            <property name="lineWidth">
+             <number>0</number>
+            </property>
+            <property name="text">
+             <string>失败0</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <widget class="QLabel" name="label_runtime_status3">
           <property name="text">
-           <string>失败0</string>
+           <string>å·²å\81\9cæ­¢æµ\8bè¯\95...</string>
           </property>
          </widget>
         </item>
        </layout>
-      </item>
-      <item>
-       <widget class="QLabel" name="label_runtime_status3">
-        <property name="text">
-         <string>已停止测试...</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
       </widget>
       <widget class="QWidget" name="verticalLayoutWidget_5">
-     <property name="font">
-      <font>
-       <family>Arial</family>
-       <pointsize>14</pointsize>
-      </font>
-     </property>
-     <layout class="QVBoxLayout" name="verticalLayout_5">
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_11">
+       <property name="font">
+        <font>
+         <family>Arial</family>
+         <pointsize>14</pointsize>
+        </font>
+       </property>
+       <layout class="QVBoxLayout" name="verticalLayout_5">
         <item>
-         <widget class="QLabel" name="label_7">
-          <property name="text">
-           <string>DUT</string>
-          </property>
-         </widget>
+         <layout class="QHBoxLayout" name="horizontalLayout_11">
+          <item>
+           <widget class="QLabel" name="label_7">
+            <property name="text">
+             <string>DUT</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="MyComboBox" name="cbox_uart_com_select_4">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="font">
+             <font>
+              <family>Arial</family>
+              <pointsize>14</pointsize>
+              <weight>50</weight>
+              <bold>false</bold>
+             </font>
+            </property>
+            <item>
+             <property name="text">
+              <string>COM1</string>
+             </property>
+            </item>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <layout class="QHBoxLayout" name="horizontalLayout_12">
+          <item>
+           <widget class="QLabel" name="label_8">
+            <property name="text">
+             <string>RGB</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="MyComboBox" name="cbox_uart_com_select_rg_4">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="font">
+             <font>
+              <family>Arial</family>
+              <pointsize>14</pointsize>
+              <weight>50</weight>
+              <bold>false</bold>
+             </font>
+            </property>
+            <item>
+             <property name="text">
+              <string>COM1</string>
+             </property>
+            </item>
+           </widget>
+          </item>
+         </layout>
         </item>
         <item>
-         <widget class="MyComboBox" name="cbox_uart_com_select_4">
+         <widget class="QPushButton" name="pbtn_spp_reconnect_4">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
           <property name="sizePolicy">
            <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
             <horstretch>0</horstretch>
@@ -613,54 +675,93 @@ font: 75 18pt &quot;Agra&quot;;</string>
             <bold>false</bold>
            </font>
           </property>
-          <item>
-           <property name="text">
-            <string>COM1</string>
-           </property>
-          </item>
-         </widget>
-        </item>
-       </layout>
-      </item>
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_12">
-        <item>
-         <widget class="QLabel" name="label_8">
           <property name="text">
-           <string>RGB</string>
+           <string>开始测试</string>
+          </property>
+          <property name="checkable">
+           <bool>false</bool>
           </property>
          </widget>
         </item>
         <item>
-         <widget class="MyComboBox" name="cbox_uart_com_select_rg_4">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
+         <widget class="QTextBrowser" name="txtb_dispaly_4">
           <property name="font">
            <font>
             <family>Arial</family>
             <pointsize>14</pointsize>
-            <weight>50</weight>
-            <bold>false</bold>
            </font>
           </property>
+          <property name="mouseTracking">
+           <bool>true</bool>
+          </property>
+          <property name="styleSheet">
+           <string notr="true">QTextBrowser{background-color:rgb(26, 26, 26);
+                       color:rgb(127, 255, 0)}</string>
+          </property>
+          <property name="verticalScrollBarPolicy">
+           <enum>Qt::ScrollBarAlwaysOn</enum>
+          </property>
+          <property name="textInteractionFlags">
+           <set>Qt::TextBrowserInteraction</set>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <layout class="QHBoxLayout" name="horizontalLayout_4">
           <item>
-           <property name="text">
-            <string>COM1</string>
-           </property>
+           <widget class="QLabel" name="label_result_success4">
+            <property name="autoFillBackground">
+             <bool>false</bool>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">color:rgb(0, 170, 0);
+font: 75 18pt &quot;Agra&quot;;</string>
+            </property>
+            <property name="lineWidth">
+             <number>0</number>
+            </property>
+            <property name="text">
+             <string>成功0</string>
+            </property>
+           </widget>
           </item>
+          <item>
+           <widget class="QLabel" name="label_result_fail4">
+            <property name="autoFillBackground">
+             <bool>false</bool>
+            </property>
+            <property name="styleSheet">
+             <string notr="true">color:rgb(170, 0, 0);
+font: 75 18pt &quot;Agra&quot;;</string>
+            </property>
+            <property name="lineWidth">
+             <number>0</number>
+            </property>
+            <property name="text">
+             <string>失败0</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <widget class="QLabel" name="label_runtime_status4">
+          <property name="text">
+           <string>已停止测试...</string>
+          </property>
          </widget>
         </item>
        </layout>
-      </item>
+      </widget>
+     </widget>
+    </item>
+    <item>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <property name="spacing">
+       <number>4</number>
+      </property>
       <item>
-       <widget class="QPushButton" name="pbtn_spp_reconnect_4">
-        <property name="enabled">
-         <bool>true</bool>
-        </property>
+       <widget class="QComboBox" name="cbox_uart_baud_select">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
           <horstretch>0</horstretch>
@@ -675,277 +776,177 @@ font: 75 18pt &quot;Agra&quot;;</string>
           <bold>false</bold>
          </font>
         </property>
-        <property name="text">
-         <string>开始测试</string>
+        <property name="cursor">
+         <cursorShape>ArrowCursor</cursorShape>
         </property>
-        <property name="checkable">
+        <property name="editable">
          <bool>false</bool>
         </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QTextBrowser" name="txtb_dispaly_4">
-        <property name="font">
-         <font>
-          <family>Arial</family>
-          <pointsize>14</pointsize>
-         </font>
-        </property>
-        <property name="mouseTracking">
-         <bool>true</bool>
+        <property name="currentText">
+         <string>500000</string>
         </property>
-        <property name="styleSheet">
-         <string notr="true">QTextBrowser{background-color:rgb(26, 26, 26);
-                       color:rgb(127, 255, 0)}</string>
-        </property>
-        <property name="verticalScrollBarPolicy">
-         <enum>Qt::ScrollBarAlwaysOn</enum>
+        <property name="currentIndex">
+         <number>11</number>
         </property>
-        <property name="textInteractionFlags">
-         <set>Qt::TextBrowserInteraction</set>
+        <property name="duplicatesEnabled">
+         <bool>true</bool>
         </property>
-       </widget>
-      </item>
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_4">
         <item>
-         <widget class="QLabel" name="label_result_success4">
-          <property name="autoFillBackground">
-           <bool>false</bool>
-          </property>
-          <property name="styleSheet">
-           <string notr="true">color:rgb(0, 170, 0);
-font: 75 18pt &quot;Agra&quot;;</string>
-          </property>
-          <property name="lineWidth">
-           <number>0</number>
-          </property>
-          <property name="text">
-           <string>成功0</string>
-          </property>
-         </widget>
+         <property name="text">
+          <string>4800</string>
+         </property>
         </item>
         <item>
-         <widget class="QLabel" name="label_result_fail4">
-          <property name="autoFillBackground">
-           <bool>false</bool>
-          </property>
-          <property name="styleSheet">
-           <string notr="true">color:rgb(170, 0, 0);
-font: 75 18pt &quot;Agra&quot;;</string>
-          </property>
-          <property name="lineWidth">
-           <number>0</number>
-          </property>
-          <property name="text">
-           <string>失败0</string>
-          </property>
-         </widget>
+         <property name="text">
+          <string>9600</string>
+         </property>
         </item>
-       </layout>
-      </item>
-      <item>
-       <widget class="QLabel" name="label_runtime_status4">
-        <property name="text">
-         <string>已停止测试...</string>
-        </property>
-       </widget>
-      </item>
-     </layout>
-      </widget>
-     </widget>
-    </item>
-    <item>
-     <widget class="QWidget" name="verticalLayoutWidget_2">
-      <layout class="QVBoxLayout" name="verticalLayout_2">
-       <item>
-        <widget class="QComboBox" name="cbox_uart_baud_select">
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
+        <item>
+         <property name="text">
+          <string>14400</string>
          </property>
-         <property name="font">
-          <font>
-           <family>Arial</family>
-           <pointsize>14</pointsize>
-           <weight>50</weight>
-           <bold>false</bold>
-          </font>
+        </item>
+        <item>
+         <property name="text">
+          <string>19200</string>
          </property>
-         <property name="cursor">
-          <cursorShape>ArrowCursor</cursorShape>
+        </item>
+        <item>
+         <property name="text">
+          <string>38400</string>
          </property>
-         <property name="editable">
-          <bool>false</bool>
+        </item>
+        <item>
+         <property name="text">
+          <string>57600</string>
          </property>
-         <property name="currentText">
-          <string>500000</string>
+        </item>
+        <item>
+         <property name="text">
+          <string>115200</string>
          </property>
-         <property name="currentIndex">
-          <number>11</number>
+        </item>
+        <item>
+         <property name="text">
+          <string>128000</string>
          </property>
-         <property name="duplicatesEnabled">
-          <bool>true</bool>
+        </item>
+        <item>
+         <property name="text">
+          <string>230400</string>
          </property>
-         <item>
-          <property name="text">
-           <string>4800</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>9600</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>14400</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>19200</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>38400</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>57600</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>115200</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>128000</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>230400</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>256000</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>460800</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>500000</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>512000</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>600000</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>750000</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>921600</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>1000000</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>1500000</string>
-          </property>
-         </item>
-         <item>
-          <property name="text">
-           <string>2000000</string>
-          </property>
-         </item>
-        </widget>
-       </item>
-       <item>
-        <widget class="QPushButton" name="pbtn_spp_connect_all">
-         <property name="enabled">
-          <bool>true</bool>
+        </item>
+        <item>
+         <property name="text">
+          <string>256000</string>
          </property>
-         <property name="sizePolicy">
-          <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-           <horstretch>0</horstretch>
-           <verstretch>0</verstretch>
-          </sizepolicy>
+        </item>
+        <item>
+         <property name="text">
+          <string>460800</string>
          </property>
-         <property name="font">
-          <font>
-           <family>Arial</family>
-           <pointsize>14</pointsize>
-           <weight>50</weight>
-           <bold>false</bold>
-          </font>
+        </item>
+        <item>
+         <property name="text">
+          <string>500000</string>
          </property>
+        </item>
+        <item>
          <property name="text">
-          <string>全部开始测试</string>
+          <string>512000</string>
          </property>
-         <property name="checkable">
-          <bool>false</bool>
+        </item>
+        <item>
+         <property name="text">
+          <string>600000</string>
          </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QTextBrowser" name="textBrowser_result">
-         <property name="font">
-          <font>
-           <family>Arial</family>
-           <pointsize>14</pointsize>
-          </font>
+        </item>
+        <item>
+         <property name="text">
+          <string>750000</string>
          </property>
-         <property name="html">
-          <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
-&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
-p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Arial','Arial','黑体'; font-size:14pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;已测试xxx设备&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;xxx成功,xxx失败。&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+        </item>
+        <item>
+         <property name="text">
+          <string>921600</string>
          </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QPushButton" name="pushButton_openlogfolder">
-         <property name="font">
-          <font>
-           <family>Arial</family>
-           <pointsize>14</pointsize>
-          </font>
+        </item>
+        <item>
+         <property name="text">
+          <string>1000000</string>
          </property>
+        </item>
+        <item>
          <property name="text">
-          <string>打开日志路径</string>
+          <string>1500000</string>
          </property>
-        </widget>
-       </item>
-      </layout>
-     </widget>
+        </item>
+        <item>
+         <property name="text">
+          <string>2000000</string>
+         </property>
+        </item>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="pbtn_spp_connect_all">
+        <property name="enabled">
+         <bool>true</bool>
+        </property>
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="font">
+         <font>
+          <family>Arial</family>
+          <pointsize>14</pointsize>
+          <weight>50</weight>
+          <bold>false</bold>
+         </font>
+        </property>
+        <property name="text">
+         <string>全部开始测试</string>
+        </property>
+        <property name="checkable">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QTextBrowser" name="textBrowser_result">
+        <property name="font">
+         <font>
+          <family>Arial</family>
+          <pointsize>14</pointsize>
+         </font>
+        </property>
+        <property name="html">
+         <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Arial','黑体'; font-size:14pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Arial','Arial','黑体';&quot;&gt;已测试xxx设备&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Arial','Arial','黑体';&quot;&gt;xxx成功,xxx失败。&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="pushButton_openlogfolder">
+        <property name="font">
+         <font>
+          <family>Arial</family>
+          <pointsize>14</pointsize>
+         </font>
+        </property>
+        <property name="text">
+         <string>打开日志路径</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
     </item>
    </layout>
   </widget>
index 20bc4fd..299f287 100644 (file)
@@ -68,6 +68,13 @@ OK~
 « fac:^^^^ BTMAC=28:11:06:4D:29:EF ^^^^ CyweeChipInfo=HS11g9LHov9p97100C5C20
 
 OK~
+
+
+» AT^GETBTMAC
+« get nv local_addr : ******4f71f0
+fac:^^^^ BTMAC=28:11:06:4F:71:F0 ^^^^ CyweeChipInfo=
+
+
 */
 #define BOOT_UP_MSG "yaffs filesystem init start"
 #define TIME_FOR_CMD "bt enable_bt_stack ret"
diff --git a/settings.json b/settings.json
new file mode 100644 (file)
index 0000000..b1ae922
--- /dev/null
@@ -0,0 +1,63 @@
+{\r
+  "version": "1.0",\r
+  "serial_ports": {\r
+    "dut_ports": [\r
+      {\r
+        "port_index": 0,\r
+        "com_name": "None",\r
+        "rgb_com_name": "None"\r
+      },\r
+      {\r
+        "port_index": 1,\r
+        "com_name": "None",\r
+        "rgb_com_name": "None"\r
+      },\r
+      {\r
+        "port_index": 2,\r
+        "com_name": "None",\r
+        "rgb_com_name": "None"\r
+      },\r
+      {\r
+        "port_index": 3,\r
+        "com_name": "None",\r
+        "rgb_com_name": "None"\r
+      }\r
+    ],\r
+    "dut_baud_rate": 500000,\r
+    "dut_baud_index": 11\r
+  },\r
+  "logging": {\r
+    "log_output_path": "./logs",\r
+    "boot_verify_log": true\r
+  },\r
+  "test_commands": {\r
+    "command_sets": [\r
+      {\r
+        "name": "default",\r
+        "commands": [\r
+          {\r
+            "cmd": "ATCMD_ADD_VOTE",\r
+            "keylog": "MCU WAKEUP SUCCESS"\r
+          },\r
+          {\r
+            "cmd": "ATCMD_GET_MAC",\r
+            "keylog": "MAC:"\r
+          },\r
+          {\r
+            "cmd": "ATCMD_SET_MAC",\r
+            "keylog": "OK"\r
+          },\r
+          {\r
+            "cmd": "ATCMD_GET_CPUID",\r
+            "keylog": "CPUID:"\r
+          },\r
+          {\r
+            "cmd": "ATCMD_POWEROFF",\r
+            "keylog": "power off"\r
+          }\r
+        ]\r
+      }\r
+    ]\r
+  }\r
+}\r
+\r
index 9f41cca..8c2779b 100644 (file)
@@ -22,9 +22,24 @@ TestPortController::TestPortController(int port_index, QObject *parent)
     , m_uart_rx_Ignoring_display(false)
     , m_write_success_count(0)
     , m_write_fail_count(0)
+    , m_test_state(TEST_STATE_IDLE)
+    , m_vote_retry_count(0)
+    , m_color_check_timer(new QTimer(this))
+    , m_audio_timeout_timer(new QTimer(this))
+    , m_gpio_timeout_timer(new QTimer(this))
+    , m_blue_color_detected(false)
+    , m_last_audio_level("")
+    , m_audio_level_count(0)
+    , m_gpio_result_detected(false)
 {
     // 连接定时器信号
     connect(m_spp_timer_handle, &QTimer::timeout, this, &TestPortController::onTimerTimeout);
+    connect(m_color_check_timer, &QTimer::timeout, this, &TestPortController::onColorCheckTimer);
+    connect(m_audio_timeout_timer, &QTimer::timeout, this, &TestPortController::onAudioTimeoutTimer);
+    connect(m_gpio_timeout_timer, &QTimer::timeout, this, &TestPortController::onGpioTimeoutTimer);
+    m_color_check_timer->setSingleShot(true);
+    m_audio_timeout_timer->setSingleShot(true);
+    m_gpio_timeout_timer->setSingleShot(true);
     
     // 连接DUT串口信号
     connect(m_dut_serial, &QSerialPort::readyRead, this, &TestPortController::onReadyRead);
@@ -41,10 +56,17 @@ TestPortController::TestPortController(int port_index, QObject *parent)
     // 连接RGBC数据解析信号(带颜色名称)
     connect(m_rgb_reader, &RgbSerialReader::rgbcDataParsedWithColor, this, 
             [this](int port_index, quint16 red, quint16 green, quint16 blue, quint16 clear, const QString& colorName) {
-        // 只显示颜色名称(颜色变化时才更新)
-        QString colorInfo = tr("颜色: %1\r\n").arg(colorName);
-        emit displayMessage(colorInfo, true);
+        // 不在窗口中显示颜色,只在控制台打印用于调试
         qDebug() << tr("端口%1 检测到颜色: %2").arg(m_port_index + 1).arg(colorName);
+        
+        // 新测试流程:检测到蓝色后,进入投票阶段
+        if (m_test_state == TEST_STATE_CHECK_BLUE_COLOR && colorName.contains(tr("蓝色"))) {
+            m_blue_color_detected = true;
+            emit displayMessage(tr("LCD颜色检测通过(蓝色)\r\n"), true);
+            transitionToState(TEST_STATE_SEND_VOTE);
+            m_vote_retry_count = 0;  // 重置投票重试计数
+            sendNextTestCommand();
+        }
     });
     
     connect(m_rgb_reader, &RgbSerialReader::errorOccurred, this, [this](const QString& error) {
@@ -125,6 +147,21 @@ void TestPortController::connectPort(const QString& com_name, int baud_rate)
     emit failCountChanged(m_write_fail_count);
     emit buttonTextChanged(tr("停止写地址"));
     emit statusChanged(tr("等待手表开机"));
+    
+    // 初始化新测试流程状态
+    m_test_state = TEST_STATE_WAIT_NAND_ID;
+    m_vote_retry_count = 0;
+    m_blue_color_detected = false;
+    m_last_audio_level.clear();
+    m_audio_level_count = 0;
+    m_gpio_result_detected = false;
+    m_test_result_summary.clear();
+    
+    // 清空窗口,显示等待设备启动
+    emit clearDisplay();
+    emit displayMessage(tr("等待设备启动...\r\n"), true);
+    
+    qDebug() << tr("端口%1初始化新测试流程,状态: %2").arg(m_port_index + 1).arg(getStateName(m_test_state));
 }
 
 void TestPortController::disconnectPort()
@@ -201,8 +238,17 @@ void TestPortController::readData()
 {
     const QByteArray data = m_dut_serial->readAll();
     
+    if (data.isEmpty()) {
+        return;
+    }
+    
+    // 控制台打印:接收到的原始数据(用于调试)
+    qDebug() << tr("端口%1 DUT串口接收到数据,长度:%2").arg(m_port_index + 1).arg(data.length());
+    QString dataStr = QString::fromUtf8(data);
+    qDebug() << tr("端口%1 DUT串口数据内容: %2").arg(m_port_index + 1).arg(dataStr);
+    
     if (m_uart_rx_flag) {
-        qDebug() << tr("端口%1接收数据:").arg(m_port_index) << data;
+        qDebug() << tr("端口%1接收数据(AT命令响应):").arg(m_port_index) << data;
     }
     
     if (!m_working_state) {
@@ -213,74 +259,159 @@ void TestPortController::readData()
     // 将新数据添加到开机检测缓存中
     m_boot_detect_buffer.append(data);
     
-    // 保持缓存大小合理
-    if (m_boot_detect_buffer.length() > 8192) {
-        m_boot_detect_buffer = m_boot_detect_buffer.right(8192);
+    // 调试:当接收到包含flash关键字的数据时,打印缓冲区信息
+    QString newDataStr = QString::fromUtf8(data);
+    if (newDataStr.contains("find nand flash chip id", Qt::CaseInsensitive)) {
+        qDebug() << tr("端口%1 [关键数据] 接收到包含flash id的数据,长度=%2,当前缓冲区长度=%3")
+                    .arg(m_port_index + 1)
+                    .arg(data.length())
+                    .arg(m_boot_detect_buffer.length());
+    }
+    
+    // 保持缓存大小合理(在检测之前先检查,避免截断关键信息)
+    // 直接在QByteArray上搜索,避免UTF-8转换问题
+    QByteArray lowerBuffer = m_boot_detect_buffer.toLower();
+    bool hasFlashInfo = lowerBuffer.contains("find nand flash chip id") || lowerBuffer.contains("nand flash chip id");
+    
+    if (m_boot_detect_buffer.length() > 16384) {  // 增加到16KB,确保不会截断关键信息
+        // 如果包含flash信息,尝试保留包含该信息的部分
+        if (hasFlashInfo) {
+            int flashPos = lowerBuffer.indexOf("find nand flash chip id");
+            if (flashPos < 0) {
+                flashPos = lowerBuffer.indexOf("nand flash chip id");
+            }
+            if (flashPos >= 0) {
+                // 保留flash信息前后各4096字节
+                int startPos = qMax(0, flashPos - 4096);
+                m_boot_detect_buffer = m_boot_detect_buffer.mid(startPos);
+                qDebug() << tr("端口%1 缓冲区包含flash信息,保留从位置%2开始的数据,新长度=%3")
+                            .arg(m_port_index + 1)
+                            .arg(startPos)
+                            .arg(m_boot_detect_buffer.length());
+            } else {
+                m_boot_detect_buffer = m_boot_detect_buffer.right(16384);
+            }
+        } else {
+            m_boot_detect_buffer = m_boot_detect_buffer.right(16384);
+        }
         static bool buffer_limit_warned[4] = {false, false, false, false};
         if (!buffer_limit_warned[m_port_index]) {
-            qDebug() << tr("端口%1开机检测缓存过大,保留最近8192字节").arg(m_port_index);
+            qDebug() << tr("端口%1开机检测缓存过大,保留最近16384字节").arg(m_port_index);
             buffer_limit_warned[m_port_index] = true;
         }
     }
     
-    // 检测开机信号
-    if (m_boot_detect_buffer.indexOf(BOOT_UP_MSG) >= 0) {
-        emit statusChanged(tr("发现新设备"));
-        m_waiting_cmd = true;
-        m_cmd_index = 0;
-        QString avalible_mac = settings::getInstance().getAvalibleMac();
-        setMacAddress(avalible_mac);
-        emit clearDisplay();
-        m_boot_detect_buffer.clear();
-        qDebug() << tr("端口%1检测到开机信号,清理缓存").arg(m_port_index);
-    }
+    // 新测试流程:检测启动日志
+    // 直接在QByteArray上搜索,避免UTF-8转换问题
     
-    // 检测MAC地址信息
-    if (m_working_state && !m_waiting_cmd) {
-        QRegExp macRegex("BTMAC=([0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2})");
-        int macPos = macRegex.indexIn(m_boot_detect_buffer);
-        if (macPos >= 0) {
-            QString foundMac = macRegex.cap(1);
-            QString macWithoutColon = foundMac.replace(":", "").toUpper();
+    // 检测nand flash id(直接在QByteArray上搜索,不区分大小写)
+    // 检测到flash表示新一轮检测开始,清空窗口数据
+    if (m_test_state == TEST_STATE_IDLE || m_test_state == TEST_STATE_WAIT_NAND_ID) {
+        int findPos = lowerBuffer.indexOf("find nand flash chip id");
+        int nandPos = lowerBuffer.indexOf("nand flash chip id");
+        
+        if (findPos >= 0 || nandPos >= 0) {
+            // 找到包含flash id的位置,尝试提取ID
+            int searchStart = (findPos >= 0) ? findPos : nandPos;
+            // 在找到的位置附近搜索 "0x" 和后续的4位十六进制数
+            QByteArray snippet = m_boot_detect_buffer.mid(qMax(0, searchStart - 20), 100);
+            QString snippetStr = QString::fromLatin1(snippet);  // 使用fromLatin1更宽松
             
-            bool mac_used = settings::getInstance().getMacUsed(macWithoutColon);
+            // 尝试多种正则表达式匹配
+            QRegExp idRegex1("find\\s+nand\\s+flash\\s+chip\\s+id[\\s:]*0x([0-9A-Fa-f]+)", Qt::CaseInsensitive);
+            QRegExp idRegex2("nand\\s+flash\\s+chip\\s+id[\\s:]*0x([0-9A-Fa-f]+)", Qt::CaseInsensitive);
             
-            if (mac_used) {
-                emit displayMessage(tr("手表地址") + macWithoutColon + tr("已占用\r\n"), false);
-                emit showResult(tr("Mac地址已占用"), false);
+            QString nandId;
+            if (idRegex1.indexIn(snippetStr) >= 0) {
+                nandId = idRegex1.cap(1);
+                qDebug() << tr("端口%1 使用正则1匹配到nand id: 0x%2").arg(m_port_index + 1).arg(nandId);
+            } else if (idRegex2.indexIn(snippetStr) >= 0) {
+                nandId = idRegex2.cap(1);
+                qDebug() << tr("端口%1 使用正则2匹配到nand id: 0x%2").arg(m_port_index + 1).arg(nandId);
             } else {
-                emit displayMessage(tr("手表当前地址") + macWithoutColon + tr(" 可用!\r\n"), true);
+                // 使用简单匹配:在snippet中查找 "0x" 后跟4位十六进制
+                int hexPos = snippet.indexOf("0x");
+                if (hexPos >= 0 && hexPos + 6 <= snippet.length()) {
+                    QByteArray hexPart = snippet.mid(hexPos + 2, 4);
+                    bool isHex = true;
+                    for (int i = 0; i < hexPart.length(); i++) {
+                        char c = hexPart[i];
+                        if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) {
+                            isHex = false;
+                            break;
+                        }
+                    }
+                    if (isHex) {
+                        nandId = QString::fromLatin1(hexPart).toUpper();
+                        qDebug() << tr("端口%1 使用简单匹配找到nand id: 0x%2").arg(m_port_index + 1).arg(nandId);
+                    }
+                }
+            }
+            
+            if (!nandId.isEmpty()) {
+                // 新一轮检测开始,清空窗口数据
+                emit clearDisplay();
+                
+                // 显示解析后的数据到窗口
+                emit displayMessage(tr("=== 新一轮检测开始 ===\r\n"), true);
+                emit displayMessage(tr("✓ 检测到nand flash id: 0x%1\r\n").arg(nandId), true);
+                
+                transitionToState(TEST_STATE_WAIT_NAND_MODEL);
+                qDebug() << tr("端口%1 ✓ 检测到nand flash id: 0x%2,清空窗口,开始新一轮检测").arg(m_port_index + 1).arg(nandId);
+            } else {
+                qDebug() << tr("端口%1 检测到包含'find nand flash chip id'的文本,但未能提取ID").arg(m_port_index + 1);
             }
         }
     }
     
-    // 检测命令时机信号
-    if (m_waiting_cmd && m_boot_detect_buffer.indexOf(TIME_FOR_CMD) >= 0) {
-        uart_send_data(ATCMD_ADD_VOTE);
-        m_boot_detect_buffer.clear();
-        qDebug() << tr("端口%1检测到命令时机信号,清理缓存").arg(m_port_index);
-    }
-    
-    // 检测启动完成信号
-    if (m_waiting_cmd && !m_startup_complete_detected &&
-        m_boot_detect_buffer.indexOf(STARTUP_POST_INIT) >= 0 && 
-        m_boot_detect_buffer.indexOf(STARTUP_POST_INIT_TASK) >= 0) {
-        m_startup_complete_detected = true;
-        qDebug() << tr("端口%1检测到启动完成信号").arg(m_port_index);
-        emit displayMessage(tr("系统启动完成,可以执行GETIDS\r\n"), true);
-        m_boot_detect_buffer.clear();
-        
-        if ((m_cmd_index == 3 || m_cmd_index == 4) && !m_uart_rx_flag) {
-            if (m_cmd_index == 3) {
-                m_cmd_index++;
-            }
-            m_uart_rx_buff_array.clear();
-            if (m_cmd_index == 4) {
-                uart_send_data(ATCMD_GET_CPUID);
+    // 检测nand flash型号(直接在QByteArray上搜索)
+    if (m_test_state == TEST_STATE_WAIT_NAND_MODEL) {
+        if (lowerBuffer.contains("nand flash") && (lowerBuffer.contains("start init") || lowerBuffer.contains(" init"))) {
+            // 尝试提取型号:查找 "nand flash" 后的型号名称
+            int nandPos = lowerBuffer.indexOf("nand flash");
+            if (nandPos >= 0) {
+                QByteArray snippet = m_boot_detect_buffer.mid(nandPos, 100);
+                QString snippetStr = QString::fromLatin1(snippet);
+                
+                QRegExp modelRegex1("nand flash\\s+([A-Z0-9]+)\\s+start init", Qt::CaseInsensitive);
+                QRegExp modelRegex2("nand flash\\s+([A-Z0-9]+)", Qt::CaseInsensitive);
+                
+                QString model;
+                if (modelRegex1.indexIn(snippetStr) >= 0) {
+                    model = modelRegex1.cap(1);
+                } else if (modelRegex2.indexIn(snippetStr) >= 0) {
+                    model = modelRegex2.cap(1);
+                }
+                
+                if (!model.isEmpty()) {
+                    // 显示解析后的数据到窗口
+                    emit displayMessage(tr("✓ 检测到nand flash型号: %1\r\n").arg(model), true);
+                    transitionToState(TEST_STATE_WAIT_BLUE_WINDOW);
+                    qDebug() << tr("端口%1 ✓ 检测到nand flash型号: %2").arg(m_port_index + 1).arg(model);
+                }
             }
         }
     }
     
+    // 检测蓝色窗口(直接在QByteArray上搜索)
+    if (m_test_state == TEST_STATE_WAIT_BLUE_WINDOW) {
+        if (m_boot_detect_buffer.contains("Blue window created and displayed:")) {
+            // 显示解析后的数据到窗口
+            emit displayMessage(tr("✓ 检测到蓝色窗口已创建\r\n"), true);
+            transitionToState(TEST_STATE_CHECK_BLUE_COLOR);
+            // 延迟1秒后检测颜色
+            m_color_check_timer->start(1000);
+            qDebug() << tr("端口%1检测到蓝色窗口,1秒后检测颜色").arg(m_port_index + 1);
+        }
+    }
+    
+    // 旧流程兼容代码已删除,现在只使用新的测试流程
+    
+    // 新测试流程:处理日志消息
+    if (m_working_state && m_test_state != TEST_STATE_IDLE) {
+        checkLogMessages();
+    }
+    
     if (m_uart_rx_flag) {
         m_uart_rx_buff_array.append(data);
         
@@ -309,56 +440,71 @@ void TestPortController::readData()
             }
             
             m_uart_rx_flag = false;
-            uart_process();
             
-            if (m_cmd_index < 0) {
-                if (m_spp_timer_handle && m_spp_timer_handle->isActive()) {
-                    m_spp_timer_handle->stop();
+            // 新测试流程中不使用旧的uart_process逻辑,避免冲突
+            // 新流程的状态转换由checkLogMessages()处理
+            if (m_test_state == TEST_STATE_IDLE || m_test_state == TEST_STATE_WAIT_NAND_ID) {
+                // 只有在旧流程(空闲或等待启动)时才使用uart_process
+                uart_process();
+                
+                if (m_cmd_index < 0) {
+                    if (m_spp_timer_handle && m_spp_timer_handle->isActive()) {
+                        m_spp_timer_handle->stop();
+                    }
+                    
+                    if (m_uart_rx_buff_array.indexOf("power off device") >= 0) {
+                        emit displayMessage(tr("关机成功\r\n"), true);
+                    }
+                    return;
                 }
                 
-                if (m_uart_rx_buff_array.indexOf("power off device") >= 0) {
-                    emit displayMessage(tr("关机成功\r\n"), true);
+                m_cmd_index++;
+                
+                switch(m_cmd_index) {
+                case 0:
+                    break;
+                case 1:
+                    uart_send_data(ATCMD_GET_MAC);
+                    break;
+                case 2:
+                {
+                    QString set_mac_cmd = QString(ATCMD_SET_MAC).arg(m_mac_address);
+                    uart_send_data(set_mac_cmd);
                 }
-                return;
-            }
-            
-            m_cmd_index++;
-            
-            switch(m_cmd_index) {
-            case 0:
-                break;
-            case 1:
-                uart_send_data(ATCMD_GET_MAC);
-                break;
-            case 2:
-            {
-                QString set_mac_cmd = QString(ATCMD_SET_MAC).arg(m_mac_address);
-                uart_send_data(set_mac_cmd);
-            }
-                break;
-            case 3:
-                uart_send_data(ATCMD_GET_MAC);
-                break;
-            case 4:
-            {
-                if (m_startup_complete_detected) {
-                    uart_send_data(ATCMD_GET_CPUID);
-                } else {
-                    emit displayMessage(tr("等待系统完全启动信号...\r\n"), false);
-                    m_cmd_index = 4;
-                    return;
+                    break;
+                case 3:
+                    uart_send_data(ATCMD_GET_MAC);
+                    break;
+                case 4:
+                {
+                    if (m_startup_complete_detected) {
+                        uart_send_data(ATCMD_GET_CPUID);
+                    } else {
+                        emit displayMessage(tr("等待系统完全启动信号...\r\n"), false);
+                        m_cmd_index = 4;
+                        return;
+                    }
                 }
-            }
-                break;
-            case 5:
-                uart_send_data(ATCMD_POWEROFF);
-                break;
-            default:
-                m_cmd_index = -1;
-                if (m_spp_timer_handle && m_spp_timer_handle->isActive()) {
-                    m_spp_timer_handle->stop();
+                    break;
+                case 5:
+                    uart_send_data(ATCMD_POWEROFF);
+                    break;
+                default:
+                    m_cmd_index = -1;
+                    if (m_spp_timer_handle && m_spp_timer_handle->isActive()) {
+                        m_spp_timer_handle->stop();
+                    }
+                    break;
+                }
+            } else {
+                // 新流程中,只处理命令响应,不调用uart_process
+                // 状态转换由checkLogMessages()根据日志消息处理
+                qDebug() << tr("端口%1 新测试流程中,跳过uart_process,由checkLogMessages处理").arg(m_port_index + 1);
+                
+                // 新流程中,如果检测到关机命令响应,直接处理
+                if (m_uart_rx_buff_array.indexOf("power off device") >= 0) {
+                    emit displayMessage(tr("关机成功\r\n"), true);
                 }
-                break;
             }
         }
     }
@@ -519,7 +665,13 @@ void TestPortController::uart_send_data(const QString& cmd)
         m_spp_timer_handle->stop();
     }
     
-    if (cmd.contains("GETIDS")) {
+    // 对于异步测试命令(如声音测试、GPIO测试),不启动AT命令超时定时器
+    // 因为这些命令的结果通过日志异步返回,不是立即响应
+    if (cmd.contains("AUDIOTEST") || cmd.contains("GPIOTEST") || 
+        cmd.contains("BTSCANTEST") || cmd.contains("BTENABLE")) {
+        // 这些命令是异步的,结果通过日志返回,不需要等待立即响应
+        qDebug() << tr("端口%1 发送异步测试命令,不启动AT命令超时定时器: %2").arg(m_port_index + 1).arg(cmd.trimmed());
+    } else if (cmd.contains("GETIDS")) {
         m_spp_timer_handle->start(5000);
     } else if (cmd.contains("GETBTMAC")) {
         m_spp_timer_handle->start(3000);
@@ -571,6 +723,17 @@ void TestPortController::resetState()
     m_boot_detect_buffer.clear();
     m_write_success_count = 0;
     m_write_fail_count = 0;
+    
+    // 重置新测试流程状态
+    m_test_state = TEST_STATE_IDLE;
+    m_vote_retry_count = 0;
+    m_blue_color_detected = false;
+    m_last_audio_level.clear();
+    m_audio_level_count = 0;
+    m_gpio_result_detected = false;
+    m_test_result_summary.clear();
+    m_color_check_timer->stop();
+    m_audio_timeout_timer->stop();
 }
 
 void TestPortController::clearBuffers()
@@ -579,3 +742,477 @@ void TestPortController::clearBuffers()
     m_boot_detect_buffer.clear();
 }
 
+// ========== 新测试流程实现 ==========
+
+void TestPortController::processNewTestFlow()
+{
+    // 处理新测试流程的状态机
+    checkLogMessages();
+    processTestCommandResponse();
+}
+
+void TestPortController::checkLogMessages()
+{
+    // 直接在QByteArray上搜索,避免UTF-8转换问题
+    QByteArray lowerBuffer = m_boot_detect_buffer.toLower();
+    
+    // 根据当前状态检查相应的日志消息
+    switch (m_test_state) {
+    case TEST_STATE_IDLE:
+        // 空闲状态,不需要处理日志
+        break;
+        
+    case TEST_STATE_COMPLETE:
+    case TEST_STATE_FAILED:
+        // 测试完成或失败状态,不需要处理日志
+        break;
+        
+    case TEST_STATE_WAIT_VOTE_SUCCESS:
+        if (m_boot_detect_buffer.contains("MCU WAKEUP SUCCESS") || m_boot_detect_buffer.contains("OK~")) {
+            emit displayMessage(tr("投票成功\r\n"), true);
+            transitionToState(TEST_STATE_GET_CPUID);
+            sendNextTestCommand();
+        }
+        break;
+        
+    case TEST_STATE_WAIT_CPUID:
+        if (m_boot_detect_buffer.contains("OK~") && lowerBuffer.contains("nandflash id:")) {
+            emit displayMessage(tr("获取CPUID成功\r\n"), true);
+            transitionToState(TEST_STATE_GET_BT_MAC);
+            sendNextTestCommand();
+        }
+        break;
+        
+    case TEST_STATE_WAIT_BT_MAC:
+        if (m_boot_detect_buffer.contains("BTMAC=") || m_boot_detect_buffer.contains("OK~")) {
+            emit displayMessage(tr("获取蓝牙MAC成功\r\n"), true);
+            transitionToState(TEST_STATE_ENABLE_BT);
+            sendNextTestCommand();
+        }
+        break;
+        
+    case TEST_STATE_WAIT_BT_ENABLE:
+        if (lowerBuffer.contains("bt enable ok") || m_boot_detect_buffer.contains("OK~")) {
+            emit displayMessage(tr("蓝牙打开成功\r\n"), true);
+            transitionToState(TEST_STATE_START_SCAN);
+            sendNextTestCommand();
+        }
+        break;
+        
+    case TEST_STATE_WAIT_SCAN_START:
+        if (m_boot_detect_buffer.contains("Starting Bluetooth scan test") || m_boot_detect_buffer.contains("OK~")) {
+            emit displayMessage(tr("开启扫描成功\r\n"), true);
+            qDebug() << tr("端口%1 检测到扫描开始,准备启动声音测试").arg(m_port_index + 1);
+            transitionToState(TEST_STATE_AUDIO_TEST);
+            sendNextTestCommand();
+        } else {
+            // 调试:检查是否包含部分关键字
+            static int scan_check_count[4] = {0, 0, 0, 0};
+            scan_check_count[m_port_index]++;
+            if (scan_check_count[m_port_index] % 20 == 0) {
+                QString bufferStr = QString::fromLatin1(m_boot_detect_buffer.right(500));
+                qDebug() << tr("端口%1 [扫描检测] 状态=%2, 缓冲区长度=%3, 检查次数=%4, 最后500字符包含'Starting'=%5, 包含'OK~'=%6")
+                            .arg(m_port_index + 1)
+                            .arg(getStateName(m_test_state))
+                            .arg(m_boot_detect_buffer.length())
+                            .arg(scan_check_count[m_port_index])
+                            .arg(bufferStr.contains("Starting"))
+                            .arg(m_boot_detect_buffer.contains("OK~"));
+            }
+        }
+        break;
+        
+    case TEST_STATE_WAIT_AUDIO_RESULT: {
+        // 检测音量结果:需要连续接收到3次以上相同的音量Level值才算成功
+        // 从日志中可以看到格式:APP|[AudioTest] Volume - RMS: 14.35% (-16.86 dB), Peak: 33.48% (-9.50 dB), Level: 中
+        // 由于可能有二进制数据,直接在原始字节数组上搜索UTF-8字节序列,避免转换问题
+        
+        // 准备要搜索的UTF-8字节序列
+        QByteArray zhongBytes = QString("中").toUtf8();      // E4 B8 AD
+        QByteArray gaoBytes = QString("高").toUtf8();        // E9 AB 98
+        QByteArray diBytes = QString("低").toUtf8();         // E4 BD 8E
+        QByteArray jidiBytes = QString("极低").toUtf8();     // E6 9E 81 E4 BD 8E
+        QByteArray jingyinBytes = QString("静音").toUtf8(); // E9 9D 99 E9 9F B3
+        
+        // 在原始字节数组上搜索 "Level:"(不区分大小写)
+        // 从后往前搜索,找到最后一个"Level:",确保获取最新的Level值
+        QByteArray lowerBuffer = m_boot_detect_buffer.toLower();
+        int levelPos = lowerBuffer.lastIndexOf("level:");
+        
+        if (levelPos >= 0) {
+            // 找到最后一个 "Level:" 位置,在后续的字节中搜索中文字符
+            // 搜索范围:从 "Level:" 后到换行符之前(最多20字节,确保只搜索当前行的Level值)
+            int searchStart = levelPos + 6; // "level:" 长度是6
+            // 找到换行符位置(\r\n 或 \n)
+            int newlinePos = m_boot_detect_buffer.indexOf("\r\n", searchStart);
+            if (newlinePos < 0) {
+                newlinePos = m_boot_detect_buffer.indexOf("\n", searchStart);
+            }
+            if (newlinePos < 0) {
+                newlinePos = qMin(m_boot_detect_buffer.length(), searchStart + 20);
+            } else {
+                newlinePos = qMin(newlinePos, searchStart + 20); // 最多20字节
+            }
+            QByteArray searchArea = m_boot_detect_buffer.mid(searchStart, newlinePos - searchStart);
+            
+            qDebug() << tr("端口%1 [Level检测] 找到Level位置=%2, 搜索起始=%3, 换行位置=%4, 搜索区域长度=%5")
+                        .arg(m_port_index + 1)
+                        .arg(levelPos)
+                        .arg(searchStart)
+                        .arg(newlinePos)
+                        .arg(searchArea.length());
+            
+            // 直接在字节数组上搜索UTF-8字节序列
+            bool hasZhong = searchArea.contains(zhongBytes);
+            bool hasGao = searchArea.contains(gaoBytes);
+            bool hasDi = searchArea.contains(diBytes);
+            bool hasJidi = searchArea.contains(jidiBytes);
+            bool hasJingyin = searchArea.contains(jingyinBytes);
+            
+            QString currentLevel;
+            bool isValidLevel = false;
+            bool isSilent = false;
+            
+            // 确定当前Level值(优先级:中 > 高 > 低 > 极低 > 静音)
+            if (hasZhong) {
+                currentLevel = "中";
+                isValidLevel = true;
+            } else if (hasGao) {
+                currentLevel = "高";
+                isValidLevel = true;
+            } else if (hasJidi) {
+                currentLevel = "极低";
+                isValidLevel = true;
+            } else if (hasDi) {
+                currentLevel = "低";
+                isValidLevel = true;
+            } else if (hasJingyin) {
+                currentLevel = "静音";
+                isSilent = true;
+            }
+            
+            qDebug() << tr("端口%1 [Level检测] 搜索区域: %2, 包含'中'=%3, 包含'高'=%4, 包含'低'=%5, 包含'极低'=%6, 包含'静音'=%7, currentLevel='%8'")
+                        .arg(m_port_index + 1)
+                        .arg(QString::fromLatin1(searchArea.toHex(' ')))
+                        .arg(hasZhong)
+                        .arg(hasGao)
+                        .arg(hasDi)
+                        .arg(hasJidi)
+                        .arg(hasJingyin)
+                        .arg(currentLevel);
+            
+            if (isValidLevel) {
+                    // 有效的Level值(非静音)
+                    // 检查是否与上次检测到的Level值相同
+                    if (currentLevel == m_last_audio_level) {
+                        // 相同,计数器+1
+                        m_audio_level_count++;
+                        qDebug() << tr("端口%1 检测到相同有效Level: %2, 连续次数: %3")
+                                    .arg(m_port_index + 1)
+                                    .arg(currentLevel)
+                                    .arg(m_audio_level_count);
+                        
+                        // 如果连续3次以上相同,认为测试成功
+                        if (m_audio_level_count >= 3) {
+                            m_audio_timeout_timer->stop();
+                            // 关闭声音检测
+                            uart_send_data("AT^AUDIOTEST=6\r\n");
+                            emit displayMessage(tr("声音测试完成(Level: %1,连续%2次)\r\n")
+                                                  .arg(currentLevel)
+                                                  .arg(m_audio_level_count), true);
+                            transitionToState(TEST_STATE_WAIT_SCAN_END);
+                            qDebug() << tr("端口%1 声音测试成功,连续%2次检测到Level: %3")
+                                        .arg(m_port_index + 1)
+                                        .arg(m_audio_level_count)
+                                        .arg(currentLevel);
+                            // 重置计数
+                            m_last_audio_level.clear();
+                            m_audio_level_count = 0;
+                        }
+                    } else {
+                        // 不同,重置计数,更新last_level
+                        m_last_audio_level = currentLevel;
+                        m_audio_level_count = 1;
+                        qDebug() << tr("端口%1 检测到新的有效Level: %2, 重置计数为1")
+                                    .arg(m_port_index + 1)
+                                    .arg(currentLevel);
+                    }
+            } else if (isSilent) {
+                // 检测到静音,重置计数(静音不应该计入有效Level)
+                if (m_last_audio_level != "静音") {
+                    // 如果之前不是静音,重置计数
+                    m_last_audio_level.clear();
+                    m_audio_level_count = 0;
+                    qDebug() << tr("端口%1 检测到静音,重置有效Level计数").arg(m_port_index + 1);
+                }
+            }
+        }
+        break;
+    }
+        
+    case TEST_STATE_WAIT_SCAN_END:
+        if (m_boot_detect_buffer.contains("Bluetooth scan test completed") || 
+            lowerBuffer.contains("scan test end") || m_boot_detect_buffer.contains("OK~")) {
+            emit displayMessage(tr("蓝牙扫描结束\r\n"), true);
+            transitionToState(TEST_STATE_GPIO_TEST);
+            sendNextTestCommand();
+        }
+        break;
+        
+    case TEST_STATE_WAIT_GPIO_RESULT: {
+        // 检测GPIO测试完成:[GpioTest] Test finished 代表测试结束
+        // 从日志中可以看到格式:Test completed: 13 passed, 21 failed
+        // 如果检测到 "[GpioTest] Test finished" 但之前未检测到 "X passed, Y failed" 格式,算失败
+        QString bufferStr = QString::fromLatin1(m_boot_detect_buffer);
+        
+        // 首先检查是否包含 "X passed, Y failed" 格式(可能在Test finished之前出现)
+        QRegExp resultRegex("(\\d+)\\s+passed[,\\s]+(\\d+)\\s+failed");
+        if (resultRegex.indexIn(bufferStr) >= 0 && !m_gpio_result_detected) {
+            // 检测到结果格式,记录标志
+            m_gpio_result_detected = true;
+            int passed = resultRegex.cap(1).toInt();
+            int failed = resultRegex.cap(2).toInt();
+            qDebug() << tr("端口%1 检测到GPIO测试结果:%2通过,%3失败").arg(m_port_index + 1).arg(passed).arg(failed);
+        }
+        
+        // 检测是否包含 "[GpioTest] Test finished"
+        if (bufferStr.contains("[GpioTest] Test finished") || bufferStr.contains("Test finished")) {
+            m_gpio_timeout_timer->stop();
+            
+            if (m_gpio_result_detected) {
+                // 之前已经检测到结果格式,认为测试成功
+                // 重新提取结果用于显示
+                if (resultRegex.indexIn(bufferStr) >= 0) {
+                    int passed = resultRegex.cap(1).toInt();
+                    int failed = resultRegex.cap(2).toInt();
+                    emit displayMessage(tr("GPIO测试完成(%1通过,%2失败)\r\n").arg(passed).arg(failed), true);
+                } else {
+                    emit displayMessage(tr("GPIO测试完成\r\n"), true);
+                }
+                transitionToState(TEST_STATE_COMPLETE);
+                finalizeTestResult();
+            } else {
+                // 检测到 "Test finished" 但之前未检测到结果格式,认为测试失败
+                emit displayMessage(tr("GPIO测试失败:未检测到测试结果(X passed, Y failed)\r\n"), false);
+                transitionToState(TEST_STATE_FAILED);
+                finalizeTestResult();
+            }
+        }
+        // 如果没有找到 "Test finished",继续等待(超时定时器会处理失败情况)
+        break;
+    }
+        
+    default:
+        break;
+    }
+}
+
+void TestPortController::onColorCheckTimer()
+{
+    // 延迟1秒后检测颜色
+    if (m_test_state == TEST_STATE_CHECK_BLUE_COLOR) {
+        // 检查RGB串口是否检测到蓝色
+        // 这里需要通过信号连接来获取颜色信息
+        emit displayMessage(tr("开始检测LCD颜色...\r\n"), true);
+        // 颜色检测结果会通过RGB串口的信号返回
+        // 如果检测到蓝色,会调用transitionToState(TEST_STATE_SEND_VOTE)
+    }
+}
+
+void TestPortController::onAudioTimeoutTimer()
+{
+    // 声音测试超时(5秒)
+    if (m_test_state == TEST_STATE_WAIT_AUDIO_RESULT) {
+        // 检查是否已经连续检测到3次以上相同的Level值
+        if (m_audio_level_count >= 3 && !m_last_audio_level.isEmpty()) {
+            // 如果已经连续3次以上相同,直接继续下一步(不打印超时错误)
+            uart_send_data("AT^AUDIOTEST=6\r\n");  // 停止声音测试
+            emit displayMessage(tr("声音测试完成(Level: %1,连续%2次)\r\n")
+                                  .arg(m_last_audio_level)
+                                  .arg(m_audio_level_count), true);
+            transitionToState(TEST_STATE_WAIT_SCAN_END);
+            // 重置计数
+            m_last_audio_level.clear();
+            m_audio_level_count = 0;
+        } else {
+            // 超时后停止声音测试(打印超时错误)
+            uart_send_data("AT^AUDIOTEST=6\r\n");  // 停止声音测试
+            emit displayMessage(tr("声音测试超时,停止测试并继续下一步\r\n"), false);
+            transitionToState(TEST_STATE_WAIT_SCAN_END);
+            // 重置计数
+            m_last_audio_level.clear();
+            m_audio_level_count = 0;
+        }
+    }
+}
+
+void TestPortController::onGpioTimeoutTimer()
+{
+    // GPIO测试超时(10秒)
+    if (m_test_state == TEST_STATE_WAIT_GPIO_RESULT) {
+        QString bufferStr = QString::fromLatin1(m_boot_detect_buffer);
+        
+        // 检查是否已经检测到 "[GpioTest] Test finished"
+        if (bufferStr.contains("[GpioTest] Test finished") || bufferStr.contains("Test finished")) {
+            // 如果已经检测到 "Test finished",检查之前是否检测到过结果
+            if (m_gpio_result_detected) {
+                // 之前检测到过结果,认为成功
+                QRegExp resultRegex("(\\d+)\\s+passed[,\\s]+(\\d+)\\s+failed");
+                if (resultRegex.indexIn(bufferStr) >= 0) {
+                    int passed = resultRegex.cap(1).toInt();
+                    int failed = resultRegex.cap(2).toInt();
+                    emit displayMessage(tr("GPIO测试完成(%1通过,%2失败)\r\n").arg(passed).arg(failed), true);
+                } else {
+                    emit displayMessage(tr("GPIO测试完成\r\n"), true);
+                }
+                transitionToState(TEST_STATE_COMPLETE);
+                finalizeTestResult();
+            } else {
+                // 之前未检测到结果,认为失败
+                emit displayMessage(tr("GPIO测试失败:未检测到测试结果(X passed, Y failed)\r\n"), false);
+                transitionToState(TEST_STATE_FAILED);
+                finalizeTestResult();
+            }
+        } else {
+            // 超时后没有检测到 "Test finished",认为测试失败
+            emit displayMessage(tr("GPIO测试失败:超时未检测到Test finished\r\n"), false);
+            transitionToState(TEST_STATE_FAILED);
+            finalizeTestResult();
+        }
+    }
+}
+
+void TestPortController::transitionToState(TestState new_state)
+{
+    if (m_test_state != new_state) {
+        QString oldStateName = getStateName(m_test_state);
+        QString newStateName = getStateName(new_state);
+        qDebug() << tr("端口%1状态转换: %2 -> %3").arg(m_port_index + 1).arg(oldStateName).arg(newStateName);
+        m_test_state = new_state;
+        emit statusChanged(newStateName);
+    }
+}
+
+QString TestPortController::getStateName(TestState state) const
+{
+    switch (state) {
+    case TEST_STATE_IDLE: return tr("空闲");
+    case TEST_STATE_WAIT_NAND_ID: return tr("等待nand flash id");
+    case TEST_STATE_WAIT_NAND_MODEL: return tr("等待nand flash型号");
+    case TEST_STATE_WAIT_BLUE_WINDOW: return tr("等待蓝色窗口");
+    case TEST_STATE_CHECK_BLUE_COLOR: return tr("检测蓝色");
+    case TEST_STATE_SEND_VOTE: return tr("发送投票");
+    case TEST_STATE_WAIT_VOTE_SUCCESS: return tr("等待投票成功");
+    case TEST_STATE_GET_CPUID: return tr("获取CPUID");
+    case TEST_STATE_WAIT_CPUID: return tr("等待CPUID");
+    case TEST_STATE_GET_BT_MAC: return tr("获取蓝牙MAC");
+    case TEST_STATE_WAIT_BT_MAC: return tr("等待蓝牙MAC");
+    case TEST_STATE_ENABLE_BT: return tr("打开蓝牙");
+    case TEST_STATE_WAIT_BT_ENABLE: return tr("等待蓝牙打开");
+    case TEST_STATE_START_SCAN: return tr("开启扫描");
+    case TEST_STATE_WAIT_SCAN_START: return tr("等待开启扫描");
+    case TEST_STATE_AUDIO_TEST: return tr("声音测试");
+    case TEST_STATE_WAIT_AUDIO_RESULT: return tr("等待音量结果");
+    case TEST_STATE_WAIT_SCAN_END: return tr("等待扫描结束");
+    case TEST_STATE_GPIO_TEST: return tr("GPIO测试");
+    case TEST_STATE_WAIT_GPIO_RESULT: return tr("等待GPIO结果");
+    case TEST_STATE_COMPLETE: return tr("测试完成");
+    case TEST_STATE_FAILED: return tr("测试失败");
+    default: return tr("未知状态");
+    }
+}
+
+void TestPortController::processTestCommandResponse()
+{
+    // 处理测试指令响应
+    // 这个函数会在readData中被调用,检查响应缓冲区
+}
+
+void TestPortController::sendNextTestCommand()
+{
+    // 根据当前状态发送下一个测试指令
+    switch (m_test_state) {
+    case TEST_STATE_SEND_VOTE:
+        // 发送投票指令(可以重试2-4次)
+        if (m_vote_retry_count < 4) {
+            m_vote_retry_count++;
+            uart_send_data(ATCMD_ADD_VOTE);
+            transitionToState(TEST_STATE_WAIT_VOTE_SUCCESS);
+            emit displayMessage(tr("发送投票指令(第%1次)\r\n").arg(m_vote_retry_count), true);
+        } else {
+            emit displayMessage(tr("投票失败,已达到最大重试次数\r\n"), false);
+            transitionToState(TEST_STATE_FAILED);
+        }
+        break;
+        
+    case TEST_STATE_GET_CPUID:
+        uart_send_data(ATCMD_GET_CPUID);
+        transitionToState(TEST_STATE_WAIT_CPUID);
+        break;
+        
+    case TEST_STATE_GET_BT_MAC:
+        uart_send_data(ATCMD_GET_MAC);
+        transitionToState(TEST_STATE_WAIT_BT_MAC);
+        break;
+        
+    case TEST_STATE_ENABLE_BT:
+        // 需要添加ATCMD_ENABLE_BT定义
+        uart_send_data("AT^BTENABLE\r\n");
+        transitionToState(TEST_STATE_WAIT_BT_ENABLE);
+        break;
+        
+    case TEST_STATE_START_SCAN:
+        uart_send_data("AT^BTSCANTEST=1\r\n");
+        transitionToState(TEST_STATE_WAIT_SCAN_START);
+        break;
+        
+    case TEST_STATE_AUDIO_TEST:
+        // 声音测试指令:AT^AUDIOTEST=5 启动测试
+        qDebug() << tr("端口%1 发送声音测试指令: AT^AUDIOTEST=5").arg(m_port_index + 1);
+        // 重置音量Level计数
+        m_last_audio_level.clear();
+        m_audio_level_count = 0;
+        uart_send_data("AT^AUDIOTEST=5\r\n");
+        transitionToState(TEST_STATE_WAIT_AUDIO_RESULT);
+        // 启动5秒超时定时器
+        m_audio_timeout_timer->start(5000);
+        qDebug() << tr("端口%1 声音测试指令已发送,状态已转换为等待结果,超时定时器已启动").arg(m_port_index + 1);
+        break;
+        
+    case TEST_STATE_GPIO_TEST:
+        // GPIO测试指令:AT^GPIOTEST=2 启动测试
+        uart_send_data("AT^GPIOTEST=2\r\n");
+        transitionToState(TEST_STATE_WAIT_GPIO_RESULT);
+        // 重置GPIO结果检测标志
+        m_gpio_result_detected = false;
+        // 启动GPIO测试超时定时器(10秒)
+        m_gpio_timeout_timer->start(10000);
+        qDebug() << tr("端口%1 GPIO测试指令已发送,启动10秒超时定时器").arg(m_port_index + 1);
+        break;
+        
+    default:
+        break;
+    }
+}
+
+void TestPortController::finalizeTestResult()
+{
+    // 统计所有测试结果
+    m_test_result_summary = tr("测试完成\r\n");
+    m_test_result_summary += tr("成功: %1\r\n").arg(m_write_success_count);
+    m_test_result_summary += tr("失败: %1\r\n").arg(m_write_fail_count);
+    
+    emit displayMessage(m_test_result_summary, m_write_fail_count == 0);
+    
+    if (m_write_fail_count == 0) {
+        emit showResult(tr("所有测试通过"), true);
+        m_write_success_count++;
+    } else {
+        emit showResult(tr("测试失败"), false);
+        m_write_fail_count++;
+    }
+    
+    emit successCountChanged(m_write_success_count);
+    emit failCountChanged(m_write_fail_count);
+}
+
index 6e21501..d468f80 100644 (file)
@@ -87,6 +87,43 @@ private:
     qint64 m_bytesToWrite;           // 指令长度
     int m_cmd_index;                  // 指令顺序: 0=AT投票, 1=GET_MAC, 2=SET_MAC, 3=GET_MAC验证, 4=GET_CPUID, 5=POWEROFF
     QString m_G_cmd;                  // 当前执行的AT命令
+    
+    // 新的测试流程状态
+    enum TestState {
+        TEST_STATE_IDLE = 0,              // 空闲状态
+        TEST_STATE_WAIT_NAND_ID,          // 等待nand flash id
+        TEST_STATE_WAIT_NAND_MODEL,       // 等待nand flash型号
+        TEST_STATE_WAIT_BLUE_WINDOW,      // 等待蓝色窗口
+        TEST_STATE_CHECK_BLUE_COLOR,      // 检测蓝色(延迟1s)
+        TEST_STATE_SEND_VOTE,             // 发送投票指令
+        TEST_STATE_WAIT_VOTE_SUCCESS,     // 等待投票成功
+        TEST_STATE_GET_CPUID,             // 获取CPUID
+        TEST_STATE_WAIT_CPUID,            // 等待CPUID
+        TEST_STATE_GET_BT_MAC,            // 获取蓝牙MAC
+        TEST_STATE_WAIT_BT_MAC,           // 等待蓝牙MAC
+        TEST_STATE_ENABLE_BT,             // 打开蓝牙
+        TEST_STATE_WAIT_BT_ENABLE,        // 等待蓝牙打开成功
+        TEST_STATE_START_SCAN,            // 开启扫描
+        TEST_STATE_WAIT_SCAN_START,       // 等待开启扫描
+        TEST_STATE_AUDIO_TEST,            // 执行声音测试
+        TEST_STATE_WAIT_AUDIO_RESULT,     // 等待音量结果(3-5秒超时)
+        TEST_STATE_WAIT_SCAN_END,         // 等待蓝牙扫描结束
+        TEST_STATE_GPIO_TEST,             // 执行GPIO测试
+        TEST_STATE_WAIT_GPIO_RESULT,      // 等待GPIO测试结果
+        TEST_STATE_COMPLETE,              // 测试完成
+        TEST_STATE_FAILED                 // 测试失败
+    };
+    
+    TestState m_test_state;           // 当前测试状态
+    int m_vote_retry_count;           // 投票重试次数(最多4次)
+    QTimer *m_color_check_timer;      // 颜色检测定时器(延迟1s)
+    QTimer *m_audio_timeout_timer;    // 声音测试超时定时器(3-5秒)
+    QTimer *m_gpio_timeout_timer;     // GPIO测试超时定时器
+    bool m_blue_color_detected;        // 蓝色是否已检测
+    QString m_test_result_summary;     // 测试结果汇总
+    QString m_last_audio_level;        // 上次检测到的音量Level值
+    int m_audio_level_count;           // 连续相同Level的计数
+    bool m_gpio_result_detected;       // GPIO测试结果是否已检测到(X passed, Y failed)
 
     // 状态标志
     bool m_working_state;             // true=写号执行中, false=写号结束
@@ -114,6 +151,18 @@ private:
     void spp_timer_callback();
     void resetState();
     void clearBuffers();
+    
+    // 新测试流程相关函数
+    void processNewTestFlow();                    // 处理新测试流程
+    void checkLogMessages();                      // 检查日志消息
+    void onColorCheckTimer();                     // 颜色检测定时器回调
+    void onAudioTimeoutTimer();                   // 声音测试超时定时器回调
+    void onGpioTimeoutTimer();                    // GPIO测试超时定时器回调
+    void transitionToState(TestState new_state);   // 状态转换
+    QString getStateName(TestState state) const;  // 获取状态名称
+    void processTestCommandResponse();             // 处理测试指令响应
+    void sendNextTestCommand();                    // 发送下一个测试指令
+    void finalizeTestResult();                     // 完成测试结果统计
 };
 
 #endif // TEST_PORT_CONTROLLER_H
diff --git a/测试流程指令顺序分析.md b/测试流程指令顺序分析.md
new file mode 100644 (file)
index 0000000..ed351a8
--- /dev/null
@@ -0,0 +1,338 @@
+# 测试流程指令顺序分析\r
+\r
+## 测试流程状态机执行顺序\r
+\r
+### 初始状态\r
+- **状态**: `TEST_STATE_WAIT_NAND_ID` (等待nand flash id)\r
+- **触发**: `connectPort()` 函数调用时初始化\r
+- **显示**: "等待设备启动..."\r
+\r
+---\r
+\r
+### 步骤1: 检测 NAND Flash ID\r
+- **状态**: `TEST_STATE_WAIT_NAND_ID`\r
+- **检测位置**: `readData()` 函数 (行302-357)\r
+- **检测内容**: \r
+  - 日志关键字: `"find nand flash chip id"` 或 `"nand flash chip id"`\r
+  - 提取ID格式: `0xXXXX` (4位十六进制)\r
+- **检测方法**: \r
+  - 在 `QByteArray` 上直接搜索(不区分大小写)\r
+  - 使用正则表达式或简单匹配提取ID\r
+- **成功动作**:\r
+  - 清空显示窗口\r
+  - 显示: "=== 新一轮检测开始 ==="\r
+  - 显示: "✓ 检测到nand flash id: 0xXXXX"\r
+  - 状态转换: `TEST_STATE_WAIT_NAND_MODEL`\r
+\r
+---\r
+\r
+### 步骤2: 检测 NAND Flash 型号\r
+- **状态**: `TEST_STATE_WAIT_NAND_MODEL`\r
+- **检测位置**: `readData()` 函数 (行360-387)\r
+- **检测内容**: \r
+  - 日志关键字: `"nand flash"` + `"start init"` 或 `" init"`\r
+  - 提取型号: 例如 `XT26Q02D`\r
+- **检测方法**: \r
+  - 正则表达式: `"nand flash\\s+([A-Z0-9]+)\\s+start init"` 或 `"nand flash\\s+([A-Z0-9]+)"`\r
+- **成功动作**:\r
+  - 显示: "✓ 检测到nand flash型号: XT26Q02D"\r
+  - 状态转换: `TEST_STATE_WAIT_BLUE_WINDOW`\r
+\r
+---\r
+\r
+### 步骤3: 检测蓝色窗口创建\r
+- **状态**: `TEST_STATE_WAIT_BLUE_WINDOW`\r
+- **检测位置**: `readData()` 函数 (行389-399)\r
+- **检测内容**: \r
+  - 日志关键字: `"Blue window created and displayed:"`\r
+- **成功动作**:\r
+  - 显示: "✓ 检测到蓝色窗口已创建"\r
+  - 状态转换: `TEST_STATE_CHECK_BLUE_COLOR`\r
+  - 启动1秒延迟定时器 (`m_color_check_timer->start(1000)`)\r
+\r
+---\r
+\r
+### 步骤4: 检测LCD蓝色(RGB传感器)\r
+- **状态**: `TEST_STATE_CHECK_BLUE_COLOR`\r
+- **检测位置**: RGB串口信号回调 (行59-65)\r
+- **检测内容**: \r
+  - RGB传感器检测到颜色名称包含 "蓝色"\r
+  - 通过 `RgbSerialReader::rgbcDataParsedWithColor` 信号触发\r
+- **成功动作**:\r
+  - 显示: "LCD颜色检测通过(蓝色)"\r
+  - 状态转换: `TEST_STATE_SEND_VOTE`\r
+  - 重置投票重试计数: `m_vote_retry_count = 0`\r
+  - 调用 `sendNextTestCommand()`\r
+\r
+---\r
+\r
+### 步骤5: 发送投票指令\r
+- **状态**: `TEST_STATE_SEND_VOTE`\r
+- **执行位置**: `sendNextTestCommand()` 函数 (行882-893)\r
+- **发送指令**: `ATCMD_ADD_VOTE` (`"AT^PMADDVOTE\r\n"`)\r
+- **重试机制**: \r
+  - 最多重试4次 (`m_vote_retry_count < 4`)\r
+  - 每次重试递增计数\r
+- **超时设置**: 1.5秒 (在 `uart_send_data()` 中设置)\r
+- **超时处理**: 如果超时,自动重发投票指令 (行669-670)\r
+- **成功动作**:\r
+  - 显示: "发送投票指令(第X次)"\r
+  - 状态转换: `TEST_STATE_WAIT_VOTE_SUCCESS`\r
+- **失败动作**:\r
+  - 如果达到最大重试次数,显示: "投票失败,已达到最大重试次数"\r
+  - 状态转换: `TEST_STATE_FAILED`\r
+\r
+---\r
+\r
+### 步骤6: 检测投票成功\r
+- **状态**: `TEST_STATE_WAIT_VOTE_SUCCESS`\r
+- **检测位置**: `checkLogMessages()` 函数 (行734-739)\r
+- **检测内容**: \r
+  - 日志关键字: `"MCU WAKEUP SUCCESS"` 或 `"OK~"`\r
+- **成功动作**:\r
+  - 显示: "投票成功"\r
+  - 状态转换: `TEST_STATE_GET_CPUID`\r
+  - 调用 `sendNextTestCommand()`\r
+\r
+---\r
+\r
+### 步骤7: 获取CPUID\r
+- **状态**: `TEST_STATE_GET_CPUID`\r
+- **执行位置**: `sendNextTestCommand()` 函数 (行895-898)\r
+- **发送指令**: `ATCMD_GET_CPUID` (`"AT^GETIDS\r\n"`)\r
+- **超时设置**: 5秒\r
+- **成功动作**:\r
+  - 状态转换: `TEST_STATE_WAIT_CPUID`\r
+\r
+---\r
+\r
+### 步骤8: 检测CPUID响应\r
+- **状态**: `TEST_STATE_WAIT_CPUID`\r
+- **检测位置**: `checkLogMessages()` 函数 (行742-747)\r
+- **检测内容**: \r
+  - 日志关键字: `"OK~"` 且 `"nandflash id:"`\r
+- **成功动作**:\r
+  - 显示: "获取CPUID成功"\r
+  - 状态转换: `TEST_STATE_GET_BT_MAC`\r
+  - 调用 `sendNextTestCommand()`\r
+\r
+---\r
+\r
+### 步骤9: 获取蓝牙MAC地址\r
+- **状态**: `TEST_STATE_GET_BT_MAC`\r
+- **执行位置**: `sendNextTestCommand()` 函数 (行900-903)\r
+- **发送指令**: `ATCMD_GET_MAC` (`"AT^GETBTMAC\r\n"`)\r
+- **超时设置**: 3秒\r
+- **成功动作**:\r
+  - 状态转换: `TEST_STATE_WAIT_BT_MAC`\r
+\r
+---\r
+\r
+### 步骤10: 检测蓝牙MAC响应\r
+- **状态**: `TEST_STATE_WAIT_BT_MAC`\r
+- **检测位置**: `checkLogMessages()` 函数 (行750-755)\r
+- **检测内容**: \r
+  - 日志关键字: `"BTMAC="` 或 `"OK~"`\r
+- **成功动作**:\r
+  - 显示: "获取蓝牙MAC成功"\r
+  - 状态转换: `TEST_STATE_ENABLE_BT`\r
+  - 调用 `sendNextTestCommand()`\r
+\r
+---\r
+\r
+### 步骤11: 打开蓝牙\r
+- **状态**: `TEST_STATE_ENABLE_BT`\r
+- **执行位置**: `sendNextTestCommand()` 函数 (行905-909)\r
+- **发送指令**: `"AT^BTENABLE\r\n"`\r
+- **超时设置**: 1.5秒\r
+- **成功动作**:\r
+  - 状态转换: `TEST_STATE_WAIT_BT_ENABLE`\r
+\r
+---\r
+\r
+### 步骤12: 检测蓝牙打开成功\r
+- **状态**: `TEST_STATE_WAIT_BT_ENABLE`\r
+- **检测位置**: `checkLogMessages()` 函数 (行758-763)\r
+- **检测内容**: \r
+  - 日志关键字: `"bt enable ok"` (不区分大小写) 或 `"OK~"`\r
+- **成功动作**:\r
+  - 显示: "蓝牙打开成功"\r
+  - 状态转换: `TEST_STATE_START_SCAN`\r
+  - 调用 `sendNextTestCommand()`\r
+\r
+---\r
+\r
+### 步骤13: 开启蓝牙扫描\r
+- **状态**: `TEST_STATE_START_SCAN`\r
+- **执行位置**: `sendNextTestCommand()` 函数 (行911-914)\r
+- **发送指令**: `"AT^BTSCANTEST=1\r\n"`\r
+- **超时设置**: 1.5秒\r
+- **成功动作**:\r
+  - 状态转换: `TEST_STATE_WAIT_SCAN_START`\r
+\r
+---\r
+\r
+### 步骤14: 检测扫描启动成功\r
+- **状态**: `TEST_STATE_WAIT_SCAN_START`\r
+- **检测位置**: `checkLogMessages()` 函数 (行766-771)\r
+- **检测内容**: \r
+  - 日志关键字: `"Starting Bluetooth scan test"` 或 `"OK~"`\r
+- **成功动作**:\r
+  - 显示: "开启扫描成功"\r
+  - 状态转换: `TEST_STATE_AUDIO_TEST`\r
+  - 调用 `sendNextTestCommand()`\r
+\r
+---\r
+\r
+### 步骤15: 执行声音测试\r
+- **状态**: `TEST_STATE_AUDIO_TEST`\r
+- **执行位置**: `sendNextTestCommand()` 函数 (行916-922)\r
+- **发送指令**: `"AT^AUDIOTEST\r\n"` (假设的指令,需要确认实际指令)\r
+- **超时设置**: 1.5秒\r
+- **超时定时器**: 启动5秒超时定时器 (`m_audio_timeout_timer->start(5000)`)\r
+- **成功动作**:\r
+  - 状态转换: `TEST_STATE_WAIT_AUDIO_RESULT`\r
+\r
+---\r
+\r
+### 步骤16: 检测音量结果\r
+- **状态**: `TEST_STATE_WAIT_AUDIO_RESULT`\r
+- **检测位置**: `checkLogMessages()` 函数 (行774-787)\r
+- **检测内容**: \r
+  - 日志关键字: `"音量"` 或 `"volume"` 或 `"高"` 或 `"中"` 或 `"低"` 或 `"极低"`\r
+  - 使用 `QString::fromLatin1()` 转换缓冲区以支持中文搜索\r
+- **超时处理**: \r
+  - 如果5秒内未检测到结果,`onAudioTimeoutTimer()` 回调触发\r
+  - 显示: "声音测试超时,继续下一步"\r
+  - 状态转换: `TEST_STATE_WAIT_SCAN_END`\r
+- **成功动作**:\r
+  - 停止超时定时器\r
+  - 显示: "声音测试完成"\r
+  - 状态转换: `TEST_STATE_WAIT_SCAN_END`\r
+\r
+---\r
+\r
+### 步骤17: 检测蓝牙扫描结束\r
+- **状态**: `TEST_STATE_WAIT_SCAN_END`\r
+- **检测位置**: `checkLogMessages()` 函数 (行789-795)\r
+- **检测内容**: \r
+  - 日志关键字: `"Bluetooth scan test completed"` 或 `"scan test end"` (不区分大小写) 或 `"OK~"`\r
+- **成功动作**:\r
+  - 显示: "蓝牙扫描结束"\r
+  - 状态转换: `TEST_STATE_GPIO_TEST`\r
+  - 调用 `sendNextTestCommand()`\r
+\r
+---\r
+\r
+### 步骤18: 执行GPIO测试\r
+- **状态**: `TEST_STATE_GPIO_TEST`\r
+- **执行位置**: `sendNextTestCommand()` 函数 (行924-928)\r
+- **发送指令**: `"AT^GPIOTEST\r\n"` (假设的指令,需要确认实际指令)\r
+- **超时设置**: 1.5秒\r
+- **成功动作**:\r
+  - 状态转换: `TEST_STATE_WAIT_GPIO_RESULT`\r
+\r
+---\r
+\r
+### 步骤19: 检测GPIO测试结果\r
+- **状态**: `TEST_STATE_WAIT_GPIO_RESULT`\r
+- **检测位置**: `checkLogMessages()` 函数 (行798-804)\r
+- **检测内容**: \r
+  - 日志关键字: `"gpio test"` (不区分大小写) 或 `"OK~"`\r
+- **成功动作**:\r
+  - 显示: "GPIO测试完成"\r
+  - 状态转换: `TEST_STATE_COMPLETE`\r
+  - 调用 `finalizeTestResult()`\r
+\r
+---\r
+\r
+### 步骤20: 完成测试并统计结果\r
+- **状态**: `TEST_STATE_COMPLETE`\r
+- **执行位置**: `finalizeTestResult()` 函数 (行935-954)\r
+- **统计内容**:\r
+  - 成功计数: `m_write_success_count`\r
+  - 失败计数: `m_write_fail_count`\r
+- **显示内容**:\r
+  - "测试完成"\r
+  - "成功: X"\r
+  - "失败: Y"\r
+- **结果判断**:\r
+  - 如果 `m_write_fail_count == 0`: 显示 "所有测试通过" (成功)\r
+  - 否则: 显示 "测试失败" (失败)\r
+- **更新计数**: 根据结果更新成功或失败计数\r
+\r
+---\r
+\r
+## 关键函数说明\r
+\r
+### 1. `readData()` (行230-489)\r
+- **作用**: 接收DUT串口数据,检测启动日志(flash id、型号、蓝色窗口)\r
+- **调用时机**: DUT串口有数据到达时 (`onReadyRead()`)\r
+- **主要检测**: \r
+  - NAND Flash ID (行302-357)\r
+  - NAND Flash 型号 (行360-387)\r
+  - 蓝色窗口 (行389-399)\r
+- **然后调用**: `checkLogMessages()` 处理其他日志消息\r
+\r
+### 2. `checkLogMessages()` (行723-809)\r
+- **作用**: 根据当前测试状态检查相应的日志消息\r
+- **调用时机**: `readData()` 中,当 `m_test_state != TEST_STATE_IDLE` 时\r
+- **检测内容**: 根据状态机当前状态检测对应的日志关键字\r
+\r
+### 3. `sendNextTestCommand()` (行878-933)\r
+- **作用**: 根据当前测试状态发送下一个AT命令\r
+- **调用时机**: \r
+  - 检测到日志消息后自动调用\r
+  - 状态转换到需要发送命令的状态时\r
+- **发送指令**: 根据状态发送相应的AT命令\r
+\r
+### 4. `uart_send_data()` (行633-653)\r
+- **作用**: 发送AT命令到DUT串口\r
+- **超时设置**: \r
+  - GETIDS: 5秒\r
+  - GETBTMAC: 3秒\r
+  - 其他: 1.5秒\r
+- **超时处理**: `spp_timer_callback()` 函数处理超时\r
+\r
+### 5. `transitionToState()` (行832-841)\r
+- **作用**: 状态转换,更新UI状态显示\r
+- **调用时机**: 检测到日志消息或命令响应后\r
+\r
+---\r
+\r
+## 数据流说明\r
+\r
+### 缓冲区管理\r
+1. **`m_boot_detect_buffer`**: 开机检测数据缓存\r
+   - 最大16KB,超过时智能截断(保留flash信息)\r
+   - 用于检测启动日志\r
+\r
+2. **`m_uart_rx_buff_array`**: AT命令响应缓冲区\r
+   - 用于接收AT命令的响应数据\r
+   - 检测结束标志: `"OK~"`, `"power off device!"`, `"DSP0 power down"`\r
+\r
+### 编码处理\r
+- **问题**: 缓冲区可能包含非UTF-8数据(乱码/二进制)\r
+- **解决方案**: \r
+  - 在 `QByteArray` 上直接搜索(`indexOf()`, `contains()`)\r
+  - 需要字符串匹配时使用 `QString::fromLatin1()` 转换\r
+\r
+---\r
+\r
+## 注意事项\r
+\r
+1. **投票指令重试**: 最多4次,每次超时自动重发\r
+2. **声音测试超时**: 5秒超时,超时后继续下一步\r
+3. **颜色检测**: 通过RGB串口传感器检测,延迟1秒后检测\r
+4. **状态转换**: 所有状态转换都会更新UI状态显示\r
+5. **错误处理**: 投票失败会转换到 `TEST_STATE_FAILED` 状态\r
+\r
+---\r
+\r
+## 待确认的指令\r
+\r
+1. **声音测试指令**: `"AT^AUDIOTEST\r\n"` (行918) - 需要确认实际指令\r
+2. **GPIO测试指令**: `"AT^GPIOTEST\r\n"` (行926) - 需要确认实际指令\r
+\r
+这些指令在代码中标记为"假设的指令",需要根据实际设备协议确认。\r
+\r