架构设计完毕,统一走TestPortController,4个设备独立。
authorSnickerSun <snickersun@163.com>
Fri, 28 Nov 2025 12:13:16 +0000 (20:13 +0800)
committerSnickerSun <snickersun@163.com>
Fri, 28 Nov 2025 12:13:16 +0000 (20:13 +0800)
HiBTMacWriteTool.pro
Setting.ini
docs/m1_产测日志.txt [new file with mode: 0644]
mainwindow.cpp
mainwindow.h
mainwindow.ui
test_port_controller.cpp [new file with mode: 0644]
test_port_controller.h [new file with mode: 0644]

index 6ac13f3..be0c714 100644 (file)
@@ -19,7 +19,8 @@ SOURCES += main.cpp\
     custom.cpp \
     sqldbmanager.cpp \
     settings.cpp \
-    dialogsettings.cpp
+    dialogsettings.cpp \
+    test_port_controller.cpp
 
 HEADERS  += mainwindow.h \
     mythread.h \
@@ -28,7 +29,8 @@ HEADERS  += mainwindow.h \
     custom.h \
     sqldbmanager.h \
     settings.h \
-    dialogsettings.h
+    dialogsettings.h \
+    test_port_controller.h
 
 #HEADERS  +=  ui_mac_settings.h \
 #    ui_mainwindow.h
index 02406f5..7436ea5 100644 (file)
@@ -1,6 +1,6 @@
 [Uart_setting]\r
 uart_com=COM8\r
-uart_baud=18\r
+uart_baud=11\r
 spp_addr=\r
 \r
 [Download_Setting]\r
diff --git a/docs/m1_产测日志.txt b/docs/m1_产测日志.txt
new file mode 100644 (file)
index 0000000..9097b46
--- /dev/null
@@ -0,0 +1,477 @@
+eg info:int en:0,int:0,int sts:0.\r
+APP|int clr:0,clr sts:0,int set:0.\r
+APP|pmu_power_on_init begin\r
+APP|pmu_power_�n_init end\r
+chip temperature=25.000000(tmp=1770)\r
+APP|Flash id is 186585, init success\r
+APP|entering NormalMode\r
+APP|partition init success\r
+APP|upg init success\r
+[osal_msg_queue_create:25]:qName:nv_write_task qID=0x0 \r
+APP|calibration nv is not active\r
+\r
+cpu 0 entering scheduler\r
+app_init start ok\r
+APP|thread_main start \r
+APP|find nand flash chip id: 0x0B52\r
+APP|nand flash XT26Q02D start init\r
+APP|\r
+nandflash init start.\r
+APP|xt26q02d_init \r
+APP|nandflash A0 Reg:0x0 \r
+APP|nandflash B0 Reg:0x11 \r
+APP|nandflash C0 Reg:0x2 \r
+APP|\r
+nandflash_qspi_init success\r
+APP|\r
+ nandflash init end.\r
+APP|nandflash init success\r
+APP|Succ read lcd id! Lcd id: 0x5598\r
+get nv local_addr : ******68663c\r
+CALLENDAR:year = 1970, month = 1, day = 1, hour = 0, minute = 0, second = 0 \r
+callendar timestamp = 0 \r
+sync time timestamp 0, timezone_in_quarters 0 \r
+[A][aw88082_i2c_init:353]aw88082 i2c init success\r
+[osal_msg_queue_create:25]:qName:sap_msg qID=0x1 \r
+APP|audio init OK\r
+APP|**********startup info**********\r
+APP|os init class is liteos.\r
+APP|store init class is nandflash.\r
+APP|display init class is MIPI.\r
+APP|board init class is E0B4.\r
+APP|psram density is 32MB.\r
+APP|**********startup info**********\r
+APP|No need to upgrade...\r
+[osal_msg_queue_create:25]:qName:at_queue qID=0x2 \r
+[osal_msg_queue_create:25]:qName:graphic_at_service_queue qID=0x3 \r
+[osal_msg_queue_create:25]:qName:app_at_service_queue qID=0x4 \r
+[osal_msg_queue_create:25]:qName:audio_at_service_queue qID=0x5 \r
+[osal_msg_queue_create:25]:qName:bt_cmd_queue qID=0x6 \r
+[osal_msg_queue_create:25]:qName:media_at_service_queue qID=0x7 \r
+[osal_msg_queue_create:25]:qName:dfx_msg qID=0x8 \r
+[osal_msg_queue_create:25]:qName:transmit qID=0x9 \r
+APP|Turning on LCD backlight...\r
+kvPath: /kvstore\r
+dataPath: \r
+Set value ret: -1\r
+brightness:0\r
+Brightness: 0% → Fall Edge: 7 → LED Current: 2.5mA\r
+APP|LCD backlight turned on (CUSTOM_UTILS + BOARD_LEINIAO)\r
+[DISPLAY I/] GrallocInitialize: gralloc initialize success\r
+[DISPLAY I/] LayerInitialize: layer initialize success\r
+[DISPLAY I/] PrintLayerInfo: layerInfo:\r
+[DISPLAY I/] PrintLayerInfo: type = 0\r
+[DISPLAY I/] PrintLayerInfo: width = 360\r
+[DISPLAY I/] PrintLayerInfo: height = 360\r
+[DISPLAY I/] PrintLayerInfo: bpp = 24\r
+[DISPLAY I/] PrintLayerInfo: pixFormat = 17\r
+[DISPLAY I/] VGUInitialize: VGU initializes successfully\r
+[DISPLAY I/] InitMemPool: Memory Pool has been inited.\r
+[DISPLAY I/] GrallocInitialize: gralloc initialize success\r
+====InitDfxCmd===\r
+[Graphic Error] [ResumeSlice: 225]No valid slice to resume\r
+APP|[POWER_MANAGER E/] filter_timer_execute_system_rule: filter timer, current default timeout:5000, keepon time:25000, event:5.\r
+APP|No need to upgrade...\r
+APP|SET DSP freq=3, div=6, codec freq=3, div=36\r
+[VAU_ERROR][vau_api_check_surface 108]input phy_addr is null!\r
+[VAU_ERROR][vau_api_check_surface_list 144]vau check src surface[0] failed!\r
+[VAU_ERROR][uapi_vau_compose 861]call vau_check_surface_list fail ret = 0x80004000!\r
+[DISPLAY E/] BlitMultiImgOnce: uapi_vau_compose failure, ret = 0x80004000!\r
+[DISPLAY E/] BlitMultiImgOnce: src[0] w:360 h:360 str:1472 fmt:0 cmp:0 rect:[0,0,360,360] outRect:[0,0,360,360]\r
+[Graphic Error] [BlitImages: 889]RenderBlit failed!\r
+[A][ALERT][sys_cmd_check_cmd_done:164] wait_time_us = 600\r
+[A][ALERT][drv_sys_pon:297] DSP0 power on\r
+APP|lwip_main run start.\r
+APP|audio manager init ok\r
+APP|app_main run start.\r
+[osal_msg_queue_create:25]:qName:app_queue qID=0xb \r
+APP|uapi_battery_init !\r
+[osal_msg_queue_create:25]:qName:battery_queue qID=0xc \r
+APP|charger not plugged ,disable charge !\r
+[WEARABLE E/] GetFeatureApi failed\r
+APP|charger not plugged ,disable charge !\r
+[WEARABLE E/] GetFeatureApi failed\r
+APP|uapi_custom_cmd_service_init !\r
+[osal_msg_queue_create:25]:qName:custom_cmd_service_queue qID=0xd \r
+APP|uapi_custom_fileoperate_service_init !\r
+[osal_msg_queue_create:25]:qName:custom_fileoperate_service_queue qID=0xe \r
+APP|No need to upgrade...\r
+[WEARABLE I/] InitBroadcastService start!\r
+[WEARABLE I/] start! topicSubscriberInfo=0x0x6c104e68\r
+[WEARABLE I/] InitBroadcastService end!\r
+[WEARABLE E/] LoadManagementFromFile open fail\r
+[WEARABLE E/] SaveManagementToFile open fail\r
+I ams starts successfully\r
+I bms starts successfully\r
+[00:00:01:747][I][Init:37]Locator service starts successfully \r
+[00:00:01:749][D][Init:56][SERVICE:sensor_service]: Init begin \r
+[WEARABLE I/] WatchConnectCmdRegister\r
+I ams feature init success\r
+I [BMS] bms feature init success\r
+[00:00:01:752][I][Init:56]Locator feature init success \r
+[00:00:01:753][D][GetTaskConfig:80][SERVICE:sensor_service]: GetTaskConfig begin \r
+[WEARABLE I/] BroadcastService featureId=4294967295, queueId=536924516, serviceId=2\r
+[WEARABLE I/] BroadcastFeature featureId=0, queueId=536924516, serviceId=2\r
+E Fail to open dir:/user/dialpubkey!\r
+E Failed to create file\r
+E Public key write failed!\r
+[WEARABLE I/] NativeAbility InstallAbility\r
+D MemUtils::InitPSRam g_psramMemory = 6c200000\r
+[WEARABLE I/] InitNativeLauncher: Minimal startup - Blue window only\r
+[WEARABLE I/] Cleared all existing views from RootView\r
+[WEARABLE I/] Blue window created and displayed: 360x360\r
+I AbilityMgrSliteFeature::OnFeatureInitialize featureId = 0, queueId = 536924708, serviceId = 6\r
+[WEARABLE I/] NativeAbility OnActive\r
+[WEARABLE E/] NativeAbility ResumeAbility 0 failed\r
+I BundleMgrService::ServiceMessageHandle\r
+[00:00:02:527][I][OnFeatureInitialize:85]Locator feature init \r
+[00:00:02:528][I][InitAbility:84]initAbility start \r
+[00:00:02:529][I][Initialize:71]ability constructed. \r
+[00:00:02:530][E][InitAbility:90]Initialize gps ability, result 1 \r
+[00:00:02:531][I][Initialize:54]LocatorAbility Initialize. \r
+[00:00:02:532][I][OnFeatureInitialize:89]LocatorAbility initialize success \r
+APP|[POWER_MANAGER E/] filter_timer_execute_system_rule: filter timer, current default timeout:5000, keepon time:0, event:5.\r
+[00:00:02:538][D][Initialize:62][SERVICE:sensor_service]: Initialize begin \r
+[00:00:02:540][D][NewSensorInterfaceInstance:47]Get sensor device instance success \r
+[A][ALERT][sys_cmd_check_cmd_done:164] wait_time_us = 900\r
+[A][ALERT][drv_sys_pd:331] DSP0 power down\r
+APP|app_main run start.\r
+APP|sys_slp: 0x1\r
+» AT^PMADDVOTE\r
+» AT^PMADDVOTE\r
+« MCU has got pm_id_debug vote\r
+\r
+MCU WAKEUP SUCCESS\r
+\r
+OK~\r
+[Graphic Error] [PauseSlice: 236]No valid slice to pause\r
+APP|uapi_lcd_backlight_off\r
+Output RESET_LCD_GPIO 1 , VCI_LCD_GPIO 0\r
+APP|app_main run start.\r
+APP|sys_slp: 0x1\r
+» AT^GETIDS\r
+« [nandflash id:] b52\r
+[norflash id:] 186585\r
+[sdk id:]1.0.9 \r
+[soc id:]\r
+0x5DD4  0x5790  0xD300  0x23C2  \r
+0xC2D7  0xEF08  0x030A  0x0F78  \r
+0x81C1  0x0001  \r
+\r
+OK~\r
+» AT^GETBTMAC\r
+« get nv local_addr : ******68663c\r
+fac:^^^^ BTMAC=28:11:06:68:66:3C ^^^^ CyweeChipInfo=\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+» AT^BTENABLE\r
+« package_common_cmd_to_bt strCmd 36 5A 00 03 00 09 01 9A 20 inParam (null) para_len 0\r
+commandID = 0x1 payload_len=0\r
+bt_manager_at_process cmdId=0x1 atId=0x901\r
+[bts][info] btsrv_set_log_type_level bts sert log type levle:ff2\r
+gap reg cbk ret 0\r
+func:audio_manager_init, line:69, success\r
+a2dp reg cbk ret 0\r
+a2dp reg cbk ret 0\r
+avrcp reg cbk ret 0\r
+[osal_msg_queue_create:25]:qName:BT_SERVICE_MSG qID=0x19 \r
+[bts][info] btsrv_task_init btsrv_init: task create success\r
+gap_state_changed_callback transport: 1 status: 0\r
+[bts][info] btsdk_get_discovery_mode mode = 00 \r
+[bts][info] gap_br_set_bt_scan_mode set scan mode old=0 new=4\r
+[bts][info] gap_br_set_bt_scan_mode btsdk_set_discovery_mode mode: d ret: 0\r
+[bts][info] pan_register_cbk pan service register cbk:A TO B start.[bts][info] btsdk_get_discovery_mode mode = 0d \r
+gap_scan_mode_changed_callback mode: 4\r
+\r
+[bts][info] bt_acore_get_config_sync_flash [ACore] bt read nv config succ, real_len:585.\r
+gap_state_changed_callback transport: 2 status: 1\r
+gap_state_changed_callback transport: 1 status: 1\r
+bt enable ok\r
+\r
+OK~\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+» AT^BTSCANTEST=1\r
+« APP|[BtScan] Starting Bluetooth scan test...\r
+APP|[BtScan] Enabling Bluetooth stack (same as AT^BTENABLE)...\r
+APP|[BtScan] Waiting for Bluetooth stack ready...\r
+APP|[BtScan] Inquiry parameters set successfully\r
+APP|[BtScan] Discovery state changed: 1\r
+APP|[BtScan] Discovery state changed: 2\r
+[bts][info] btsrv_start_bt_discovery discovery started\r
+APP|[BtScan] Discovery started successfully\r
+APP|[BtScan] Bluetooth scan started successfully\r
+APP|[BtScan] Scanning for devices...\r
+BT SCAN TEST START: Success\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+[bts][info] btsrv_handle_remote_device_found addr: ****a4a2ca05 [little endian: 05caa2a4**** ] name: 18J173203837 hdl: 0\r
+[bts][debug] btsrv_add_remote_dev_node addr: ****a4a2ca05 hdl: 0\r
+[bts][info] btsrv_notify_gap_discovery_result descovery result\r
+APP|[BtScan] New device discovered: AC:3F:A4:A2:CA:05\r
+APP|[BtScan] Device name: 18J173203837\r
+[bts][info] btsrv_notify_gap_discovery_result found device addr: ****a4a2ca05 name: 18J173203837APP|[BtScan] Device: AC:3F:A4:A2:CA:05, RSSI=-93 dBm\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+[bts][info] btsrv_handle_remote_device_found addr: ****a4a2ca05 [little endian: 05caa2a4**** ] name: 18J173203837 hdl: 0\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+» AT^BTSCANTEST=2\r
+« APP|[BtScan] Stopping Bluetooth scan test...\r
+[bts][info] gap_br_cancel_discovery btsdk_stop_device_discovery ret=0x0\r
+[bts][info] gap_br_c[bts][info] btsrv_inquiry_complete_ind_callback inquiry complete\r
+[bts][info] btsrv_handle_conn_event_msg set discovery status to stop\r
+APP|[BtScan] Discovery state changed: 3\r
+ancel_discovery discovery stopped\r
+APP|[BtScan] Discovery state changed: 3\r
+APP|[BtScan] Final scan results:\r
+APP|[BtScan] Found 1 device(s):\r
+APP|[BtScan] Device[1]: MAC=AC:3F:A4:A2:CA:05, RSSI=-93 dBmAPP|, Name=18J173203837APP|\r
+APP|[BtScan] Bluetooth scan stopped\r
+BT SCAN TEST STOP: Success\r
+» AT^BTSCANTEST=2\r
+« APP|[BtScan] Stopping Bluetooth scan test...\r
+APP|[BtScan] Scan not running\r
+BT SCAN TEST STOP: Success\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+» AT^BTSCANTEST=2\r
+« APP|[BtScan] Stopping Bluetooth scan test...\r
+APP|[BtScan] Scan not running\r
+BT SCAN TEST STOP: Success\r
+APP|charger not plugged ,disable charge !\r
+[WEARABLE I/] MsgCenterNotify: args=0x0x6c103670, topic=10021\r
+[WEARABLE I/] MsgCenterNotifyProc:: LowPower Alarm !\r
+[WEARABLE I/] MsgCenterNotifyLowpowerProc: alarm_type=1\r
+kvPath: /kvstore\r
+dataPath: \r
+Set value ret: -1\r
+brightness:0\r
+Brightness: 0% → Fall Edge: 7 → LED Current: 2.5mA\r
+[WEARABLE E/] MsgCenterNotifyLowpowerProc: ThunderBirdMainView::GetInstance() returned null\r
+APP|mipi_tx has been enable!\r
+APP|Succ read lcd id! Lcd id: 0x5598\r
+APP|timeout when wait phy ready \r
+kvPath: /kvstore\r
+dataPath: \r
+Set value ret: -1\r
+brightness:0\r
+[Graphic Error] [ResumeSlice: 225]No valid slice to resume\r
+APP|[POWER_MANAGER E/] filter_timer_execute_system_rule: filter timer, current default timeout:5000, keepon time:5000, event:5.\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+» AT^GPIOTEST=2\r
+« APP|[GpioTest] Starting GPIO test...\r
+APP|[GpioTest] No GPIO pairs configured, initializing with default config...\r
+APP|[GpioTest] Invalid input pin name: HSUART_CTS\r
+APP|[GpioTest] Parsed 34 GPIO pairs from JSON\r
+APP|[GpioTest] Default config initialized successfully\r
+APP|[GpioTest] Starting GPIO test with 34 pairs...\r
+APP|[GpioTest] Testing pair 0: S_AGPIO_L23 (input) <-> S_AGPIO_L12 (output)\r
+APP|[GpioTest] Pair 0: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 1: S_AGPIO_L13 (input) <-> S_AGPIO_L31 (output)\r
+APP|[GpioTest] Pair 1: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 2: S_AGPIO_L3 (input) <-> S_AGPIO_L2 (output)\r
+APP|[GpioTest] Pair 2: PASSED - S_AGPIO_L3 <-> S_AGPIO_L2\r
+APP|[GpioTest] Testing pair 3: S_AGPIO_L1 (input) <-> S_AGPIO_L4 (output)\r
+APP|[GpioTest] Pair 3: PASSED - S_AGPIO_L1 <-> S_AGPIO_L4\r
+APP|[GpioTest] Testing pair 4: S_AGPIO_L0 (input) <-> S_AGPIO_R4 (output)\r
+APP|[GpioTest] Pair 4: PASSED - S_AGPIO_L0 <-> S_AGPIO_R4\r
+APP|[GpioTest] Testing pair 5: S_AGPIO_R5 (input) <-> S_MGPIO14 (output)\r
+APP|[GpioTest] Pair 5: PASSED - S_AGPIO_R5 <-> S_MGPIO14\r
+APP|[GpioTest] Testing pair 6: S_MGPIO13 (input) <-> S_AGPIO_R10 (output)\r
+APP|[GpioTest] Pair 6: PASSED - S_MGPIO13 <-> S_AGPIO_R10\r
+APP|[GpioTest] Testing pair 7: S_MGPIO11 (input) <-> S_MGPIO12 (output)\r
+APP|[GpioTest] Pair 7: PASSED - S_MGPIO11 <-> S_MGPIO12\r
+APP|[GpioTest] Testing pair 8: S_AGPIO_R2 (input) <-> S_AGPIO_R1 (output)\r
+APP|[GpioTest] Pair 8: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 9: S_AGPIO_L24 (input) <-> S_AGPIO_L17 (output)\r
+APP|[GpioTest] Pair 9: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 10: S_AGPIO_L21 (input) <-> S_AGPIO_L11 (output)\r
+APP|[GpioTest] Pair 10: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 11: S_AGPIO_L19 (input) <-> S_AGPIO_R0 (output)\r
+APP|[GpioTest] Pair 11: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 12: S_HGPIO13 (input) <-> S_AGPIO_R3 (output)\r
+APP|[GpioTest] Pair 12: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 13: S_AGPIO_R6 (input) <-> S_MGPIO25 (output)\r
+APP|[GpioTest] Pair 13: PASSED - S_AGPIO_R6 <-> S_MGPIO25\r
+APP|[GpioTest] Testing pair 14: S_MGPIO26 (input) <-> S_MGPIO23 (output)\r
+APP|[GpioTest] Pair 14: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 15: S_MGPIO24 (input) <-> S_MGPIO31 (output)\r
+APP|[GpioTest] Pair 15: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 16: S_MGPIO29 (input) <-> S_MGPIO30 (output)\r
+APP|[GpioTest] Pair 16: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 17: S_MGPIO32 (input) <-> S_MGPIO28 (output)\r
+APP|[GpioTest] Pair 17: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 18: S_MGPIO27 (input) <-> S_MGPIO22 (output)\r
+APP|[GpioTest] Pair 18: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 19: S_MGPIO21 (input) <-> S_MGPIO19 (output)\r
+APP|[GpioTest] Pair 19: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 20: S_MGPIO20 (input) <-> S_AGPIO_R7 (output)\r
+APP|[GpioTest] Pair 20: PASSED - S_MGPIO20 <-> S_AGPIO_R7\r
+APP|[GpioTest] Testing pair 21: S_AGPIO_R8 (input) <-> S_AGPIO_R9 (output)\r
+APP|[GpioTest] Pair 21: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 22: S_AGPIO_L30 (input) <-> S_AGPIO_L29 (output)\r
+APP|[GpioTest] Pair 22: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 23: S_AGPIO_L32 (input) <-> S_AGPIO_L20 (output)\r
+APP|[GpioTest] Pair 23: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 24: S_AGPIO_L15 (input) <-> S_HGPIO5 (output)\r
+APP|[GpioTest] Pair 24: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 25: S_HGPIO4 (input) <-> S_HGPIO0 (output)\r
+APP|[GpioTest] Pair 25: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 26: S_HGPIO1 (input) <-> S_HGPIO2 (output)\r
+APP|[GpioTest] Pair 26: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 27: S_HGPIO3 (input) <-> S_MGPIO3 (output)\r
+APP|[GpioTest] Pair 27: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 28: S_MGPIO1 (input) <-> S_MGPIO2 (output)\r
+APP|[GpioTest] Pair 28: PASSED - S_MGPIO1 <-> S_MGPIO2\r
+APP|[GpioTest] Testing pair 29: S_MGPIO0 (input) <-> S_MGPIO6 (output)\r
+APP|[GpioTest] Pair 29: FAILED - Output HIGH but input read 0 (expected HIGH)\r
+APP|[GpioTest] Testing pair 30: S_MGPIO9 (input) <-> S_MGPIO8 (output)\r
+APP|[GpioTest] Pair 30: PASSED - S_MGPIO9 <-> S_MGPIO8\r
+APP|[GpioTest] Testing pair 31: S_MGPIO7 (input) <-> S_MGPIO8 (output)\r
+APP|[GpioTest] Pair 31: PASSED - S_MGPIO7 <-> S_MGPIO8\r
+APP|[GpioTest] Testing pair 32: S_AGPIO_L28 (input) <-> S_AGPIO_L18 (output)\r
+APP|[GpioTest] Pair 32: PASSED - S_AGPIO_L28 <-> S_AGPIO_L18\r
+APP|[GpioTest] Testing pair 33: S_HGPIO9 (input) <-> S_AGPIO_L26 (output)\r
+APP|[GpioTest] Pair 33: PASSED - S_HGPIO9 <-> S_AGPIO_L26\r
+APP|[GpioTest] Test completed: 13 passed, 21 failed\r
+APP|[GpioTest] Failed pairs:\r
+APP|[GpioTest]   Pair 0: S_AGPIO_L23 (input) <-> S_AGPIO_L12 (output)\r
+APP|[GpioTest]   Pair 1: S_AGPIO_L13 (input) <-> S_AGPIO_L31 (output)\r
+APP|[GpioTest]   Pair 8: S_AGPIO_R2 (input) <-> S_AGPIO_R1 (output)\r
+APP|[GpioTest]   Pair 9: S_AGPIO_L24 (input) <-> S_AGPIO_L17 (output)\r
+APP|[GpioTest]   Pair 10: S_AGPIO_L21 (input) <-> S_AGPIO_L11 (output)\r
+APP|[GpioTest]   Pair 11: S_AGPIO_L19 (input) <-> S_AGPIO_R0 (output)\r
+APP|[GpioTest]   Pair 12: S_HGPIO13 (input) <-> S_AGPIO_R3 (output)\r
+APP|[GpioTest]   Pair 14: S_MGPIO26 (input) <-> S_MGPIO23 (output)\r
+APP|[GpioTest]   Pair 15: S_MGPIO24 (input) <-> S_MGPIO31 (output)\r
+APP|[GpioTest]   Pair 16: S_MGPIO29 (input) <-> S_MGPIO30 (output)\r
+APP|[GpioTest]   Pair 17: S_MGPIO32 (input) <-> S_MGPIO28 (output)\r
+APP|[GpioTest]   Pair 18: S_MGPIO27 (input) <-> S_MGPIO22 (output)\r
+APP|[GpioTest]   Pair 19: S_MGPIO21 (input) <-> S_MGPIO19 (output)\r
+APP|[GpioTest]   Pair 21: S_AGPIO_R8 (input) <-> S_AGPIO_R9 (output)\r
+APP|[GpioTest]   Pair 22: S_AGPIO_L30 (input) <-> S_AGPIO_L29 (output)\r
+APP|[GpioTest]   Pair 23: S_AGPIO_L32 (input) <-> S_AGPIO_L20 (output)\r
+APP|[GpioTest]   Pair 24: S_AGPIO_L15 (input) <-> S_HGPIO5 (output)\r
+APP|[GpioTest]   Pair 25: S_HGPIO4 (input) <-> S_HGPIO0 (output)\r
+APP|[GpioTest]   Pair 26: S_HGPIO1 (input) <-> S_HGPIO2 (output)\r
+APP|[GpioTest]   Pair 27: S_HGPIO3 (input) <-> S_MGPIO3 (output)\r
+APP|[GpioTest]   Pair 29: S_MGPIO0 (input) <-> S_MGPIO6 (output)\r
+APP|[GpioTest] Test finished\r
+GPIO TEST START: Success\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+[Graphic Error] [PauseSlice: 236]No valid slice to pause\r
+APP|uapi_lcd_backlight_off\r
+Output RESET_LCD_GPIO 1 , VCI_LCD_GPIO 0\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+APP|charger not plugged ,disable charge !\r
+[WEARABLE I/] MsgCenterNotify: args=0x0x6c103670, topic=10021\r
+[WEARABLE I/] MsgCenterNotifyProc:: LowPower Alarm !\r
+[WEARABLE I/] MsgCenterNotifyLowpowerProc: alarm_type=1\r
+kvPath: /kvstore\r
+dataPath: \r
+Set value ret: -1\r
+brightness:0\r
+Brightness: 0% → Fall Edge: 7 → LED Current: 2.5mA\r
+[WEARABLE E/] MsgCenterNotifyLowpowerProc: ThunderBirdMainView::GetInstance() returned null\r
+APP|mipi_tx has been enable!\r
+APP|Succ read lcd id! Lcd id: 0x5598\r
+APP|timeout when wait phy ready \r
+kvPath: /kvstore\r
+dataPath: \r
+Set value ret: -1\r
+brightness:0\r
+[Graphic Error] [ResumeSlice: 225]No valid slice to resume\r
+APP|[POWER_MANAGER E/] filter_timer_execute_system_rule: filter timer, current default timeout:5000, keepon time:5000, event:5.\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+» AT^AUDIOTEST=5\r
+« APP|[AudioTest] Starting audio test...\r
+[00:01:30:051][W]{ai_media_service_init():808} AI media service already initialized \r
+[00:01:30:052][E]{old_Start_AIVoice():1289} StartAIVoice \r
+[00:01:30:053][I]{GetGlobalMutex():709} Global AI voice context mutex created successfully \r
+[00:01:30:055][I]{old_Start_AIVoice():1325} Using custom input audio params: format=1, channels=1, sampleRate=16000 \r
+[00:01:30:057][I]{old_Start_AIVoice():1340} Using custom output audio params: format=1, channels=1, sampleRate=16000 \r
+[00:01:30:060][I]{old_Start_AIVoice():1356} OGG encapsulation disabled by parameter \r
+[00:01:30:061][E]{old_Start_AIVoice():1362} g_aiVoiceContext->taskHandle \r
+[00:01:30:063][I]{CreateAIVoiceQueue():747} AI voice input queue created successfully \r
+APP|SET DSP freq=3, div=5, codec freq=3, div=36\r
+APP|set hifi mode=2.\r
+APP|SET DSP freq=3, div=5, codec freq=3, div=36\r
+[A][ALERT][sys_cmd_check_cmd_done:164] wait_time_us = 500\r
+[A][ALERT][drv_sys_pon:297] DSP0 power on\r
+[00:01:30:104][I]{old_Start_AIVoice():1392} AI voice thread created successfully with name: AIVoiceThread \r
+APP|[AudioTest] Play thread started\r
+APP|[AudioTest] Pre-filled 5 periods (160 bytes, 5.0 ms) of PCM data\r
+[00:01:30:108] E/TrackHandle :{StreamWriteTrack():720} track[0] is neither running or pause, write failed\r
+[00:01:30:110] E/AudioManagerCWrapper :{AudioStreamOutStreamWrite():365} audio stream out play failed 0xffffffff\r
+APP|[AudioTest] Audio test started successfully\r
+APP|[AudioTest] Playing 1kHz tone, monitoring volume every 0.5s...\r
+AUDIO TEST START: Success\r
+  Playing 1kHz tone, monitoring volume every 0.5s...\r
+aw_sysst_check succed\r
+aw_pa_start \r
+[00:01:30:367][I]{CreateAIVoiceInputThread():960} AI voice input thread created successfully \r
+[00:01:30:368][I]{RunAIVoice():1045} RunAIVoice: waiting for queue data... \r
+[00:01:30:369][I]{AIVoiceInputThreadFunc():978} AI voice input thread started \r
+APP|[AudioTest] Volume - RMS: 0.02% (-75.19 dB), Peak: 0.45% (-46.96 dB), Level: 静音\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+APP|[AudioTest] Volume - RMS: 13.79% (-17.21 dB), Peak: 36.59% (-8.73 dB), Level: 中\r
+APP|[AudioTest] Volume - RMS: 15.28% (-16.32 dB), Peak: 31.50% (-10.04 dB), Level: 中\r
+APP|[AudioTest] Volume - RMS: 14.13% (-17.00 dB), Peak: 31.48% (-10.04 dB), Level: 中\r
+APP|[AudioTest] Volume - RMS: 14.53% (-16.76 dB), Peak: 31.32% (-10.08 dB), Level: 中\r
+APP|[AudioTest] Volume - RMS: 14.11% (-17.01 dB), Peak: 31.38% (-10.07 dB), Level: 中\r
+» AT^AUDIOTEST=6\r
+« APP|[AudioTest] Stopping audio test...\r
+APP|[AudioTest] Play thread stopped\r
+APP|[AudioTest] Calling StopAIVoice()...\r
+Waiting for AI voice thread to stop...\r
+Thread validation passed, waiting for thread: AIVoiceThread\r
+osThreadJoin failed (-3), using state check...\r
+[00:01:34:050][I]{AIVoiceInputThreadFunc():1027} AI voice input thread stopped \r
+[Graphic Error] [PauseSlice: 236]No valid slice to pause\r
+Waiting... 1/50 (state: 3, running: yes)\r
+APP|uapi_lcd_backlight_off\r
+Output RESET_LCD_GPIO 1 , VCI_LCD_GPIO 0\r
+Waiting... 2/50 (state: 3, running: yes)\r
+[A][ALERT][core_adp_destroy:414] adp = 0x6D000001\r
+[A][ALERT][core_mod_free:316] mod_node->mid.u32 = 0x6D000001\r
+APP|SET DSP freq=3, div=6, codec freq=3, div=36\r
+APP|set hifi mode=1.\r
+[A][ALERT][core_adp_destroy:414] adp = 0x6D000101\r
+[A][ALERT][core_mod_free:316] mod_node->mid.u32 = 0x6D000101\r
+[A][aw88082_i2c_deinit:373]aw88082 i2c deinit success\r
+[00:01:34:376][I]{DeinitAIVoiceResources():811} AI voice input queue deleted \r
+AI voice thread cleanup completed\r
+Waiting... 3/50 (state: 0, running: no)\r
+AI voice thread stopped successfully (state check)\r
+AI voice stopped and resources cleaned up\r
+APP|[AudioTest] Audio test stopped\r
+AUDIO TEST STOP: Success\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+[A][ALERT][sys_cmd_check_cmd_done:164] wait_time_us = 700\r
+[A][ALERT][drv_sys_pd:331] DSP0 power down\r
+» AT^AUDIOTEST=7 0.5\r
+« APP|[AudioTest] Play volume set to 0.50 (50%)\r
+AUDIO TEST SET VOLUME: Success (0.00, 0%)\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
+APP|app_main run start.\r
+APP|sys_slp: 0x0\r
index 89dd459..99f3305 100644 (file)
@@ -8,311 +8,28 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
 {
     ui->setupUi(this);
     
-    // 初始化串口对象
-    serialport1 = new QSerialPort(this);
-    serialport2 = new QSerialPort(this);
-    serialport3 = new QSerialPort(this);
-    serialport4 = new QSerialPort(this);
-    
-    QSerialPort *ports[MAX_SERIAL_PORTS] = {serialport1, serialport2, serialport3, serialport4};
-    
-    // 初始化统一配置结构
-    for (int i = 0; i < MAX_SERIAL_PORTS; i++) {
-        // 创建串口上下文
-        port_contexts[i] = new SerialPortContext(i + 1);
-        
-        // 创建定时器
-        spp_timer_handles[i] = new QTimer(this);
-        
-        // 连接定时器信号(使用lambda捕获端口索引)
-        connect(spp_timer_handles[i], &QTimer::timeout, [this, i]() {
-            this->spp_timer_callback(i);
-        });
-        
-        // 初始化上下文
-        port_contexts[i]->init(ports[i], spp_timer_handles[i]);
-        
-        // 创建结果线程
-        result_threads[i] = new Result_Thread(this, i + 1);
-        result_threads[i]->start();
-        result_threads[i]->pause();
-    }
-    
-    // 向后兼容:映射到数组
-    result_thread1 = result_threads[0];
-    result_thread2 = result_threads[1];
-    result_thread3 = result_threads[2];
-    result_thread4 = result_threads[3];
-    
-    // 向后兼容:保留原有的定时器引用(映射到数组)
-    // 注意:spp_timer_handle1 将在后续代码中通过 port_contexts[0]->spp_timer_handle 访问
+    // 创建测试端口控制器实例
+    port_controller1 = new TestPortController(0, this);
+    port_controller2 = new TestPortController(1, this);
+    port_controller3 = new TestPortController(2, this);
+    port_controller4 = new TestPortController(3, this);
+    
+    // 连接信号槽
+    connectPortControllerSignals(port_controller1, 0);
+    connectPortControllerSignals(port_controller2, 1);
+    connectPortControllerSignals(port_controller3, 2);
+    connectPortControllerSignals(port_controller4, 3);
     
     ui_setting_read();
 }
 
-// ui_show_result1已在后面实现为向后兼容函数
+// 旧的统一处理函数已移到TestPortController类中,以下函数保留用于向后兼容
 
-// 统一的readData函数
+// 向后兼容:readData(已废弃,数据读取现在由TestPortController内部处理)
 void MainWindow::readData(int port_index)
 {
-    if (port_index < 0 || port_index >= MAX_SERIAL_PORTS) {
-        qDebug() << tr("无效的端口索引:") << port_index;
-        return;
-    }
-    
-    SerialPortContext *ctx = port_contexts[port_index];
-    if (ctx == nullptr || ctx->serialport == nullptr) {
-        qDebug() << tr("串口上下文未初始化,端口索引:") << port_index;
-        return;
-    }
-    
-    const QByteArray data = ctx->serialport->readAll();
-    // 调试输出
-    if(ctx->uart_rx_flag)
-        qDebug() << tr("端口%1接收数据:").arg(port_index) << data;
-
-    if (ctx->working_state == false) {
-        qDebug() << tr("端口%1写号结束,跳过读取串口").arg(port_index);
-        return;
-    }
-    
-    // 记录串口接收到的数据
-    if (!data.isEmpty()) {
-        QString dataStr = QString::fromUtf8(data);
-    }
-    
-    // 将新数据添加到开机检测缓存中
-    ctx->boot_detect_buffer.append(data);
-    
-    // 保持缓存大小合理,避免内存过度使用(保留最近8192字节)
-    if (ctx->boot_detect_buffer.length() > 8192) {
-        ctx->boot_detect_buffer = ctx->boot_detect_buffer.right(8192);
-        // 只在第一次超过限制时打印,避免重复打印
-        static bool buffer_limit_warned[MAX_SERIAL_PORTS] = {false, false, false, false};
-        if (!buffer_limit_warned[port_index]) {
-            qDebug() << tr("端口%1开机检测缓存过大,保留最近8192字节").arg(port_index);
-            buffer_limit_warned[port_index] = true;
-        }
-    }
-    
-    // 在缓存区中检测开机信号,处理分包情况
-    if (ctx->boot_detect_buffer.indexOf(BOOT_UP_MSG) >= 0) {
-        UIPortWidgets widgets = getUIPortWidgets(port_index);
-        widgets.label_runtime_status->setText(tr("发现新设备"));
-        ctx->waiting_cmd = true;
-        ctx->cmd_index = 0;
-        QString avalible_mac = settings::getInstance().getAvalibleMac();
-        widgets.ledit_spp_addr->setText(avalible_mac);
-        widgets.txtb_dispaly->clear();
-        // 检测到开机信号后清理缓存,避免无限增长
-        ctx->boot_detect_buffer.clear();
-        qDebug() << tr("端口%1检测到开机信号(yaffs filesystem init start),清理缓存").arg(port_index);
-    }
-    
-    // 在缓存区中检测MAC地址信息,处理分包情况
-    if (ctx->working_state && !ctx->waiting_cmd) {
-        // 使用正则表达式在缓存区中查找完整的MAC地址
-        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(ctx->boot_detect_buffer);
-        if (macPos >= 0) {
-            QString foundMac = macRegex.cap(1); // 提取MAC地址部分 (28:11:06:XX:XX:XX)
-            qDebug() << tr("端口%1在开机缓冲区中发现完整MAC地址:").arg(port_index) << foundMac;
-            
-            // 转换为无冒号格式
-            QString macWithoutColon = foundMac.replace(":", "").toUpper();
-            qDebug() << tr("端口%1转换后的MAC地址:").arg(port_index) << macWithoutColon;
-            
-            // 检查MAC地址是否已被使用
-            bool mac_used = settings::getInstance().getMacUsed(macWithoutColon);
-            qDebug() << tr("端口%1 MAC地址是否已被使用:").arg(port_index) << mac_used;
-            
-            if (mac_used) {
-                ui_display(port_index, tr("手表地址") + macWithoutColon + tr("已占用\r\n"), LOG_DIRECT_OUT);
-                ui_show_result(port_index, tr("Mac地址已占用"), false);
-            } else {
-                ui_display(port_index, tr("手表当前地址") + macWithoutColon + tr(" 可用!\r\n"), LOG_DIRECT_IN);
-                qDebug() << tr("端口%1手表当前MAC地址可用:").arg(port_index) << macWithoutColon;
-            }
-        }
-    }
-    
-    // 在缓存区中检测命令时机信号,处理分包情况
-    if (ctx->waiting_cmd && ctx->boot_detect_buffer.indexOf(TIME_FOR_CMD) >= 0) {
-        uart_send_data(port_index, ATCMD_ADD_VOTE);
-        // 检测到命令时机后也清理缓存
-        ctx->boot_detect_buffer.clear();
-        qDebug() << tr("端口%1检测到命令时机信号,清理缓存").arg(port_index);
-    }
-    
-    // 检测启动完成信号,需要同时检测到两个信号
-    if (ctx->waiting_cmd && !ctx->startup_complete_detected &&
-        ctx->boot_detect_buffer.indexOf(STARTUP_POST_INIT) >= 0 && 
-        ctx->boot_detect_buffer.indexOf(STARTUP_POST_INIT_TASK) >= 0) {
-        ctx->startup_complete_detected = true; // 设置标志,防止重复触发
-        qDebug() << tr("端口%1检测到启动完成信号,系统已完全启动").arg(port_index);
-        ui_display(port_index, tr("系统启动完成,可以执行GETIDS\r\n"), LOG_DIRECT_IN);
-        
-        // 清理缓存
-        ctx->boot_detect_buffer.clear();
-        qDebug() << tr("端口%1检测到启动完成信号,清理缓存").arg(port_index);
-        
-        // 如果当前正在等待GETIDS执行,且没有AT命令在执行,则触发GETIDS
-        if ((ctx->cmd_index == 3 || ctx->cmd_index == 4) && !ctx->uart_rx_flag) {
-            qDebug() << tr("端口%1启动完成且正在等待GETIDS,立即触发GETIDS执行").arg(port_index);
-            qDebug() << tr("端口%1当前cmd_index:").arg(port_index) << ctx->cmd_index;
-            
-            if (ctx->cmd_index == 3) {
-                ctx->cmd_index++; // 从3递增到4
-                qDebug() << tr("端口%1 cmd_index从3递增到4").arg(port_index);
-            }
-            // 如果cmd_index已经是4,保持不变,重新执行case 4
-            
-            // 清空之前的响应缓冲区,准备接收GETIDS响应
-            ctx->uart_rx_buff_array.clear();
-            qDebug() << tr("端口%1清空响应缓冲区,准备执行GETIDS").arg(port_index);
-            
-            // 重新执行switch逻辑,现在startup_complete_detected = true
-            switch(ctx->cmd_index) {
-            case 4:
-                qDebug() << tr("端口%1系统已完全启动,发送GETIDS指令").arg(port_index);
-                uart_send_data(port_index, ATCMD_GET_CPUID);
-                break;
-            default:
-                qDebug() << tr("端口%1启动完成回调中的cmd_index异常:").arg(port_index) << ctx->cmd_index;
-                break;
-            }
-        }
-    }
-
-    if (ctx->uart_rx_flag) {
-        // 指令下达完毕,开始接收数据
-        ctx->uart_rx_buff_array.append(data);
-        qDebug() << tr("端口%1 AT命令响应数据累积中,当前长度:").arg(port_index) << ctx->uart_rx_buff_array.length();
-        qDebug() << tr("端口%1当前累积内容:").arg(port_index) << ctx->uart_rx_buff_array;
-        
-        // 检查各种可能的结束标志
-        bool hasOK = ctx->uart_rx_buff_array.indexOf("OK~") >= 0;
-        bool hasPowerOff = ctx->uart_rx_buff_array.indexOf("power off device!") >= 0;
-        bool hasDSPPowerDown = ctx->uart_rx_buff_array.indexOf("DSP0 power down") >= 0;
-        
-        // 特殊处理:对于GETBTMAC命令,如果检测到完整的MAC地址响应,认为命令完成
-        bool isGetMacComplete = false;
-        qDebug() << tr("端口%1当前命令G_cmd:").arg(port_index) << ctx->G_cmd;
-        qDebug() << tr("端口%1是否包含GETBTMAC:").arg(port_index) << ctx->G_cmd.contains("GETBTMAC");
-        
-        if (ctx->G_cmd.contains("GETBTMAC")) {
-            qDebug() << tr("端口%1开始GETBTMAC特殊检测").arg(port_index);
-            // 检查是否包含完整的MAC地址格式和CyweeChipInfo
-            bool hasLocalAddr = ctx->uart_rx_buff_array.indexOf("get nv local_addr") >= 0;
-            bool hasBTMAC = ctx->uart_rx_buff_array.indexOf("BTMAC=") >= 0;
-            bool hasCyweeChipInfo = ctx->uart_rx_buff_array.indexOf("CyweeChipInfo=") >= 0;
-            
-            qDebug() << tr("端口%1检测结果 - hasLocalAddr:").arg(port_index) << hasLocalAddr 
-                     << tr("hasBTMAC:") << hasBTMAC << tr("hasCyweeChipInfo:") << hasCyweeChipInfo;
-            
-            if (hasLocalAddr && hasBTMAC && hasCyweeChipInfo) {
-                qDebug() << tr("端口%1基本条件满足,检查MAC地址格式").arg(port_index);
-                // 进一步检查是否包含完整的MAC地址格式
-                QRegExp completeMacRegex("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 = completeMacRegex.indexIn(ctx->uart_rx_buff_array);
-                qDebug() << tr("端口%1 MAC地址正则匹配结果:").arg(port_index) << macPos;
-                
-                if (macPos >= 0) {
-                    QString foundMac = completeMacRegex.cap(1);
-                    qDebug() << tr("端口%1找到完整MAC地址:").arg(port_index) << foundMac;
-                    isGetMacComplete = true;
-                    qDebug() << tr("端口%1 GETBTMAC命令响应完整,包含完整MAC地址和CyweeChipInfo").arg(port_index);
-                }
-            }
-        } else {
-            qDebug() << tr("端口%1当前命令不是GETBTMAC,跳过GETBTMAC特殊检测").arg(port_index);
-        }
-        
-        qDebug() << tr("端口%1结束标志检查 - OK~:").arg(port_index) << hasOK 
-                 << tr("power off:") << hasPowerOff << tr("DSP0 power down:") << hasDSPPowerDown 
-                 << tr("GETMAC完整:") << isGetMacComplete;
-        
-        if (hasOK || hasPowerOff || hasDSPPowerDown || isGetMacComplete) {
-            qDebug() << tr("端口%1检测到结束标志,开始处理AT命令结果").arg(port_index);
-            
-            // 停止超时定时器
-            if (ctx->spp_timer_handle && ctx->spp_timer_handle->isActive()) {
-                ctx->spp_timer_handle->stop();
-                qDebug() << tr("端口%1停止AT命令超时定时器").arg(port_index);
-            }
-            
-            ctx->uart_rx_flag = false;
-            uart_process(port_index); // 开始处理当前指令结果
-            
-            if (ctx->cmd_index < 0) {
-                if (ctx->spp_timer_handle && ctx->spp_timer_handle->isActive()) {
-                    ctx->spp_timer_handle->stop();
-                }
-                
-                if (ctx->uart_rx_buff_array.indexOf("power off device") >= 0) {
-                    ui_display(port_index, tr("关机成功\r\n"), LOG_DIRECT_IN);
-                }
-                return;
-            }
-            
-            ctx->cmd_index++; // 开始执行下一指令
-            qDebug() << tr("端口%1 next cmdindex").arg(port_index) << ctx->cmd_index;
-            
-            UIPortWidgets widgets = getUIPortWidgets(port_index);
-            switch(ctx->cmd_index) {
-            case 0:
-            {
-                // 空操作
-            }
-                break;
-            case 1:
-            {
-                qDebug() << tr("端口%1执行case 1: 查询手表MAC地址").arg(port_index);
-                uart_send_data(port_index, ATCMD_GET_MAC);
-            }
-                break;
-            case 2:
-            {
-                QString set_mac_cmd = QString(ATCMD_SET_MAC).arg(widgets.ledit_spp_addr->text());
-                uart_send_data(port_index, set_mac_cmd);
-            }
-                break;
-            case 3:
-            {
-                uart_send_data(port_index, ATCMD_GET_MAC);
-            }
-                break;
-            case 4:
-            {
-                // 只有在检测到启动完成信号后才发送GETIDS
-                if (ctx->startup_complete_detected) {
-                    qDebug() << tr("端口%1系统已完全启动,发送GETIDS指令").arg(port_index);
-                    uart_send_data(port_index, ATCMD_GET_CPUID);
-                } else {
-                    qDebug() << tr("端口%1等待系统完全启动信号,暂不发送GETIDS").arg(port_index);
-                    ui_display(port_index, tr("等待系统完全启动信号...\r\n"), LOG_DIRECT_OUT);
-                    // 保持在case 4,等待启动完成信号
-                    ctx->cmd_index = 4;
-                    return;
-                }
-            }
-                break;
-            case 5:
-            {
-                uart_send_data(port_index, ATCMD_POWEROFF);
-            }
-                break;
-            default:
-            {
-                ctx->cmd_index = -1;
-                if (ctx->spp_timer_handle && ctx->spp_timer_handle->isActive()) {
-                    ctx->spp_timer_handle->stop();
-                }
-            }
-                break;
-            }
-        }
-    }
+    Q_UNUSED(port_index);
+    // 数据读取现在由TestPortController的onReadyRead槽处理
 }
 
 // 向后兼容:readData1
@@ -339,32 +56,21 @@ MainWindow::~MainWindow()
 {
     ui_setting_save();
     
-    // 停止所有线程和定时器
-    for (int i = 0; i < MAX_SERIAL_PORTS; i++) {
-        if (spp_timer_handles[i] != nullptr) {
-            spp_timer_handles[i]->stop();
-        }
-        if (result_threads[i] != nullptr) {
-            result_threads[i]->stop();
-            result_threads[i]->wait();
-            delete result_threads[i];
-        }
-        if (port_contexts[i] != nullptr) {
-            delete port_contexts[i];
-        }
-    }
+    // 删除端口控制器(会自动清理内部资源)
+    delete port_controller1;
+    delete port_controller2;
+    delete port_controller3;
+    delete port_controller4;
     
     delete ui;
 }
-// 统一的poweroff_watch函数
+// 统一的poweroff_watch函数(使用TestPortController)
 void MainWindow::poweroff_watch(int port_index)
 {
-    if (port_index < 0 || port_index >= MAX_SERIAL_PORTS) {
-        qDebug() << tr("无效的端口索引:") << port_index;
-        return;
+    TestPortController* controller = getPortController(port_index);
+    if (controller) {
+        controller->poweroffWatch();
     }
-    
-    uart_send_data(port_index, ATCMD_POWEROFF);
 }
 
 // 向后兼容:poweroff_watch1
@@ -389,7 +95,7 @@ MainWindow::UIPortWidgets MainWindow::getUIPortWidgets(int port_index)
     case 0:
         widgets.txtb_dispaly = ui->txtb_dispaly;
         widgets.label_runtime_status = ui->label_runtime_status1;
-        widgets.ledit_spp_addr = ui->ledit_spp_addr_1;
+
         widgets.label_result_success = ui->label_result_success1;
         widgets.label_result_fail = ui->label_result_fail1;
         widgets.cbox_uart_com_select = ui->cbox_uart_com_select_1;
@@ -398,7 +104,7 @@ MainWindow::UIPortWidgets MainWindow::getUIPortWidgets(int port_index)
     case 1:
         widgets.txtb_dispaly = ui->txtb_dispaly_2;
         widgets.label_runtime_status = ui->label_runtime_status2;
-        widgets.ledit_spp_addr = ui->ledit_spp_addr_2;
+
         widgets.label_result_success = ui->label_result_success2;
         widgets.label_result_fail = ui->label_result_fail2;
         widgets.cbox_uart_com_select = ui->cbox_uart_com_select_2;
@@ -407,7 +113,7 @@ MainWindow::UIPortWidgets MainWindow::getUIPortWidgets(int port_index)
     case 2:
         widgets.txtb_dispaly = ui->txtb_dispaly_3;
         widgets.label_runtime_status = ui->label_runtime_status3;
-        widgets.ledit_spp_addr = ui->ledit_spp_addr_3;
+
         widgets.label_result_success = ui->label_result_success3;
         widgets.label_result_fail = ui->label_result_fail3;
         widgets.cbox_uart_com_select = ui->cbox_uart_com_select_3;
@@ -416,7 +122,7 @@ MainWindow::UIPortWidgets MainWindow::getUIPortWidgets(int port_index)
     case 3:
         widgets.txtb_dispaly = ui->txtb_dispaly_4;
         widgets.label_runtime_status = ui->label_runtime_status4;
-        widgets.ledit_spp_addr = ui->ledit_spp_addr_4;
+
         widgets.label_result_success = ui->label_result_success4;
         widgets.label_result_fail = ui->label_result_fail4;
         widgets.cbox_uart_com_select = ui->cbox_uart_com_select_4;
@@ -425,7 +131,7 @@ MainWindow::UIPortWidgets MainWindow::getUIPortWidgets(int port_index)
     default:
         widgets.txtb_dispaly = ui->txtb_dispaly;
         widgets.label_runtime_status = ui->label_runtime_status1;
-        widgets.ledit_spp_addr = ui->ledit_spp_addr_1;
+
         widgets.label_result_success = ui->label_result_success1;
         widgets.label_result_fail = ui->label_result_fail1;
         widgets.cbox_uart_com_select = ui->cbox_uart_com_select_1;
@@ -435,57 +141,122 @@ MainWindow::UIPortWidgets MainWindow::getUIPortWidgets(int port_index)
     return widgets;
 }
 
-// 统一的UI显示函数
-void MainWindow::ui_display(int port_index, QString str, bool inOrOut)
+// 获取指定端口的控制器
+TestPortController* MainWindow::getPortController(int port_index)
 {
-    if (port_index < 0 || port_index >= MAX_SERIAL_PORTS) {
-        qDebug() << tr("无效的端口索引:") << port_index;
-        return;
-    }
-    
-    UIPortWidgets widgets = getUIPortWidgets(port_index);
-    if (widgets.txtb_dispaly == nullptr) {
-        qDebug() << tr("UI控件未找到,端口索引:") << port_index;
-        return;
-    }
-    
-    widgets.txtb_dispaly->moveCursor(QTextCursor::End);
-    if(inOrOut){
-        widgets.txtb_dispaly->setTextColor(QColor(127, 255, 0));
-    }else{
-        widgets.txtb_dispaly->setTextColor(Qt::red);
+    switch(port_index) {
+    case 0: return port_controller1;
+    case 1: return port_controller2;
+    case 2: return port_controller3;
+    case 3: return port_controller4;
+    default: return port_controller1;
     }
-    widgets.txtb_dispaly->insertPlainText(str);
-    widgets.txtb_dispaly->moveCursor(QTextCursor::End);
 }
 
-// 统一的结果显示函数
-void MainWindow::ui_show_result(int port_index, QString msg, bool success)
+// 连接端口控制器的信号槽
+void MainWindow::connectPortControllerSignals(TestPortController* controller, int port_index)
 {
-    if (port_index < 0 || port_index >= MAX_SERIAL_PORTS) {
-        qDebug() << tr("无效的端口索引:") << port_index;
-        return;
-    }
+    if (!controller) return;
     
-    SerialPortContext *ctx = port_contexts[port_index];
     UIPortWidgets widgets = getUIPortWidgets(port_index);
     
-    if (widgets.label_runtime_status == nullptr) {
-        qDebug() << tr("UI控件未找到,端口索引:") << port_index;
-        return;
-    }
+    // 连接显示消息信号
+    connect(controller, &TestPortController::displayMessage, [widgets](QString str, bool inOrOut) {
+        if (widgets.txtb_dispaly) {
+            widgets.txtb_dispaly->moveCursor(QTextCursor::End);
+            if (inOrOut) {
+                widgets.txtb_dispaly->setTextColor(QColor(127, 255, 0));
+            } else {
+                widgets.txtb_dispaly->setTextColor(Qt::red);
+            }
+            widgets.txtb_dispaly->insertPlainText(str);
+            widgets.txtb_dispaly->moveCursor(QTextCursor::End);
+        }
+    });
     
-    widgets.label_runtime_status->setText(msg);
-    if (success) {
-        ctx->write_success_count++;
-        widgets.label_result_success->setText(tr("成功%1").arg(ctx->write_success_count));
-    } else {
-        ctx->write_fail_count++;
-        widgets.label_result_fail->setText(tr("失败%1").arg(ctx->write_fail_count));
-        poweroff_watch(port_index);
+    // 连接结果显示信号
+    connect(controller, &TestPortController::showResult, [this, controller, widgets](QString msg, bool success) {
+        if (widgets.label_runtime_status) {
+            widgets.label_runtime_status->setText(msg);
+        }
+        if (success) {
+            if (widgets.label_result_success) {
+                widgets.label_result_success->setText(tr("成功%1").arg(controller->successCount()));
+            }
+        } else {
+            if (widgets.label_result_fail) {
+                widgets.label_result_fail->setText(tr("失败%1").arg(controller->failCount()));
+            }
+            controller->poweroffWatch();
+        }
+    });
+    
+    // 连接状态变化信号
+    connect(controller, &TestPortController::statusChanged, [widgets](QString status) {
+        if (widgets.label_runtime_status) {
+            widgets.label_runtime_status->setText(status);
+        }
+    });
+    
+    // 连接成功计数变化信号
+    connect(controller, &TestPortController::successCountChanged, [widgets](int count) {
+        if (widgets.label_result_success) {
+            widgets.label_result_success->setText(tr("成功%1").arg(count));
+        }
+    });
+    
+    // 连接失败计数变化信号
+    connect(controller, &TestPortController::failCountChanged, [widgets](int count) {
+        if (widgets.label_result_fail) {
+            widgets.label_result_fail->setText(tr("失败%1").arg(count));
+        }
+    });
+    
+    // 连接MAC地址变化信号(UI中暂无显示MAC地址的控件,保留信号连接以备将来使用)
+    connect(controller, &TestPortController::macAddressChanged, [](QString mac) {
+        Q_UNUSED(mac);
+        // MAC地址变化信号已连接,但UI中暂无显示控件
+    });
+    
+    // 连接按钮文本变化信号
+    connect(controller, &TestPortController::buttonTextChanged, [widgets](QString text) {
+        if (widgets.pbtn_spp_reconnect) {
+            widgets.pbtn_spp_reconnect->setText(text);
+        }
+    });
+    
+    // 连接清空显示信号
+    connect(controller, &TestPortController::clearDisplay, [widgets]() {
+        if (widgets.txtb_dispaly) {
+            widgets.txtb_dispaly->clear();
+        }
+    });
+    
+    // 连接MAC状态更新信号(用于更新textBrowser_result)
+    connect(controller, &TestPortController::updateMacStatus, [this](QString status) {
+        if (ui->textBrowser_result) {
+            ui->textBrowser_result->setText(status);
+        }
+    });
+}
+
+// 统一的UI显示函数(保留用于向后兼容,实际由信号槽处理)
+void MainWindow::ui_display(int port_index, QString str, bool inOrOut)
+{
+    TestPortController* controller = getPortController(port_index);
+    if (controller) {
+        // 通过公共方法触发信号(在connectPortControllerSignals中已连接)
+        controller->triggerDisplayMessage(str, inOrOut);
     }
-    if (ctx->spp_timer_handle && ctx->spp_timer_handle->isActive()) {
-        ctx->spp_timer_handle->stop();
+}
+
+// 统一的结果显示函数(保留用于向后兼容,实际由信号槽处理)
+void MainWindow::ui_show_result(int port_index, QString msg, bool success)
+{
+    TestPortController* controller = getPortController(port_index);
+    if (controller) {
+        // 通过公共方法触发信号(在connectPortControllerSignals中已连接)
+        controller->triggerShowResult(msg, success);
     }
 }
 
@@ -544,295 +315,51 @@ void MainWindow::ui_setting_save()
 // 读取config配置
 void MainWindow::ui_setting_read()
 {
+    // 先更新所有串口选择框(包含最新串口列表和None选项)
     uart_com_select();
+    
     QSettings *msettings = new QSettings("Setting.ini", QSettings::IniFormat);
-    ui->cbox_uart_com_select_1->ChangeItem(msettings->value("Uart_setting/uart_com").toString());
+    QString saved_com = msettings->value("Uart_setting/uart_com").toString();
+    
+    // 如果保存的串口存在,则设置为当前选择;否则保持为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);
+        }
+    }
+    
     ui->cbox_uart_baud_select->setCurrentIndex(msettings->value("Uart_setting/uart_baud").toInt());
 
     settings::getInstance().load_settings();
     ui->textBrowser_result->setText(settings::getInstance().getmacStatusFull());
-
 }
 
 
 /* --------------------------------uart操作--------------------------- */
-// 统一的uart_process函数
+// 统一的uart_process函数(已废弃,逻辑在TestPortController中)
 void MainWindow::uart_process(int port_index)
 {
-    if (port_index < 0 || port_index >= MAX_SERIAL_PORTS) {
-        qDebug() << tr("无效的端口索引:") << port_index;
-        return;
-    }
-    
-    SerialPortContext *ctx = port_contexts[port_index];
-    if (ctx == nullptr) {
-        qDebug() << tr("串口上下文未初始化,端口索引:") << port_index;
-        return;
-    }
-    
-    UIPortWidgets widgets = getUIPortWidgets(port_index);
-    
-    qDebug() << tr("端口%1 uart_process").arg(port_index) << ctx->cmd_index;
-    // 处理指令结果
-    switch(ctx->cmd_index) {
-    case 0:
-        ui_display(port_index, tr("阻止休眠\r\n"), LOG_DIRECT_IN);
-        qDebug() << tr("端口%1阻止休眠").arg(port_index);
-        break;
-    case 1:
-    {
-        // 检查当前的号是否已经是写过的号,防止重复写号造成的浪费
-        qDebug() << tr("端口%1执行case 1: 查询手表MAC地址").arg(port_index);
-        qDebug() << tr("端口%1 uart_rx_buff_array长度:").arg(port_index) << ctx->uart_rx_buff_array.length();
-        qDebug() << tr("端口%1 uart_rx_buff_array内容:").arg(port_index) << ctx->uart_rx_buff_array;
-        
-        // 使用正则表达式查找MAC地址格式: BTMAC=28:11:06:XX:XX:XX,支持多包检测
-        qDebug() << tr("端口%1开始在AT响应中查找MAC地址").arg(port_index);
-        qDebug() << tr("端口%1当前缓存内容:").arg(port_index) << ctx->uart_rx_buff_array;
-        qDebug() << tr("端口%1缓存长度:").arg(port_index) << ctx->uart_rx_buff_array.length();
-        
-        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 ret = macRegex.indexIn(ctx->uart_rx_buff_array);
-        qDebug() << tr("端口%1正则表达式查找结果:").arg(port_index) << ret;
-        
-        // 如果正则表达式没找到,尝试简单的BTMAC=查找来调试
-        int simple_ret = ctx->uart_rx_buff_array.indexOf("BTMAC=");
-        qDebug() << tr("端口%1简单BTMAC=查找结果:").arg(port_index) << simple_ret;
-        
-        if (simple_ret >= 0) {
-            // 显示BTMAC=后面的内容,看看是否完整
-            QString after_btmac = ctx->uart_rx_buff_array.mid(simple_ret);
-            qDebug() << tr("端口%1 BTMAC=后面的内容:").arg(port_index) << after_btmac;
-            
-            // 备用方法:如果正则表达式失败,尝试手动提取MAC地址
-            if (ret < 0) {
-                qDebug() << tr("端口%1正则表达式失败,尝试备用提取方法").arg(port_index);
-                
-                // 查找BTMAC=后面是否有足够的字符来组成MAC地址
-                QString remaining = ctx->uart_rx_buff_array.mid(simple_ret + 6); // 跳过"BTMAC="
-                qDebug() << tr("端口%1 BTMAC=后的剩余内容:").arg(port_index) << remaining;
-                
-                // 尝试提取MAC地址,即使不完整也显示当前状态
-                QRegExp partialMacRegex("([0-9A-Fa-f:]+)");
-                if (partialMacRegex.indexIn(remaining) >= 0) {
-                    QString partialMac = partialMacRegex.cap(1);
-                    qDebug() << tr("端口%1部分MAC地址:").arg(port_index) << partialMac;
-                    
-                    // 检查是否是完整的MAC地址(应该有5个冒号)
-                    int colonCount = partialMac.count(':');
-                    qDebug() << tr("端口%1冒号数量:").arg(port_index) << colonCount << tr("(完整MAC地址应该有5个冒号)");
-                    
-                    if (colonCount == 5) {
-                        qDebug() << tr("端口%1检测到完整MAC地址,使用备用方法处理").arg(port_index);
-                        QString unit = partialMac.replace(":", "").toUpper();
-                        qDebug() << tr("端口%1备用方法提取的MAC地址:").arg(port_index) << unit;
-                        
-                        bool mac_used = settings::getInstance().getMacUsed(unit.toUpper());
-                        qDebug() << tr("端口%1 MAC地址是否已被使用:").arg(port_index) << mac_used;
-                        
-                        if (mac_used) {
-                            ui_display(port_index, tr("手表地址") + unit + tr("已占用\r\n"), LOG_DIRECT_OUT);
-                            ui_show_result(port_index, tr("Mac地址已占用"), false);
-                            ctx->cmd_index = -1;
-                        } else {
-                            ui_display(port_index, tr("手表当前地址") + unit + tr(" 可用!\r\n"), LOG_DIRECT_IN);
-                        }
-                        
-                        // 跳过后面的正常处理
-                        break;
-                    } else {
-                        qDebug() << tr("端口%1 MAC地址不完整,等待更多数据").arg(port_index);
-                    }
-                }
-            }
-        }
-        
-        if (ret >= 0) {
-            QString mac_with_colon = macRegex.cap(1); // 提取MAC地址部分 (28:11:06:4D:29:EF)
-            qDebug() << tr("端口%1找到BTMAC=,位置:").arg(port_index) << ret;
-            qDebug() << tr("端口%1提取的MAC地址(带冒号):").arg(port_index) << mac_with_colon;
-            
-            QString unit = mac_with_colon.replace(":", "").toUpper(); // "28110604D29EF"
-            qDebug() << tr("端口%1处理后的MAC地址(无冒号):").arg(port_index) << unit;
-            
-            bool mac_used = settings::getInstance().getMacUsed(unit.toUpper());
-            qDebug() << tr("端口%1 MAC地址是否已被使用:").arg(port_index) << mac_used;
-            
-            if (mac_used) {
-                ui_display(port_index, tr("手表地址") + unit + tr("已占用\r\n"), LOG_DIRECT_OUT);
-                ui_show_result(port_index, tr("Mac地址已占用"), false);
-                ctx->cmd_index = -1;
-            } else {
-                ui_display(port_index, tr("手表当前地址") + unit + tr(" 可用!\r\n"), LOG_DIRECT_IN);
-            }
-        } else {
-            qDebug() << tr("端口%1在uart_rx_buff_array中未找到BTMAC=").arg(port_index);
-            qDebug() << tr("端口%1完整缓存内容(十六进制):").arg(port_index) << ctx->uart_rx_buff_array.toHex();
-            ui_display(port_index, tr("查询手表Mac失败!\r\n"), LOG_DIRECT_OUT);
-            ctx->cmd_index = -1;
-            ui_show_result(port_index, tr("查询手表Mac失败"), false);
-        }
-    }
-        break;
-    case 2:
-    {
-        QString new_mac = widgets.ledit_spp_addr->text();
-        ui_display(port_index, tr("执行设置地址\r\n"), LOG_DIRECT_OUT);
-        qDebug() << tr("端口%1执行case 2: 设置MAC地址完成").arg(port_index);
-        qDebug() << tr("端口%1设置的MAC地址:").arg(port_index) << new_mac;
-        ui_display(port_index, tr("MAC地址设置完成,等待设备处理...\r\n"), LOG_DIRECT_IN);
-    }
-        break;
-    case 3:
-    {
-        // 验证设置的MAC地址是否成功
-        QString unit = widgets.ledit_spp_addr->text();
-        qDebug() << tr("端口%1执行case 3: 验证设置的MAC地址").arg(port_index);
-        qDebug() << tr("端口%1期望的MAC地址:").arg(port_index) << unit;
-        qDebug() << tr("端口%1响应数据长度:").arg(port_index) << ctx->uart_rx_buff_array.length();
-        
-        if (ctx->uart_rx_buff_array.length() < 50) {
-            qDebug() << tr("端口%1响应数据较短,可能是超时或设备重启中").arg(port_index);
-        }
-        
-        // 使用正则表达式查找MAC地址格式: BTMAC=28:11:06:XX:XX:XX,支持多包检测
-        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 ret = macRegex.indexIn(ctx->uart_rx_buff_array);
-        if (ret >= 0) {
-            // 提取MAC地址部分
-            QString mac_with_colon = macRegex.cap(1); // "28:11:06:4D:29:EF"
-            QString unit_watch = mac_with_colon.replace(":", "").toUpper(); // "28110604D29EF"
-            
-            qDebug() << tr("端口%1手表返回的MAC地址:").arg(port_index) << unit_watch;
-            qDebug() << tr("端口%1期望的MAC地址:").arg(port_index) << unit;
-            
-            if (unit_watch.toUpper() == unit.toUpper()) {
-                ui_display(port_index, tr("设置Mac") + unit_watch + tr("成功\r\n"), LOG_DIRECT_IN);
-            } else {
-                ui_display(port_index, tr("设置Mac") + unit_watch + tr("失败\r\n"), LOG_DIRECT_OUT);
-                ctx->cmd_index = -2;
-                ui_show_result(port_index, tr("Mac地址设置失败"), false);
-            }
-        } else {
-            ui_display(port_index, tr("设置Mac") + unit + tr("失败\r\n"), LOG_DIRECT_OUT);
-            ctx->cmd_index = -3;
-            ui_show_result(port_index, tr("查询手表Mac失败"), false);
-        }
-    }
-        break;
-    case 4:
-    {
-        qDebug() << tr("端口%1执行case 4: 获取CPU ID").arg(port_index);
-        qDebug() << tr("端口%1响应内容:").arg(port_index) << ctx->uart_rx_buff_array;
-        qDebug() << tr("端口%1响应长度:").arg(port_index) << ctx->uart_rx_buff_array.length();
-        
-        // 使用分包检测方式查找CPU ID信息
-        int ret = ctx->uart_rx_buff_array.indexOf("[soc id:]");
-        qDebug() << tr("端口%1 [soc id:]查找结果:").arg(port_index) << ret;
-        
-        if (ret >= 0) {
-            // 查找[soc id:]后面的内容,直到遇到OK~或其他结束标志
-            QString soc_section = ctx->uart_rx_buff_array.mid(ret);
-            qDebug() << tr("端口%1 SOC部分内容:").arg(port_index) << soc_section;
-            
-            // 检查是否包含完整的数据结束标志
-            bool hasCompleteData = soc_section.contains("OK~") || soc_section.contains("\r\n\r\n");
-            qDebug() << tr("端口%1是否包含完整数据标志:").arg(port_index) << hasCompleteData;
-            
-            // 提取所有的十六进制数据(0x开头的),支持分包和多行格式
-            QRegExp hexRegex("0x[0-9A-Fa-f]{4}");
-            QStringList hexValues;
-            int pos = 0;
-            
-            while ((pos = hexRegex.indexIn(soc_section, pos)) != -1) {
-                hexValues << hexRegex.cap(0);
-                pos += hexRegex.matchedLength();
-                qDebug() << tr("端口%1找到十六进制值:").arg(port_index) << hexRegex.cap(0) << tr("位置:") << pos;
-            }
-            
-            qDebug() << tr("端口%1提取的十六进制值:").arg(port_index) << hexValues;
-            qDebug() << tr("端口%1十六进制值数量:").arg(port_index) << hexValues.size();
-            
-            // 检查数据完整性:需要至少10个十六进制值且有结束标志
-            if (hexValues.size() >= 10 && hasCompleteData) {
-                // 将所有十六进制值连接成CPU ID(去掉0x前缀)
-                QString cpu_id = "";
-                for (const QString &hex : hexValues) {
-                    cpu_id += hex.mid(2); // 去掉"0x"前缀
-                }
-                
-                qDebug() << tr("端口%1组合的CPU ID:").arg(port_index) << cpu_id;
-                ui_display(port_index, "cpuid: " + cpu_id + "\r\n", LOG_DIRECT_IN);
-                
-                int db_ret = settings::getInstance().set_mac_used(widgets.ledit_spp_addr->text(), cpu_id, true);
-                qDebug() << tr("端口%1 set mac used").arg(port_index) << widgets.ledit_spp_addr->text() << cpu_id << tr("ret") << db_ret;
-                
-                if (db_ret == 1) {
-                    ui->textBrowser_result->setText(settings::getInstance().getmacStatusFull());
-                    ui_display(port_index, tr("设置mac成功\r\n"), LOG_DIRECT_IN);
-                } else {
-                    ui_show_result(port_index, tr("获取cpuid失败\r\n"), false);
-                }
-            } else {
-                qDebug() << tr("端口%1 CPU ID数据不完整 - 十六进制值:").arg(port_index) << hexValues.size() << tr("完整标志:") << hasCompleteData;
-                
-                if (!hasCompleteData) {
-                    qDebug() << tr("端口%1等待完整的AT^GETIDS响应数据").arg(port_index);
-                    ui_display(port_index, tr("等待CPU ID完整数据...\r\n"), LOG_DIRECT_OUT);
-                    return; // 等待更多数据
-                } else if (hexValues.size() < 10) {
-                    qDebug() << tr("端口%1十六进制值数量不足,期望>=10,实际:").arg(port_index) << hexValues.size();
-                    ui_display(port_index, tr("CPU ID格式不正确\r\n"), LOG_DIRECT_OUT);
-                    ctx->cmd_index = -4;
-                    ui_show_result(port_index, tr("获取CPU ID失败"), false);
-                }
-            }
-        } else {
-            qDebug() << tr("端口%1未找到[soc id:]标志,可能数据分包传输中").arg(port_index);
-            ui_display(port_index, tr("等待CPU ID数据...\r\n"), LOG_DIRECT_OUT);
-            
-            // 不使用备用CPU ID,直接失败
-            ctx->cmd_index = -4;
-            ui_show_result(port_index, tr("获取CPU ID失败"), false);
-        }
-    }
-        break;
-    case 5:
-    {
-        int ret = ctx->uart_rx_buff_array.indexOf("power off device");
-        if (ret >= 0) {
-            ui_display(port_index, tr("关机成功\r\n"), LOG_DIRECT_IN);
-        } else {
-            ui_display(port_index, tr("关机失败\r\n"), LOG_DIRECT_OUT);
-        }
-        ui_show_result(port_index, tr("设置mac成功\r\n"), true);
-    }
-        break;
-    default:
-    {
-        ctx->cmd_index = -1;
-    }
-        break;
-    }
+    // 此函数已废弃,处理逻辑现在由TestPortController内部处理
+    Q_UNUSED(port_index);
 }
 
-// 向后兼容:uart_process1
+// 向后兼容:uart_process1-4(已废弃,逻辑在TestPortController中)
 void MainWindow::uart_process1()
 {
-    uart_process(0);
+    Q_UNUSED(0);
 }
-// 向后兼容:uart_process2/3/4
 void MainWindow::uart_process2()
 {
-    uart_process(1);
+    Q_UNUSED(1);
 }
 void MainWindow::uart_process3()
 {
-    uart_process(2);
+    Q_UNUSED(2);
 }
 void MainWindow::uart_process4()
 {
-    uart_process(3);
+    Q_UNUSED(3);
 }
 //void MainWindow::uart_open(QString com,QString com_baud)
 //{
@@ -842,48 +369,12 @@ void MainWindow::uart_process4()
 //{
 
 //}
-// 统一的uart_send_data函数
+// 统一的uart_send_data函数(已废弃,逻辑在TestPortController中)
 void MainWindow::uart_send_data(int port_index, QString cmd)
 {
-    if (port_index < 0 || port_index >= MAX_SERIAL_PORTS) {
-        qDebug() << tr("无效的端口索引:") << port_index;
-        return;
-    }
-    
-    SerialPortContext *ctx = port_contexts[port_index];
-    if (ctx == nullptr || ctx->serialport == nullptr) {
-        qDebug() << tr("串口上下文未初始化,端口索引:") << port_index;
-        return;
-    }
-    
-    qint64 ret = 0;
-    
-    // 发送AT指令之前清空缓存区,确保响应数据的准确性
-    ctx->uart_rx_buff_array.clear();
-    qDebug() << tr("端口%1发送AT指令前清空缓存区").arg(port_index);
-    
-    qDebug() << tr("端口%1 uart_send_data").arg(port_index) << cmd;
-    ret = ctx->serialport->write(cmd.toUtf8());
-    ctx->m_bytesToWrite = ret;
-    qDebug() << tr("端口%1 uart_send_data").arg(port_index) << cmd << tr(" ret") << ctx->m_bytesToWrite;
-    
-    ctx->G_cmd = cmd;
-    if (ctx->spp_timer_handle && ctx->spp_timer_handle->isActive()) {
-        ctx->spp_timer_handle->stop();
-    }
-    
-    // 对于特定命令使用更长的超时时间
-    if (cmd.contains("GETIDS")) {
-        ctx->spp_timer_handle->start(5000); // 5秒超时
-        qDebug() << tr("端口%1 GETIDS命令使用5秒超时").arg(port_index);
-    } else if (cmd.contains("GETBTMAC")) {
-        ctx->spp_timer_handle->start(3000); // GETBTMAC命令3秒超时
-        qDebug() << tr("端口%1 GETBTMAC命令使用3秒超时").arg(port_index);
-    } else {
-        ctx->spp_timer_handle->start(1500); // 其他命令1.5秒超时
-    }
-    // 发送指令,在发送结束的handleBytesWritten中,设置接收状态,
-    // 接收函数 readData 中确认指令是否执行完毕,然后执行下一个指令。
+    // 此函数已废弃,发送逻辑现在由TestPortController内部处理
+    Q_UNUSED(port_index);
+    Q_UNUSED(cmd);
 }
 
 // 向后兼容:uart_send_data1
@@ -905,39 +396,11 @@ void MainWindow::uart_send_data4(QString cmd)
     uart_send_data(3, cmd);
 }
 
-// 统一的spp_timer_callback函数
+// 统一的spp_timer_callback函数(已废弃,逻辑在TestPortController中)
 void MainWindow::spp_timer_callback(int port_index)
 {
-    if (port_index < 0 || port_index >= MAX_SERIAL_PORTS) {
-        qDebug() << tr("无效的端口索引:") << port_index;
-        return;
-    }
-    
-    SerialPortContext *ctx = port_contexts[port_index];
-    if (ctx == nullptr) {
-        qDebug() << tr("串口上下文未初始化,端口索引:") << port_index;
-        return;
-    }
-    
-    ctx->uart_rx_flag = false;
-    qDebug() << tr("端口%1 AT命令超时:").arg(port_index) << ctx->G_cmd;
-    
-    if (ctx->G_cmd == ATCMD_ADD_VOTE) {
-        uart_send_data(port_index, ATCMD_ADD_VOTE);
-    } else if (ctx->G_cmd.contains("GETIDS")) {
-        // GETIDS命令超时,跳过CPU ID获取,继续执行关机
-        ui_display(port_index, tr("获取CPU ID超时,跳过此步骤\r\n"), LOG_DIRECT_OUT);
-        
-        // 直接跳到关机步骤
-        ctx->cmd_index = 4; // 设置为4,这样下次会执行case 5(关机)
-        ctx->uart_rx_flag = false;
-        uart_process(port_index); // 直接处理,跳过CPU ID
-    } else {
-        ui_display(port_index, tr("AT命令超时: %1\r\n").arg(ctx->G_cmd), LOG_DIRECT_OUT);
-        if (ctx->spp_timer_handle && ctx->spp_timer_handle->isActive()) {
-            ctx->spp_timer_handle->stop();
-        }
-    }
+    // 此函数已废弃,超时处理现在由TestPortController内部处理
+    Q_UNUSED(port_index);
 }
 
 // 向后兼容:spp_timer_callback1
@@ -945,55 +408,79 @@ void MainWindow::spp_timer_callback1()
 {
     spp_timer_callback(0);
 }
-// uart收到的数据进行回显到显示栏
+// uart收到的数据进行回显到显示栏(已废弃,现在由TestPortController处理)
 void MainWindow::uart_rx_dispaly1(int buf_len, u8Piont buf)
 {
-    // 使用端口0的上下文
-    SerialPortContext *ctx = port_contexts[0];
-    if (ctx) {
-        ctx->uart_rx_flag = true;
-        if (ctx->uart_rx_Ignoring_display) {
-            QString str((char *)buf);
-            if(str.contains("ADDR")){
-//            ui->ledit_dongle_mac->setText(str.mid(str.indexOf("=",0)+1,12));
-            }
-            return;
-        }
+    Q_UNUSED(buf_len);
+    Q_UNUSED(buf);
+    // 此函数已废弃,数据回显现在由TestPortController处理
+    if (buf) {
+        free(buf);
     }
-    QString str;
-    QByteArray data((const char*)buf, buf_len);
-//    if (ui->ckbox_Hex_Display->isChecked()) {
-//        for (int i = 0; i < data.size(); i++) {
-//           str += QString("%1 ").arg((quint8)data.at(i), 2, 16, QChar('0'));
-//        }
-//        str=str.toUpper();
-//    } else {
-//        for (int i = 0; i < data.size(); i++) {
-//           str += QString(data.at(i));
-//        }
-//    }
-    ui_display1(str,true);
-    free(buf);
 }
 
+// 统一的串口选择更新函数 - 更新所有4个串口选择框
 void MainWindow::uart_com_select()
 {
-    ui->cbox_uart_com_select_1->clear();
+    // 获取可用串口列表
     QStringList strlist = uart_get_enable_comm_or_port();
+    
+    // 排序串口列表(按COM编号)
     qSort(strlist.begin(), strlist.end(),[](const QString& s1, const QString& s2){
         QString a1=s1;QString a2=s2;
-        return a1.replace("COM","").toInt() < a2.replace("COM","").toInt(); });
-        ui->cbox_uart_com_select_1->addItems(strlist);
+        return a1.replace("COM","").toInt() < a2.replace("COM","").toInt(); 
+    });
+    
+    // 保存当前选中的串口(如果有)
+    QStringList currentSelections;
+    currentSelections << ui->cbox_uart_com_select_1->currentText();
+    currentSelections << ui->cbox_uart_com_select_2->currentText();
+    currentSelections << ui->cbox_uart_com_select_3->currentText();
+    currentSelections << ui->cbox_uart_com_select_4->currentText();
+    
+    // 更新所有4个串口选择框
+    QComboBox *comboBoxes[] = {
+        ui->cbox_uart_com_select_1,
+        ui->cbox_uart_com_select_2,
+        ui->cbox_uart_com_select_3,
+        ui->cbox_uart_com_select_4
+    };
+    
+    for (int i = 0; i < MAX_SERIAL_PORTS; i++) {
+        comboBoxes[i]->clear();
+        // 添加 "None" 作为第一个选项(默认值)
+        comboBoxes[i]->addItem(tr("None"));
+        // 添加可用串口列表
+        comboBoxes[i]->addItems(strlist);
+        
+        // 尝试恢复之前的选择(如果仍然存在)
+        if (!currentSelections[i].isEmpty() && currentSelections[i] != tr("None")) {
+            int index = comboBoxes[i]->findText(currentSelections[i]);
+            if (index >= 0) {
+                comboBoxes[i]->setCurrentIndex(index);
+            } else {
+                // 如果之前的串口不存在了,设置为 "None"
+                comboBoxes[i]->setCurrentIndex(0);
+            }
+        } else {
+            // 如果没有之前的选择,设置为 "None"
+            comboBoxes[i]->setCurrentIndex(0);
+        }
+    }
+    
+    qDebug() << tr("已更新所有串口选择框,共找到") << strlist.size() << tr("个可用串口");
 }
 void MainWindow::uart_com_switch(QString com)
 {
+    Q_UNUSED(com);
     QString str_uart_baud = ui->cbox_uart_baud_select->currentText();
-
+    Q_UNUSED(str_uart_baud);
 }
 void MainWindow::uart_baud_switch(QString baud)
 {
-   QString str_com = ui->cbox_uart_com_select_1->currentText();
-
+    Q_UNUSED(baud);
+    QString str_com = ui->cbox_uart_com_select_1->currentText();
+    Q_UNUSED(str_com);
 }
 // nIndex为索引号 bValue选择返回值为key还是value,默认为value
 QString MainWindow::uart_get_comm_or_port(int nIndex, bool bValue)
@@ -1056,7 +543,10 @@ QStringList MainWindow::uart_get_enable_comm_or_port()
 /* ------------------------------------------------------------------- */
 void MainWindow::spp_connected_callback()
 {
-    ui_display1("com send cmd failed! ",false);
+    // 使用端口0的控制器
+    if (port_controller1) {
+        port_controller1->triggerDisplayMessage("com send cmd failed! ", false);
+    }
 }
 // 向后兼容:spp_timer_callback2/3/4
 void MainWindow::spp_timer_callback2()
@@ -1074,7 +564,7 @@ void MainWindow::spp_timer_callback4()
 
 // spp_timer_callback1已在后面实现为向后兼容函数
 
-// 统一的spp_connect函数
+// 统一的spp_connect函数(使用TestPortController)
 void MainWindow::spp_connect(int port_index)
 {
     if (port_index < 0 || port_index >= MAX_SERIAL_PORTS) {
@@ -1082,105 +572,30 @@ void MainWindow::spp_connect(int port_index)
         return;
     }
     
-    SerialPortContext *ctx = port_contexts[port_index];
-    if (ctx == nullptr || ctx->serialport == nullptr) {
-        qDebug() << tr("串口上下文未初始化,端口索引:") << port_index;
+    TestPortController* controller = getPortController(port_index);
+    if (!controller) {
+        qDebug() << tr("端口控制器未初始化,端口索引:") << port_index;
         return;
     }
     
     UIPortWidgets widgets = getUIPortWidgets(port_index);
     
-    if (ctx->working_state == false) {
+    if (!controller->isWorking()) {
         // 开始工作
         QString baud_rate = ui->cbox_uart_baud_select->currentText();
         QString com_name = widgets.cbox_uart_com_select->currentText();
-
-        qDebug() << tr("=== 开始连接串口%1 ===").arg(port_index + 1);
-        qDebug() << tr("串口名称:") << com_name;
-        qDebug() << tr("波特率:") << baud_rate;
-
-        ctx->serialport->setPortName(com_name);
-        ctx->serialport->setBaudRate(baud_rate.toInt());
-        // 设置串口参数以提高兼容性
-        ctx->serialport->setDataBits(QSerialPort::Data8);
-        ctx->serialport->setParity(QSerialPort::NoParity);
-        ctx->serialport->setStopBits(QSerialPort::OneStop);
-        ctx->serialport->setFlowControl(QSerialPort::NoFlowControl);
-        
-        // 设置更大的读缓冲区,提高数据处理能力
-        ctx->serialport->setReadBufferSize(32768); // 32KB缓冲区
         
-        qDebug() << tr("端口%1串口配置 - 波特率:").arg(port_index) << ctx->serialport->baudRate();
-        qDebug() << tr("端口%1串口配置 - 数据位:").arg(port_index) << ctx->serialport->dataBits();
-        qDebug() << tr("端口%1串口配置 - 停止位:").arg(port_index) << ctx->serialport->stopBits();
-        qDebug() << tr("端口%1串口配置 - 校验位:").arg(port_index) << ctx->serialport->parity();
-        qDebug() << tr("端口%1串口配置 - 流控制:").arg(port_index) << ctx->serialport->flowControl();
-        qDebug() << tr("端口%1串口读缓冲区大小:").arg(port_index) << ctx->serialport->readBufferSize();
-
-        widgets.txtb_dispaly->clear();
-        if (ctx->serialport->isOpen()) {
-            qDebug() << tr("端口%1串口已经打开,重置命令索引").arg(port_index);
-            ctx->cmd_index = 0;
-        } else {
-            if (ctx->serialport->open(QIODevice::ReadWrite)) {
-                qDebug() << tr("端口%1串口打开成功,连接信号槽").arg(port_index);
-                
-                // 使用lambda捕获port_index来连接信号槽
-                connect(ctx->serialport, &QSerialPort::readyRead, [this, port_index]() {
-                    this->readData(port_index);
-                });
-                connect(ctx->serialport, &QSerialPort::bytesWritten, [this, port_index](qint64 bytes) {
-                    this->handleBytesWritten(port_index, bytes);
-                });
-                
-                ctx->cmd_index = 0;
-            } else {
-                qDebug() << tr("端口%1串口打开失败:").arg(port_index) << ctx->serialport->errorString();
-                QMessageBox::critical(this, tr("Error"), ctx->serialport->errorString());
-                ui_display(port_index, tr("Open error\r\n"), false);
-                return;
-            }
+        // 检查是否选择了 "None"
+        if (com_name.isEmpty() || com_name == tr("None") || com_name == "None") {
+            qDebug() << tr("端口%1未选择串口(选择了None),跳过打开串口操作").arg(port_index + 1);
+            QMessageBox::information(this, tr("提示"), tr("端口%1未选择串口,请先选择串口").arg(port_index + 1));
+            return;
         }
-
-        // 开始工作
-        qDebug() << tr("端口%1开始写地址工作模式").arg(port_index);
-        ctx->working_state = true;
-        ctx->write_fail_count = 0;
-        ctx->write_success_count = 0;
-        
-        // 初始化开机检测缓存
-        ctx->boot_detect_buffer.clear();
-        ctx->waiting_cmd = false; // 重置等待命令状态
-        ctx->startup_complete_detected = false; // 重置启动完成检测标志
-        qDebug() << tr("端口%1初始化开机检测缓存").arg(port_index);
         
-        widgets.label_result_fail->setText(tr("失败%1").arg(ctx->write_fail_count));
-        widgets.label_result_success->setText(tr("成功%1").arg(ctx->write_success_count));
-        widgets.pbtn_spp_reconnect->setText(tr("停止写地址"));
-        widgets.label_runtime_status->setText(tr("等待手表开机"));
-        
-        qDebug() << tr("端口%1工作状态设置: working_state = true").arg(port_index);
-        qDebug() << tr("端口%1等待检测手表开机信号:").arg(port_index) << BOOT_UP_MSG;
-        qDebug() << tr("端口%1等待检测命令时机信号:").arg(port_index) << TIME_FOR_CMD;
-
-        qDebug() << settings::getInstance().getmacStatusFull();
+        controller->connectPort(com_name, baud_rate.toInt());
     } else {
         // 停止工作
-        qDebug() << tr("端口%1停止写地址工作模式").arg(port_index);
-        widgets.pbtn_spp_reconnect->setText(tr("开始写地址"));
-        widgets.label_runtime_status->setText(tr("已停止写地址..."));
-        ctx->working_state = false;
-        
-        // 清空开机检测缓存
-        ctx->boot_detect_buffer.clear();
-        qDebug() << tr("端口%1清空开机检测缓存").arg(port_index);
-        
-        widgets.txtb_dispaly->clear();
-        if (ctx->serialport->isOpen()) {
-            ctx->serialport->close();
-        }
-        disconnect(ctx->serialport, &QSerialPort::readyRead, this, nullptr);
-        disconnect(ctx->serialport, &QSerialPort::bytesWritten, this, nullptr);
+        controller->disconnectPort();
     }
 }
 
@@ -1191,26 +606,12 @@ void MainWindow::spp_connect_1()
 }
 
 
-// 统一的handleBytesWritten函数
+// 统一的handleBytesWritten函数(已废弃,逻辑在TestPortController中)
 void MainWindow::handleBytesWritten(int port_index, qint64 bytes)
 {
-    if (port_index < 0 || port_index >= MAX_SERIAL_PORTS) {
-        qDebug() << tr("无效的端口索引:") << port_index;
-        return;
-    }
-    
-    SerialPortContext *ctx = port_contexts[port_index];
-    if (ctx == nullptr) {
-        qDebug() << tr("串口上下文未初始化,端口索引:") << port_index;
-        return;
-    }
-    
-    qDebug() << tr("端口%1 handleBytesWritten m_bytesToWrite").arg(port_index) << ctx->m_bytesToWrite << tr("written") << bytes;
-    ctx->m_bytesToWrite -= bytes;
-    if (ctx->m_bytesToWrite == 0) {
-        ctx->uart_rx_flag = true;
-        ctx->uart_rx_buff_array.clear();
-    }
+    // 此函数已废弃,发送完成处理现在由TestPortController内部处理
+    Q_UNUSED(port_index);
+    Q_UNUSED(bytes);
 }
 
 // 向后兼容:handleBytesWritten1
@@ -1234,23 +635,11 @@ void MainWindow::spp_connect_4()
 
 void MainWindow::spp_connect_all()
 {
-    // 使用端口0的上下文
-    SerialPortContext *ctx = port_contexts[0];
-    if (ctx) {
-        ctx->uart_rx_Ignoring_display = true;
-    }
-//    dongle_is_connected = false;
-//    dongle_try_count = 0;
-//    spp_try_count = 0;
-//    uapi_uart_callback_register(uart_callback);
-//    at_handler->at_send_cmd_board(DONGLE_MODE_ADDR,NULL);
-    ui_display1("spp connectting...",false);
-
-    // spp查询定时器周期为1500ms
-    if (spp_timer_handles[0]) {
-        spp_timer_handles[0]->start(1500);
+    // 使用端口0的控制器
+    if (port_controller1) {
+        port_controller1->displayMessage("spp connectting...", false);
     }
-//    ui->pbtn_spp_connect->setEnabled(false);
+    // 注意:此函数的功能可能需要根据实际需求调整
 }
 
 //void MainWindow::at_check_send_status(bool flag)
index eedfe6c..8e2797e 100644 (file)
@@ -19,7 +19,7 @@
 #include "sqldbmanager.h"
 
 #include "settings.h"
-#include "serial_port_context.h"
+#include "test_port_controller.h"
 #include <QTextBrowser>
 #include <QLabel>
 #include <QLineEdit>
@@ -49,27 +49,16 @@ private:
     bool LOG_DIRECT_OUT=false;
     bool LOG_DIRECT_IN=true;
     /* ------------------------uart------------------------------- */
-    // 统一配置:4个串口的上下文数组
-    SerialPortContext *port_contexts[MAX_SERIAL_PORTS];
-    QTimer *spp_timer_handles[MAX_SERIAL_PORTS];
-    Result_Thread *result_threads[MAX_SERIAL_PORTS];
-    
-    // 向后兼容:保留原有变量名(映射到port_contexts[0])
-    // 这些变量将在实现中通过宏或内联函数映射到port_contexts[0]
-    QSerialPort *serialport1;
-    QSerialPort *serialport2;
-    QSerialPort *serialport3;
-    QSerialPort *serialport4;
-    Result_Thread *result_thread1;
-    Result_Thread *result_thread2;
-    Result_Thread *result_thread3;
-    Result_Thread *result_thread4;
+    // 测试端口控制器实例(不使用数组)
+    TestPortController *port_controller1;
+    TestPortController *port_controller2;
+    TestPortController *port_controller3;
+    TestPortController *port_controller4;
     
     // UI控件映射辅助结构
     struct UIPortWidgets {
         QTextBrowser *txtb_dispaly;
         QLabel *label_runtime_status;
-        QLineEdit *ledit_spp_addr;
         QLabel *label_result_success;
         QLabel *label_result_fail;
         QComboBox *cbox_uart_com_select;  // 串口选择框
@@ -79,22 +68,28 @@ private:
     // 获取指定端口的UI控件
     UIPortWidgets getUIPortWidgets(int port_index);
     
-    // 统一处理函数(支持多端口)
+    // 获取指定端口的控制器
+    TestPortController* getPortController(int port_index);
+    
+    // 连接端口控制器的信号槽
+    void connectPortControllerSignals(TestPortController* controller, int port_index);
+    
+    // 向后兼容函数(保留原有接口)
+    void ui_display1(QString str,bool inOrOut);
+    void ui_show_result1(QString msg,bool success);
+    void poweroff_watch1();
+    void uart_send_data1(QString cmd);
+    
+    // 废弃的统一处理函数(保留用于向后兼容,实际逻辑在TestPortController中)
     void readData(int port_index);
     void uart_process(int port_index);
     void uart_send_data(int port_index, QString cmd);
     void handleBytesWritten(int port_index, qint64 bytes);
     void spp_timer_callback(int port_index);
     void spp_connect(int port_index);
+    void poweroff_watch(int port_index);
     void ui_display(int port_index, QString str, bool inOrOut);
     void ui_show_result(int port_index, QString msg, bool success);
-    void poweroff_watch(int port_index);
-    
-    // 向后兼容:保留原有函数名(调用统一函数,port_index=0)
-    void ui_display1(QString str,bool inOrOut);
-    void ui_show_result1(QString msg,bool success);
-    void poweroff_watch1();
-    void uart_send_data1(QString cmd);
 
     /*----------写地址任务相关变量---end------------*/
 
index 3d8081f..b51b7a9 100644 (file)
-<?xml version="1.0" encoding="UTF-8"?>\r
-<ui version="4.0">\r
- <class>MainWindow</class>\r
- <widget class="QMainWindow" name="MainWindow">\r
-  <property name="geometry">\r
-   <rect>\r
-    <x>0</x>\r
-    <y>0</y>\r
-    <width>1398</width>\r
-    <height>758</height>\r
-   </rect>\r
-  </property>\r
-  <property name="font">\r
-   <font>\r
-    <family>黑体</family>\r
-    <weight>50</weight>\r
-    <bold>false</bold>\r
-   </font>\r
-  </property>\r
-  <property name="windowTitle">\r
-   <string>BTMacWriteTool V1.3</string>\r
-  </property>\r
-  <property name="windowIcon">\r
-   <iconset>\r
-    <normaloff>:/icon/windows.ico</normaloff>:/icon/windows.ico</iconset>\r
-  </property>\r
-  <property name="windowOpacity">\r
-   <double>1.000000000000000</double>\r
-  </property>\r
-  <property name="layoutDirection">\r
-   <enum>Qt::LeftToRight</enum>\r
-  </property>\r
-  <widget class="QWidget" name="centralwidget">\r
-   <widget class="QWidget" name="verticalLayoutWidget_2">\r
-    <property name="geometry">\r
-     <rect>\r
-      <x>1060</x>\r
-      <y>20</y>\r
-      <width>306</width>\r
-      <height>701</height>\r
-     </rect>\r
-    </property>\r
-    <property name="font">\r
-     <font>\r
-      <family>Arial</family>\r
-      <pointsize>14</pointsize>\r
-     </font>\r
-    </property>\r
-    <layout class="QVBoxLayout" name="verticalLayout_2">\r
-     <item>\r
-      <widget class="QComboBox" name="cbox_uart_baud_select">\r
-       <property name="sizePolicy">\r
-        <sizepolicy hsizetype="Expanding" vsizetype="Fixed">\r
-         <horstretch>0</horstretch>\r
-         <verstretch>0</verstretch>\r
-        </sizepolicy>\r
-       </property>\r
-       <property name="font">\r
-        <font>\r
-         <family>Arial</family>\r
-         <pointsize>14</pointsize>\r
-         <weight>50</weight>\r
-         <bold>false</bold>\r
-        </font>\r
-       </property>\r
-       <property name="cursor">\r
-        <cursorShape>ArrowCursor</cursorShape>\r
-       </property>\r
-       <property name="editable">\r
-        <bool>false</bool>\r
-       </property>\r
-       <property name="currentText">\r
-        <string>500000</string>\r
-       </property>\r
-       <property name="currentIndex">\r
-        <number>11</number>\r
-       </property>\r
-       <property name="duplicatesEnabled">\r
-        <bool>true</bool>\r
-       </property>\r
-       <item>\r
-        <property name="text">\r
-         <string>4800</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>9600</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>14400</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>19200</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>38400</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>57600</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>115200</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>128000</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>230400</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>256000</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>460800</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>500000</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>512000</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>600000</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>750000</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>921600</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>1000000</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>1500000</string>\r
-        </property>\r
-       </item>\r
-       <item>\r
-        <property name="text">\r
-         <string>2000000</string>\r
-        </property>\r
-       </item>\r
-      </widget>\r
-     </item>\r
-     <item>\r
-      <widget class="QPushButton" name="pbtn_spp_connect_all">\r
-       <property name="enabled">\r
-        <bool>true</bool>\r
-       </property>\r
-       <property name="sizePolicy">\r
-        <sizepolicy hsizetype="Expanding" vsizetype="Fixed">\r
-         <horstretch>0</horstretch>\r
-         <verstretch>0</verstretch>\r
-        </sizepolicy>\r
-       </property>\r
-       <property name="font">\r
-        <font>\r
-         <family>Arial</family>\r
-         <pointsize>14</pointsize>\r
-         <weight>50</weight>\r
-         <bold>false</bold>\r
-        </font>\r
-       </property>\r
-       <property name="text">\r
-        <string>全部开始测试</string>\r
-       </property>\r
-       <property name="checkable">\r
-        <bool>false</bool>\r
-       </property>\r
-      </widget>\r
-     </item>\r
-     <item>\r
-      <widget class="QTextBrowser" name="textBrowser_result">\r
-       <property name="font">\r
-        <font>\r
-         <family>Arial</family>\r
-         <pointsize>14</pointsize>\r
-        </font>\r
-       </property>\r
-       <property name="html">\r
-        <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;\r
-&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;\r
-p, li { white-space: pre-wrap; }\r
-&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;\r
-&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;\r
-&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>\r
-       </property>\r
-      </widget>\r
-     </item>\r
-     <item>\r
-      <widget class="QPushButton" name="pushButton_openlogfolder">\r
-       <property name="font">\r
-        <font>\r
-         <family>Arial</family>\r
-         <pointsize>14</pointsize>\r
-        </font>\r
-       </property>\r
-       <property name="text">\r
-        <string>打开日志路径</string>\r
-       </property>\r
-      </widget>\r
-     </item>\r
-    </layout>\r
-   </widget>\r
-   <widget class="QSplitter" name="splitter">\r
-    <property name="geometry">\r
-     <rect>\r
-      <x>10</x>\r
-      <y>20</y>\r
-      <width>1032</width>\r
-      <height>701</height>\r
-     </rect>\r
-    </property>\r
-    <property name="font">\r
-     <font>\r
-      <family>Arial</family>\r
-      <pointsize>14</pointsize>\r
-     </font>\r
-    </property>\r
-    <property name="orientation">\r
-     <enum>Qt::Horizontal</enum>\r
-    </property>\r
-    <widget class="QWidget" name="verticalLayoutWidget">\r
-     <property name="font">\r
-      <font>\r
-       <family>Arial</family>\r
-       <pointsize>14</pointsize>\r
-      </font>\r
-     </property>\r
-     <layout class="QVBoxLayout" name="verticalLayout">\r
-      <item>\r
-       <widget class="MyComboBox" name="cbox_uart_com_select_1">\r
-        <property name="sizePolicy">\r
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">\r
-          <horstretch>0</horstretch>\r
-          <verstretch>0</verstretch>\r
-         </sizepolicy>\r
-        </property>\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-          <weight>50</weight>\r
-          <bold>false</bold>\r
-         </font>\r
-        </property>\r
-        <item>\r
-         <property name="text">\r
-          <string>COM1</string>\r
-         </property>\r
-        </item>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <widget class="QLineEdit" name="ledit_spp_addr_1">\r
-        <property name="sizePolicy">\r
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">\r
-          <horstretch>0</horstretch>\r
-          <verstretch>0</verstretch>\r
-         </sizepolicy>\r
-        </property>\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-          <weight>50</weight>\r
-          <bold>false</bold>\r
-         </font>\r
-        </property>\r
-        <property name="whatsThis">\r
-         <string/>\r
-        </property>\r
-        <property name="placeholderText">\r
-         <string>MAC地址</string>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <widget class="QPushButton" name="pbtn_spp_reconnect_1">\r
-        <property name="enabled">\r
-         <bool>true</bool>\r
-        </property>\r
-        <property name="sizePolicy">\r
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">\r
-          <horstretch>0</horstretch>\r
-          <verstretch>0</verstretch>\r
-         </sizepolicy>\r
-        </property>\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-          <weight>50</weight>\r
-          <bold>false</bold>\r
-         </font>\r
-        </property>\r
-        <property name="text">\r
-         <string>开始测试</string>\r
-        </property>\r
-        <property name="checkable">\r
-         <bool>false</bool>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <widget class="QTextBrowser" name="txtb_dispaly">\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-         </font>\r
-        </property>\r
-        <property name="mouseTracking">\r
-         <bool>true</bool>\r
-        </property>\r
-        <property name="styleSheet">\r
-         <string notr="true">QTextBrowser{background-color:rgb(26, 26, 26);\r
-                       color:rgb(127, 255, 0)}</string>\r
-        </property>\r
-        <property name="lineWidth">\r
-         <number>1</number>\r
-        </property>\r
-        <property name="verticalScrollBarPolicy">\r
-         <enum>Qt::ScrollBarAlwaysOn</enum>\r
-        </property>\r
-        <property name="textInteractionFlags">\r
-         <set>Qt::TextBrowserInteraction</set>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <layout class="QHBoxLayout" name="horizontalLayout">\r
-        <item>\r
-         <widget class="QLabel" name="label_result_success1">\r
-          <property name="autoFillBackground">\r
-           <bool>false</bool>\r
-          </property>\r
-          <property name="styleSheet">\r
-           <string notr="true">color:rgb(0, 170, 0);\r
-font: 75 18pt &quot;Agra&quot;;</string>\r
-          </property>\r
-          <property name="lineWidth">\r
-           <number>0</number>\r
-          </property>\r
-          <property name="text">\r
-           <string>成功0</string>\r
-          </property>\r
-         </widget>\r
-        </item>\r
-        <item>\r
-         <widget class="QLabel" name="label_result_fail1">\r
-          <property name="autoFillBackground">\r
-           <bool>false</bool>\r
-          </property>\r
-          <property name="styleSheet">\r
-           <string notr="true">color:rgb(170, 0, 0);\r
-font: 75 18pt &quot;Agra&quot;;</string>\r
-          </property>\r
-          <property name="lineWidth">\r
-           <number>0</number>\r
-          </property>\r
-          <property name="text">\r
-           <string>失败0</string>\r
-          </property>\r
-         </widget>\r
-        </item>\r
-       </layout>\r
-      </item>\r
-      <item>\r
-       <widget class="QLabel" name="label_runtime_status1">\r
-        <property name="text">\r
-         <string>已停止测试...</string>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-     </layout>\r
-    </widget>\r
-    <widget class="QWidget" name="verticalLayoutWidget_3">\r
-     <property name="font">\r
-      <font>\r
-       <family>Arial</family>\r
-       <pointsize>14</pointsize>\r
-      </font>\r
-     </property>\r
-     <layout class="QVBoxLayout" name="verticalLayout_3">\r
-      <item>\r
-       <widget class="MyComboBox" name="cbox_uart_com_select_2">\r
-        <property name="sizePolicy">\r
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">\r
-          <horstretch>0</horstretch>\r
-          <verstretch>0</verstretch>\r
-         </sizepolicy>\r
-        </property>\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-          <weight>50</weight>\r
-          <bold>false</bold>\r
-         </font>\r
-        </property>\r
-        <item>\r
-         <property name="text">\r
-          <string>COM1</string>\r
-         </property>\r
-        </item>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <widget class="QLineEdit" name="ledit_spp_addr_2">\r
-        <property name="sizePolicy">\r
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">\r
-          <horstretch>0</horstretch>\r
-          <verstretch>0</verstretch>\r
-         </sizepolicy>\r
-        </property>\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-          <weight>50</weight>\r
-          <bold>false</bold>\r
-         </font>\r
-        </property>\r
-        <property name="whatsThis">\r
-         <string/>\r
-        </property>\r
-        <property name="placeholderText">\r
-         <string>MAC地址</string>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <widget class="QPushButton" name="pbtn_spp_reconnect_2">\r
-        <property name="enabled">\r
-         <bool>true</bool>\r
-        </property>\r
-        <property name="sizePolicy">\r
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">\r
-          <horstretch>0</horstretch>\r
-          <verstretch>0</verstretch>\r
-         </sizepolicy>\r
-        </property>\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-          <weight>50</weight>\r
-          <bold>false</bold>\r
-         </font>\r
-        </property>\r
-        <property name="text">\r
-         <string>开始测试</string>\r
-        </property>\r
-        <property name="checkable">\r
-         <bool>false</bool>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <widget class="QTextBrowser" name="txtb_dispaly_2">\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-         </font>\r
-        </property>\r
-        <property name="mouseTracking">\r
-         <bool>true</bool>\r
-        </property>\r
-        <property name="styleSheet">\r
-         <string notr="true">QTextBrowser{background-color:rgb(26, 26, 26);\r
-                       color:rgb(127, 255, 0)}</string>\r
-        </property>\r
-        <property name="verticalScrollBarPolicy">\r
-         <enum>Qt::ScrollBarAlwaysOn</enum>\r
-        </property>\r
-        <property name="textInteractionFlags">\r
-         <set>Qt::TextBrowserInteraction</set>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <layout class="QHBoxLayout" name="horizontalLayout_2">\r
-        <item>\r
-         <widget class="QLabel" name="label_result_success2">\r
-          <property name="autoFillBackground">\r
-           <bool>false</bool>\r
-          </property>\r
-          <property name="styleSheet">\r
-           <string notr="true">color:rgb(0, 170, 0);\r
-font: 75 18pt &quot;Agra&quot;;</string>\r
-          </property>\r
-          <property name="lineWidth">\r
-           <number>0</number>\r
-          </property>\r
-          <property name="text">\r
-           <string>成功0</string>\r
-          </property>\r
-         </widget>\r
-        </item>\r
-        <item>\r
-         <widget class="QLabel" name="label_result_fail2">\r
-          <property name="autoFillBackground">\r
-           <bool>false</bool>\r
-          </property>\r
-          <property name="styleSheet">\r
-           <string notr="true">color:rgb(170, 0, 0);\r
-font: 75 18pt &quot;Agra&quot;;</string>\r
-          </property>\r
-          <property name="lineWidth">\r
-           <number>0</number>\r
-          </property>\r
-          <property name="text">\r
-           <string>失败0</string>\r
-          </property>\r
-         </widget>\r
-        </item>\r
-       </layout>\r
-      </item>\r
-      <item>\r
-       <widget class="QLabel" name="label_runtime_status2">\r
-        <property name="text">\r
-         <string>已停止测试...</string>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-     </layout>\r
-    </widget>\r
-    <widget class="QWidget" name="verticalLayoutWidget_4">\r
-     <property name="font">\r
-      <font>\r
-       <family>Arial</family>\r
-       <pointsize>14</pointsize>\r
-      </font>\r
-     </property>\r
-     <layout class="QVBoxLayout" name="verticalLayout_4">\r
-      <item>\r
-       <widget class="MyComboBox" name="cbox_uart_com_select_3">\r
-        <property name="sizePolicy">\r
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">\r
-          <horstretch>0</horstretch>\r
-          <verstretch>0</verstretch>\r
-         </sizepolicy>\r
-        </property>\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-          <weight>50</weight>\r
-          <bold>false</bold>\r
-         </font>\r
-        </property>\r
-        <item>\r
-         <property name="text">\r
-          <string>COM1</string>\r
-         </property>\r
-        </item>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <widget class="QLineEdit" name="ledit_spp_addr_3">\r
-        <property name="sizePolicy">\r
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">\r
-          <horstretch>0</horstretch>\r
-          <verstretch>0</verstretch>\r
-         </sizepolicy>\r
-        </property>\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-          <weight>50</weight>\r
-          <bold>false</bold>\r
-         </font>\r
-        </property>\r
-        <property name="whatsThis">\r
-         <string/>\r
-        </property>\r
-        <property name="placeholderText">\r
-         <string>MAC地址</string>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <widget class="QPushButton" name="pbtn_spp_reconnect_3">\r
-        <property name="enabled">\r
-         <bool>true</bool>\r
-        </property>\r
-        <property name="sizePolicy">\r
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">\r
-          <horstretch>0</horstretch>\r
-          <verstretch>0</verstretch>\r
-         </sizepolicy>\r
-        </property>\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-          <weight>50</weight>\r
-          <bold>false</bold>\r
-         </font>\r
-        </property>\r
-        <property name="text">\r
-         <string>开始测试</string>\r
-        </property>\r
-        <property name="checkable">\r
-         <bool>false</bool>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <widget class="QTextBrowser" name="txtb_dispaly_3">\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-         </font>\r
-        </property>\r
-        <property name="mouseTracking">\r
-         <bool>true</bool>\r
-        </property>\r
-        <property name="styleSheet">\r
-         <string notr="true">QTextBrowser{background-color:rgb(26, 26, 26);\r
-                       color:rgb(127, 255, 0)}</string>\r
-        </property>\r
-        <property name="verticalScrollBarPolicy">\r
-         <enum>Qt::ScrollBarAlwaysOn</enum>\r
-        </property>\r
-        <property name="textInteractionFlags">\r
-         <set>Qt::TextBrowserInteraction</set>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <layout class="QHBoxLayout" name="horizontalLayout_3">\r
-        <item>\r
-         <widget class="QLabel" name="label_result_success3">\r
-          <property name="autoFillBackground">\r
-           <bool>false</bool>\r
-          </property>\r
-          <property name="styleSheet">\r
-           <string notr="true">color:rgb(0, 170, 0);\r
-font: 75 18pt &quot;Agra&quot;;</string>\r
-          </property>\r
-          <property name="lineWidth">\r
-           <number>0</number>\r
-          </property>\r
-          <property name="text">\r
-           <string>成功0</string>\r
-          </property>\r
-         </widget>\r
-        </item>\r
-        <item>\r
-         <widget class="QLabel" name="label_result_fail3">\r
-          <property name="autoFillBackground">\r
-           <bool>false</bool>\r
-          </property>\r
-          <property name="styleSheet">\r
-           <string notr="true">color:rgb(170, 0, 0);\r
-font: 75 18pt &quot;Agra&quot;;</string>\r
-          </property>\r
-          <property name="lineWidth">\r
-           <number>0</number>\r
-          </property>\r
-          <property name="text">\r
-           <string>失败0</string>\r
-          </property>\r
-         </widget>\r
-        </item>\r
-       </layout>\r
-      </item>\r
-      <item>\r
-       <widget class="QLabel" name="label_runtime_status3">\r
-        <property name="text">\r
-         <string>已停止测试...</string>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-     </layout>\r
-    </widget>\r
-    <widget class="QWidget" name="verticalLayoutWidget_5">\r
-     <property name="font">\r
-      <font>\r
-       <family>Arial</family>\r
-       <pointsize>14</pointsize>\r
-      </font>\r
-     </property>\r
-     <layout class="QVBoxLayout" name="verticalLayout_5">\r
-      <item>\r
-       <widget class="MyComboBox" name="cbox_uart_com_select_4">\r
-        <property name="sizePolicy">\r
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">\r
-          <horstretch>0</horstretch>\r
-          <verstretch>0</verstretch>\r
-         </sizepolicy>\r
-        </property>\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-          <weight>50</weight>\r
-          <bold>false</bold>\r
-         </font>\r
-        </property>\r
-        <item>\r
-         <property name="text">\r
-          <string>COM1</string>\r
-         </property>\r
-        </item>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <widget class="QLineEdit" name="ledit_spp_addr_4">\r
-        <property name="sizePolicy">\r
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">\r
-          <horstretch>0</horstretch>\r
-          <verstretch>0</verstretch>\r
-         </sizepolicy>\r
-        </property>\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-          <weight>50</weight>\r
-          <bold>false</bold>\r
-         </font>\r
-        </property>\r
-        <property name="whatsThis">\r
-         <string/>\r
-        </property>\r
-        <property name="placeholderText">\r
-         <string>MAC地址</string>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <widget class="QPushButton" name="pbtn_spp_reconnect_4">\r
-        <property name="enabled">\r
-         <bool>true</bool>\r
-        </property>\r
-        <property name="sizePolicy">\r
-         <sizepolicy hsizetype="Expanding" vsizetype="Fixed">\r
-          <horstretch>0</horstretch>\r
-          <verstretch>0</verstretch>\r
-         </sizepolicy>\r
-        </property>\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-          <weight>50</weight>\r
-          <bold>false</bold>\r
-         </font>\r
-        </property>\r
-        <property name="text">\r
-         <string>开始测试</string>\r
-        </property>\r
-        <property name="checkable">\r
-         <bool>false</bool>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <widget class="QTextBrowser" name="txtb_dispaly_4">\r
-        <property name="font">\r
-         <font>\r
-          <family>Arial</family>\r
-          <pointsize>14</pointsize>\r
-         </font>\r
-        </property>\r
-        <property name="mouseTracking">\r
-         <bool>true</bool>\r
-        </property>\r
-        <property name="styleSheet">\r
-         <string notr="true">QTextBrowser{background-color:rgb(26, 26, 26);\r
-                       color:rgb(127, 255, 0)}</string>\r
-        </property>\r
-        <property name="verticalScrollBarPolicy">\r
-         <enum>Qt::ScrollBarAlwaysOn</enum>\r
-        </property>\r
-        <property name="textInteractionFlags">\r
-         <set>Qt::TextBrowserInteraction</set>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-      <item>\r
-       <layout class="QHBoxLayout" name="horizontalLayout_4">\r
-        <item>\r
-         <widget class="QLabel" name="label_result_success4">\r
-          <property name="autoFillBackground">\r
-           <bool>false</bool>\r
-          </property>\r
-          <property name="styleSheet">\r
-           <string notr="true">color:rgb(0, 170, 0);\r
-font: 75 18pt &quot;Agra&quot;;</string>\r
-          </property>\r
-          <property name="lineWidth">\r
-           <number>0</number>\r
-          </property>\r
-          <property name="text">\r
-           <string>成功0</string>\r
-          </property>\r
-         </widget>\r
-        </item>\r
-        <item>\r
-         <widget class="QLabel" name="label_result_fail4">\r
-          <property name="autoFillBackground">\r
-           <bool>false</bool>\r
-          </property>\r
-          <property name="styleSheet">\r
-           <string notr="true">color:rgb(170, 0, 0);\r
-font: 75 18pt &quot;Agra&quot;;</string>\r
-          </property>\r
-          <property name="lineWidth">\r
-           <number>0</number>\r
-          </property>\r
-          <property name="text">\r
-           <string>失败0</string>\r
-          </property>\r
-         </widget>\r
-        </item>\r
-       </layout>\r
-      </item>\r
-      <item>\r
-       <widget class="QLabel" name="label_runtime_status4">\r
-        <property name="text">\r
-         <string>已停止测试...</string>\r
-        </property>\r
-       </widget>\r
-      </item>\r
-     </layout>\r
-    </widget>\r
-   </widget>\r
-   <zorder>splitter</zorder>\r
-   <zorder>verticalLayoutWidget_2</zorder>\r
-  </widget>\r
-  <widget class="QStatusBar" name="statusbar">\r
-   <property name="enabled">\r
-    <bool>true</bool>\r
-   </property>\r
-   <property name="sizeGripEnabled">\r
-    <bool>true</bool>\r
-   </property>\r
-  </widget>\r
- </widget>\r
- <customwidgets>\r
-  <customwidget>\r
-   <class>MyComboBox</class>\r
-   <extends>QComboBox</extends>\r
-   <header location="global">custom.h</header>\r
-   <slots>\r
-    <signal>mouse_clicked(bool)</signal>\r
-   </slots>\r
-  </customwidget>\r
- </customwidgets>\r
- <resources/>\r
- <connections>\r
-  <connection>\r
-   <sender>pbtn_spp_reconnect_2</sender>\r
-   <signal>clicked()</signal>\r
-   <receiver>MainWindow</receiver>\r
-   <slot>spp_connect_2()</slot>\r
-   <hints>\r
-    <hint type="sourcelabel">\r
-     <x>386</x>\r
-     <y>126</y>\r
-    </hint>\r
-    <hint type="destinationlabel">\r
-     <x>676</x>\r
-     <y>346</y>\r
-    </hint>\r
-   </hints>\r
-  </connection>\r
-  <connection>\r
-   <sender>pbtn_spp_reconnect_3</sender>\r
-   <signal>clicked()</signal>\r
-   <receiver>MainWindow</receiver>\r
-   <slot>spp_connect_3()</slot>\r
-   <hints>\r
-    <hint type="sourcelabel">\r
-     <x>645</x>\r
-     <y>126</y>\r
-    </hint>\r
-    <hint type="destinationlabel">\r
-     <x>676</x>\r
-     <y>346</y>\r
-    </hint>\r
-   </hints>\r
-  </connection>\r
-  <connection>\r
-   <sender>pbtn_spp_reconnect_4</sender>\r
-   <signal>clicked()</signal>\r
-   <receiver>MainWindow</receiver>\r
-   <slot>spp_connect_4()</slot>\r
-   <hints>\r
-    <hint type="sourcelabel">\r
-     <x>905</x>\r
-     <y>126</y>\r
-    </hint>\r
-    <hint type="destinationlabel">\r
-     <x>676</x>\r
-     <y>346</y>\r
-    </hint>\r
-   </hints>\r
-  </connection>\r
-  <connection>\r
-   <sender>pbtn_spp_connect_all</sender>\r
-   <signal>clicked()</signal>\r
-   <receiver>MainWindow</receiver>\r
-   <slot>spp_connect_all()</slot>\r
-   <hints>\r
-    <hint type="sourcelabel">\r
-     <x>1192</x>\r
-     <y>79</y>\r
-    </hint>\r
-    <hint type="destinationlabel">\r
-     <x>676</x>\r
-     <y>346</y>\r
-    </hint>\r
-   </hints>\r
-  </connection>\r
-  <connection>\r
-   <sender>pushButton_openlogfolder</sender>\r
-   <signal>clicked()</signal>\r
-   <receiver>MainWindow</receiver>\r
-   <slot>openLogfolder()</slot>\r
-   <hints>\r
-    <hint type="sourcelabel">\r
-     <x>1192</x>\r
-     <y>608</y>\r
-    </hint>\r
-    <hint type="destinationlabel">\r
-     <x>676</x>\r
-     <y>346</y>\r
-    </hint>\r
-   </hints>\r
-  </connection>\r
-  <connection>\r
-   <sender>pbtn_spp_reconnect_1</sender>\r
-   <signal>clicked()</signal>\r
-   <receiver>MainWindow</receiver>\r
-   <slot>spp_connect_1()</slot>\r
-   <hints>\r
-    <hint type="sourcelabel">\r
-     <x>126</x>\r
-     <y>126</y>\r
-    </hint>\r
-    <hint type="destinationlabel">\r
-     <x>676</x>\r
-     <y>346</y>\r
-    </hint>\r
-   </hints>\r
-  </connection>\r
- </connections>\r
- <slots>\r
-  <slot>ui_open_mac_config()</slot>\r
-  <slot>uart_process1()</slot>\r
-  <slot>readData1()</slot>\r
-  <slot>readData2()</slot>\r
-  <slot>readData3()</slot>\r
-  <slot>readData4()</slot>\r
-  <slot>uart_rx_dispaly1(int,uint8_t*)</slot>\r
-  <slot>spp_connect_1()</slot>\r
-  <slot>spp_connect_2()</slot>\r
-  <slot>spp_connect_3()</slot>\r
-  <slot>spp_connect_4()</slot>\r
-  <slot>spp_timer_callback1()</slot>\r
-  <slot>spp_connect_all()</slot>\r
-  <slot>uart_process2()</slot>\r
-  <slot>uart_process3()</slot>\r
-  <slot>uart_process4()</slot>\r
-  <slot>openLogfolder()</slot>\r
-  <slot>spp_timer_callback2()</slot>\r
-  <slot>spp_timer_callback3()</slot>\r
-  <slot>spp_timer_callback4()</slot>\r
- </slots>\r
-</ui>\r
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1398</width>
+    <height>758</height>
+   </rect>
+  </property>
+  <property name="font">
+   <font>
+    <family>黑体</family>
+    <weight>50</weight>
+    <bold>false</bold>
+   </font>
+  </property>
+  <property name="windowTitle">
+   <string>BTMacWriteTool V1.3</string>
+  </property>
+  <property name="windowIcon">
+   <iconset>
+    <normaloff>:/icon/windows.ico</normaloff>:/icon/windows.ico</iconset>
+  </property>
+  <property name="windowOpacity">
+   <double>1.000000000000000</double>
+  </property>
+  <property name="layoutDirection">
+   <enum>Qt::LeftToRight</enum>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <layout class="QHBoxLayout" name="horizontalLayout_main">
+    <property name="spacing">
+     <number>6</number>
+    </property>
+    <property name="leftMargin">
+     <number>9</number>
+    </property>
+    <property name="topMargin">
+     <number>9</number>
+    </property>
+    <property name="rightMargin">
+     <number>9</number>
+    </property>
+    <property name="bottomMargin">
+     <number>9</number>
+    </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>
+      <widget class="QWidget" name="verticalLayoutWidget">
+       <property name="font">
+        <font>
+         <family>Arial</family>
+         <pointsize>14</pointsize>
+        </font>
+       </property>
+       <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>
+       <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="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>
+          <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_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>已停止测试...</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">
+        <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="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>
+          <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_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>已停止测试...</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">
+        <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="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>
+          <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_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>已停止测试...</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">
+        <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="QPushButton" name="pbtn_spp_reconnect_4">
+        <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_4">
+        <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_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>
+        </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>
+      </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>
+         </property>
+         <property name="font">
+          <font>
+           <family>Arial</family>
+           <pointsize>14</pointsize>
+           <weight>50</weight>
+           <bold>false</bold>
+          </font>
+         </property>
+         <property name="cursor">
+          <cursorShape>ArrowCursor</cursorShape>
+         </property>
+         <property name="editable">
+          <bool>false</bool>
+         </property>
+         <property name="currentText">
+          <string>500000</string>
+         </property>
+         <property name="currentIndex">
+          <number>11</number>
+         </property>
+         <property name="duplicatesEnabled">
+          <bool>true</bool>
+         </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>
+         </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','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>
+         </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>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QStatusBar" name="statusbar">
+   <property name="enabled">
+    <bool>true</bool>
+   </property>
+   <property name="sizeGripEnabled">
+    <bool>true</bool>
+   </property>
+  </widget>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>MyComboBox</class>
+   <extends>QComboBox</extends>
+   <header location="global">custom.h</header>
+   <slots>
+    <signal>mouse_clicked(bool)</signal>
+   </slots>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>pbtn_spp_reconnect_2</sender>
+   <signal>clicked()</signal>
+   <receiver>MainWindow</receiver>
+   <slot>spp_connect_2()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>386</x>
+     <y>126</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>676</x>
+     <y>346</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>pbtn_spp_reconnect_3</sender>
+   <signal>clicked()</signal>
+   <receiver>MainWindow</receiver>
+   <slot>spp_connect_3()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>645</x>
+     <y>126</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>676</x>
+     <y>346</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>pbtn_spp_reconnect_4</sender>
+   <signal>clicked()</signal>
+   <receiver>MainWindow</receiver>
+   <slot>spp_connect_4()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>905</x>
+     <y>126</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>676</x>
+     <y>346</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>pbtn_spp_connect_all</sender>
+   <signal>clicked()</signal>
+   <receiver>MainWindow</receiver>
+   <slot>spp_connect_all()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>1192</x>
+     <y>79</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>676</x>
+     <y>346</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>pushButton_openlogfolder</sender>
+   <signal>clicked()</signal>
+   <receiver>MainWindow</receiver>
+   <slot>openLogfolder()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>1192</x>
+     <y>608</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>676</x>
+     <y>346</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>pbtn_spp_reconnect_1</sender>
+   <signal>clicked()</signal>
+   <receiver>MainWindow</receiver>
+   <slot>spp_connect_1()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>126</x>
+     <y>126</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>676</x>
+     <y>346</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+ <slots>
+  <slot>ui_open_mac_config()</slot>
+  <slot>uart_process1()</slot>
+  <slot>readData1()</slot>
+  <slot>readData2()</slot>
+  <slot>readData3()</slot>
+  <slot>readData4()</slot>
+  <slot>uart_rx_dispaly1(int,uint8_t*)</slot>
+  <slot>spp_connect_1()</slot>
+  <slot>spp_connect_2()</slot>
+  <slot>spp_connect_3()</slot>
+  <slot>spp_connect_4()</slot>
+  <slot>spp_timer_callback1()</slot>
+  <slot>spp_connect_all()</slot>
+  <slot>uart_process2()</slot>
+  <slot>uart_process3()</slot>
+  <slot>uart_process4()</slot>
+  <slot>openLogfolder()</slot>
+  <slot>spp_timer_callback2()</slot>
+  <slot>spp_timer_callback3()</slot>
+  <slot>spp_timer_callback4()</slot>
+ </slots>
+</ui>
diff --git a/test_port_controller.cpp b/test_port_controller.cpp
new file mode 100644 (file)
index 0000000..b792cc5
--- /dev/null
@@ -0,0 +1,540 @@
+#include "test_port_controller.h"
+#include "settings.h"
+#include <QRegExp>
+#include <QDebug>
+#include <QMessageBox>
+
+TestPortController::TestPortController(int port_index, QObject *parent)
+    : QObject(parent)
+    , m_port_index(port_index)
+    , m_dut_serial(new QSerialPort(this))
+    , m_rgb_serial(new QSerialPort(this))
+    , m_spp_timer_handle(new QTimer(this))
+    , m_result_thread(new Result_Thread(nullptr, port_index + 1))
+    , m_bytesToWrite(0)
+    , m_cmd_index(0)
+    , m_working_state(false)
+    , m_waiting_cmd(false)
+    , m_startup_complete_detected(false)
+    , m_uart_rx_flag(false)
+    , m_uart_rx_Ignoring_display(false)
+    , m_write_success_count(0)
+    , m_write_fail_count(0)
+{
+    // 连接定时器信号
+    connect(m_spp_timer_handle, &QTimer::timeout, this, &TestPortController::onTimerTimeout);
+    
+    // 连接串口信号
+    connect(m_dut_serial, &QSerialPort::readyRead, this, &TestPortController::onReadyRead);
+    connect(m_dut_serial, &QSerialPort::bytesWritten, this, &TestPortController::onBytesWritten);
+    
+    // 启动结果线程
+    m_result_thread->start();
+    m_result_thread->pause();
+}
+
+TestPortController::~TestPortController()
+{
+    disconnectPort();
+    if (m_result_thread) {
+        m_result_thread->stop();
+        m_result_thread->wait();
+        delete m_result_thread;
+    }
+}
+
+void TestPortController::connectPort(const QString& com_name, int baud_rate)
+{
+    if (m_working_state) {
+        // 停止工作
+        disconnectPort();
+        return;
+    }
+    
+    // 检查是否选择了 "None"
+    if (com_name.isEmpty() || com_name == tr("None") || com_name == "None") {
+        qDebug() << tr("端口%1未选择串口(选择了None),跳过打开串口操作").arg(m_port_index + 1);
+        emit displayMessage(tr("未选择串口,请先选择串口\r\n"), false);
+        return;
+    }
+    
+    qDebug() << tr("=== 开始连接串口%1 ===").arg(m_port_index + 1);
+    qDebug() << tr("串口名称:") << com_name;
+    qDebug() << tr("波特率:") << baud_rate;
+    
+    m_dut_serial->setPortName(com_name);
+    m_dut_serial->setBaudRate(baud_rate);
+    m_dut_serial->setDataBits(QSerialPort::Data8);
+    m_dut_serial->setParity(QSerialPort::NoParity);
+    m_dut_serial->setStopBits(QSerialPort::OneStop);
+    m_dut_serial->setFlowControl(QSerialPort::NoFlowControl);
+    m_dut_serial->setReadBufferSize(32768); // 32KB缓冲区
+    
+    emit clearDisplay();
+    
+    if (m_dut_serial->isOpen()) {
+        qDebug() << tr("端口%1串口已经打开,重置命令索引").arg(m_port_index);
+        m_cmd_index = 0;
+    } else {
+        if (m_dut_serial->open(QIODevice::ReadWrite)) {
+            qDebug() << tr("端口%1串口打开成功").arg(m_port_index);
+            m_cmd_index = 0;
+        } else {
+            qDebug() << tr("端口%1串口打开失败:").arg(m_port_index) << m_dut_serial->errorString();
+            emit displayMessage(tr("Open error\r\n"), false);
+            return;
+        }
+    }
+    
+    // 开始工作
+    qDebug() << tr("端口%1开始写地址工作模式").arg(m_port_index);
+    m_working_state = true;
+    m_write_fail_count = 0;
+    m_write_success_count = 0;
+    
+    // 初始化开机检测缓存
+    m_boot_detect_buffer.clear();
+    m_waiting_cmd = false;
+    m_startup_complete_detected = false;
+    
+    emit successCountChanged(m_write_success_count);
+    emit failCountChanged(m_write_fail_count);
+    emit buttonTextChanged(tr("停止写地址"));
+    emit statusChanged(tr("等待手表开机"));
+}
+
+void TestPortController::disconnectPort()
+{
+    qDebug() << tr("端口%1停止写地址工作模式").arg(m_port_index);
+    emit buttonTextChanged(tr("开始写地址"));
+    emit statusChanged(tr("已停止写地址..."));
+    m_working_state = false;
+    
+    // 清空开机检测缓存
+    m_boot_detect_buffer.clear();
+    
+    emit clearDisplay();
+    
+    if (m_dut_serial->isOpen()) {
+        m_dut_serial->close();
+    }
+}
+
+void TestPortController::poweroffWatch()
+{
+    uart_send_data(ATCMD_POWEROFF);
+}
+
+void TestPortController::setMacAddress(const QString& mac)
+{
+    m_mac_address = mac;
+    emit macAddressChanged(mac);
+}
+
+void TestPortController::triggerDisplayMessage(QString str, bool inOrOut)
+{
+    emit displayMessage(str, inOrOut);
+}
+
+void TestPortController::triggerShowResult(QString msg, bool success)
+{
+    emit showResult(msg, success);
+}
+
+void TestPortController::onReadyRead()
+{
+    readData();
+}
+
+void TestPortController::onBytesWritten(qint64 bytes)
+{
+    handleBytesWritten(bytes);
+}
+
+void TestPortController::onTimerTimeout()
+{
+    spp_timer_callback();
+}
+
+void TestPortController::readData()
+{
+    const QByteArray data = m_dut_serial->readAll();
+    
+    if (m_uart_rx_flag) {
+        qDebug() << tr("端口%1接收数据:").arg(m_port_index) << data;
+    }
+    
+    if (!m_working_state) {
+        qDebug() << tr("端口%1写号结束,跳过读取串口").arg(m_port_index);
+        return;
+    }
+    
+    // 将新数据添加到开机检测缓存中
+    m_boot_detect_buffer.append(data);
+    
+    // 保持缓存大小合理
+    if (m_boot_detect_buffer.length() > 8192) {
+        m_boot_detect_buffer = m_boot_detect_buffer.right(8192);
+        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);
+            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);
+    }
+    
+    // 检测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();
+            
+            bool mac_used = settings::getInstance().getMacUsed(macWithoutColon);
+            
+            if (mac_used) {
+                emit displayMessage(tr("手表地址") + macWithoutColon + tr("已占用\r\n"), false);
+                emit showResult(tr("Mac地址已占用"), false);
+            } else {
+                emit displayMessage(tr("手表当前地址") + macWithoutColon + tr(" 可用!\r\n"), true);
+            }
+        }
+    }
+    
+    // 检测命令时机信号
+    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);
+            }
+        }
+    }
+    
+    if (m_uart_rx_flag) {
+        m_uart_rx_buff_array.append(data);
+        
+        // 检查结束标志
+        bool hasOK = m_uart_rx_buff_array.indexOf("OK~") >= 0;
+        bool hasPowerOff = m_uart_rx_buff_array.indexOf("power off device!") >= 0;
+        bool hasDSPPowerDown = m_uart_rx_buff_array.indexOf("DSP0 power down") >= 0;
+        
+        bool isGetMacComplete = false;
+        if (m_G_cmd.contains("GETBTMAC")) {
+            bool hasLocalAddr = m_uart_rx_buff_array.indexOf("get nv local_addr") >= 0;
+            bool hasBTMAC = m_uart_rx_buff_array.indexOf("BTMAC=") >= 0;
+            bool hasCyweeChipInfo = m_uart_rx_buff_array.indexOf("CyweeChipInfo=") >= 0;
+            
+            if (hasLocalAddr && hasBTMAC && hasCyweeChipInfo) {
+                QRegExp completeMacRegex("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})");
+                if (completeMacRegex.indexIn(m_uart_rx_buff_array) >= 0) {
+                    isGetMacComplete = true;
+                }
+            }
+        }
+        
+        if (hasOK || hasPowerOff || hasDSPPowerDown || isGetMacComplete) {
+            if (m_spp_timer_handle && m_spp_timer_handle->isActive()) {
+                m_spp_timer_handle->stop();
+            }
+            
+            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();
+                }
+                
+                if (m_uart_rx_buff_array.indexOf("power off device") >= 0) {
+                    emit displayMessage(tr("关机成功\r\n"), true);
+                }
+                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 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;
+            }
+        }
+    }
+}
+
+void TestPortController::uart_process()
+{
+    qDebug() << tr("端口%1 uart_process").arg(m_port_index) << m_cmd_index;
+    
+    switch(m_cmd_index) {
+    case 0:
+        emit displayMessage(tr("阻止休眠\r\n"), true);
+        break;
+    case 1:
+    {
+        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 ret = macRegex.indexIn(m_uart_rx_buff_array);
+        
+        if (ret >= 0) {
+            QString mac_with_colon = macRegex.cap(1);
+            QString unit = mac_with_colon.replace(":", "").toUpper();
+            
+            bool mac_used = settings::getInstance().getMacUsed(unit.toUpper());
+            
+            if (mac_used) {
+                emit displayMessage(tr("手表地址") + unit + tr("已占用\r\n"), false);
+                m_write_fail_count++;
+                emit failCountChanged(m_write_fail_count);
+                emit showResult(tr("Mac地址已占用"), false);
+                m_cmd_index = -1;
+            } else {
+                emit displayMessage(tr("手表当前地址") + unit + tr(" 可用!\r\n"), true);
+            }
+        } else {
+            emit displayMessage(tr("查询手表Mac失败!\r\n"), false);
+            m_cmd_index = -1;
+            m_write_fail_count++;
+            emit failCountChanged(m_write_fail_count);
+            emit showResult(tr("查询手表Mac失败"), false);
+        }
+    }
+        break;
+    case 2:
+        emit displayMessage(tr("执行设置地址\r\n"), false);
+        emit displayMessage(tr("MAC地址设置完成,等待设备处理...\r\n"), true);
+        break;
+    case 3:
+    {
+        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 ret = macRegex.indexIn(m_uart_rx_buff_array);
+        if (ret >= 0) {
+            QString mac_with_colon = macRegex.cap(1);
+            QString unit_watch = mac_with_colon.replace(":", "").toUpper();
+            
+            if (unit_watch.toUpper() == m_mac_address.toUpper()) {
+                emit displayMessage(tr("设置Mac") + unit_watch + tr("成功\r\n"), true);
+            } else {
+                emit displayMessage(tr("设置Mac") + unit_watch + tr("失败\r\n"), false);
+                m_cmd_index = -2;
+                m_write_fail_count++;
+                emit failCountChanged(m_write_fail_count);
+                emit showResult(tr("Mac地址设置失败"), false);
+            }
+        } else {
+            emit displayMessage(tr("设置Mac") + m_mac_address + tr("失败\r\n"), false);
+            m_cmd_index = -3;
+            m_write_fail_count++;
+            emit failCountChanged(m_write_fail_count);
+            emit showResult(tr("查询手表Mac失败"), false);
+        }
+    }
+        break;
+    case 4:
+    {
+        int ret = m_uart_rx_buff_array.indexOf("[soc id:]");
+        if (ret >= 0) {
+            QString soc_section = m_uart_rx_buff_array.mid(ret);
+            bool hasCompleteData = soc_section.contains("OK~") || soc_section.contains("\r\n\r\n");
+            
+            QRegExp hexRegex("0x[0-9A-Fa-f]{4}");
+            QStringList hexValues;
+            int pos = 0;
+            
+            while ((pos = hexRegex.indexIn(soc_section, pos)) != -1) {
+                hexValues << hexRegex.cap(0);
+                pos += hexRegex.matchedLength();
+            }
+            
+            if (hexValues.size() >= 10 && hasCompleteData) {
+                QString cpu_id = "";
+                for (const QString &hex : hexValues) {
+                    cpu_id += hex.mid(2);
+                }
+                
+                emit displayMessage("cpuid: " + cpu_id + "\r\n", true);
+                
+                int db_ret = settings::getInstance().set_mac_used(m_mac_address, cpu_id, true);
+                
+                if (db_ret == 1) {
+                    emit displayMessage(tr("设置mac成功\r\n"), true);
+                    // 更新MAC状态显示
+                    emit updateMacStatus(settings::getInstance().getmacStatusFull());
+                } else {
+                    m_write_fail_count++;
+                    emit failCountChanged(m_write_fail_count);
+                    emit showResult(tr("获取cpuid失败\r\n"), false);
+                }
+            } else {
+                if (!hasCompleteData) {
+                    emit displayMessage(tr("等待CPU ID完整数据...\r\n"), false);
+                    return;
+                } else if (hexValues.size() < 10) {
+                    emit displayMessage(tr("CPU ID格式不正确\r\n"), false);
+                    m_cmd_index = -4;
+                    m_write_fail_count++;
+                    emit failCountChanged(m_write_fail_count);
+                    emit showResult(tr("获取CPU ID失败"), false);
+                }
+            }
+        } else {
+            emit displayMessage(tr("等待CPU ID数据...\r\n"), false);
+            m_cmd_index = -4;
+            m_write_fail_count++;
+            emit failCountChanged(m_write_fail_count);
+            emit showResult(tr("获取CPU ID失败"), false);
+        }
+    }
+        break;
+    case 5:
+    {
+        int ret = m_uart_rx_buff_array.indexOf("power off device");
+        if (ret >= 0) {
+            emit displayMessage(tr("关机成功\r\n"), true);
+        } else {
+            emit displayMessage(tr("关机失败\r\n"), false);
+        }
+        m_write_success_count++;
+        emit successCountChanged(m_write_success_count);
+        emit showResult(tr("设置mac成功\r\n"), true);
+    }
+        break;
+    default:
+        m_cmd_index = -1;
+        break;
+    }
+}
+
+void TestPortController::uart_send_data(const QString& cmd)
+{
+    m_uart_rx_buff_array.clear();
+    qDebug() << tr("端口%1 uart_send_data").arg(m_port_index) << cmd;
+    
+    qint64 ret = m_dut_serial->write(cmd.toUtf8());
+    m_bytesToWrite = ret;
+    
+    m_G_cmd = cmd;
+    if (m_spp_timer_handle && m_spp_timer_handle->isActive()) {
+        m_spp_timer_handle->stop();
+    }
+    
+    if (cmd.contains("GETIDS")) {
+        m_spp_timer_handle->start(5000);
+    } else if (cmd.contains("GETBTMAC")) {
+        m_spp_timer_handle->start(3000);
+    } else {
+        m_spp_timer_handle->start(1500);
+    }
+}
+
+void TestPortController::handleBytesWritten(qint64 bytes)
+{
+    m_bytesToWrite -= bytes;
+    if (m_bytesToWrite == 0) {
+        m_uart_rx_flag = true;
+        m_uart_rx_buff_array.clear();
+    }
+}
+
+void TestPortController::spp_timer_callback()
+{
+    m_uart_rx_flag = false;
+    qDebug() << tr("端口%1 AT命令超时:").arg(m_port_index) << m_G_cmd;
+    
+    if (m_G_cmd == ATCMD_ADD_VOTE) {
+        uart_send_data(ATCMD_ADD_VOTE);
+    } else if (m_G_cmd.contains("GETIDS")) {
+        emit displayMessage(tr("获取CPU ID超时,跳过此步骤\r\n"), false);
+        m_cmd_index = 4;
+        m_uart_rx_flag = false;
+        uart_process();
+    } else {
+        emit displayMessage(tr("AT命令超时: %1\r\n").arg(m_G_cmd), false);
+        if (m_spp_timer_handle && m_spp_timer_handle->isActive()) {
+            m_spp_timer_handle->stop();
+        }
+    }
+}
+
+void TestPortController::resetState()
+{
+    m_bytesToWrite = 0;
+    m_cmd_index = 0;
+    m_G_cmd.clear();
+    m_working_state = false;
+    m_waiting_cmd = false;
+    m_startup_complete_detected = false;
+    m_uart_rx_flag = false;
+    m_uart_rx_Ignoring_display = false;
+    m_uart_rx_buff_array.clear();
+    m_boot_detect_buffer.clear();
+    m_write_success_count = 0;
+    m_write_fail_count = 0;
+}
+
+void TestPortController::clearBuffers()
+{
+    m_uart_rx_buff_array.clear();
+    m_boot_detect_buffer.clear();
+}
+
diff --git a/test_port_controller.h b/test_port_controller.h
new file mode 100644 (file)
index 0000000..b25c36b
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef TEST_PORT_CONTROLLER_H
+#define TEST_PORT_CONTROLLER_H
+
+#include <QObject>
+#include <QSerialPort>
+#include <QTimer>
+#include <QByteArray>
+#include <QString>
+#include "result_thread.h"
+#include "settings.h"
+
+// 前向声明
+class QSerialPort;
+class QTimer;
+class Result_Thread;
+
+// 测试端口控制器类 - 封装每个测试端口的所有变量和函数
+class TestPortController : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit TestPortController(int port_index, QObject *parent = nullptr);
+    ~TestPortController();
+
+    // 端口索引 (0-3)
+    int portIndex() const { return m_port_index; }
+
+    // 串口对象访问
+    QSerialPort* dutSerial() const { return m_dut_serial; }
+    QSerialPort* rgbSerial() const { return m_rgb_serial; }
+
+    // 状态访问
+    bool isWorking() const { return m_working_state; }
+    int successCount() const { return m_write_success_count; }
+    int failCount() const { return m_write_fail_count; }
+
+    // 公共接口函数
+    void connectPort(const QString& com_name, int baud_rate);
+    void disconnectPort();
+    void poweroffWatch();
+    void setMacAddress(const QString& mac);
+    
+    // 用于向后兼容的公共方法(触发信号)
+    void triggerDisplayMessage(QString str, bool inOrOut);
+    void triggerShowResult(QString msg, bool success);
+
+signals:
+    // UI更新信号
+    void displayMessage(QString str, bool inOrOut);  // 显示消息 (inOrOut: true=输入/绿色, false=输出/红色)
+    void showResult(QString msg, bool success);      // 显示结果
+    void statusChanged(QString status);              // 状态文本变化
+    void successCountChanged(int count);             // 成功计数变化
+    void failCountChanged(int count);                // 失败计数变化
+    void macAddressChanged(QString mac);             // MAC地址变化
+    void buttonTextChanged(QString text);            // 按钮文本变化
+    void clearDisplay();                              // 清空显示
+    void updateMacStatus(QString status);            // 更新MAC状态显示(用于textBrowser_result)
+
+private slots:
+    void onReadyRead();
+    void onBytesWritten(qint64 bytes);
+    void onTimerTimeout();
+
+private:
+    // 端口索引 (0-3)
+    int m_port_index;
+
+    // 串口对象
+    QSerialPort *m_dut_serial;
+    QSerialPort *m_rgb_serial;
+
+    // 定时器
+    QTimer *m_spp_timer_handle;
+
+    // 结果线程
+    Result_Thread *m_result_thread;
+
+    // 指令相关
+    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命令
+
+    // 状态标志
+    bool m_working_state;             // true=写号执行中, false=写号结束
+    bool m_waiting_cmd;                // 等待命令时机
+    bool m_startup_complete_detected;  // 启动完成信号已检测标志
+    bool m_uart_rx_flag;               // 是否有uart通路数据上报
+    bool m_uart_rx_Ignoring_display;  // 是否忽略uart数据,不回显
+
+    // 数据缓冲区
+    QByteArray m_uart_rx_buff_array;  // AT命令响应缓冲区
+    QByteArray m_boot_detect_buffer;   // 开机检测数据缓存,处理分包情况
+
+    // 统计
+    int m_write_success_count;        // 成功计数
+    int m_write_fail_count;           // 失败计数
+
+    // MAC地址
+    QString m_mac_address;            // 当前MAC地址
+
+    // 内部处理函数
+    void readData();
+    void uart_process();
+    void uart_send_data(const QString& cmd);
+    void handleBytesWritten(qint64 bytes);
+    void spp_timer_callback();
+    void resetState();
+    void clearBuffers();
+};
+
+#endif // TEST_PORT_CONTROLLER_H
+