├── .gitignore ├── .gitmodules ├── .vscode ├── c_cpp_properties.json ├── extensions.json └── settings.json ├── CMakeLists.txt ├── LICENSE ├── README.md ├── assets ├── chevron_right_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.png ├── gitea_favicon.png ├── gitee_favicon.ico ├── github_favicon.png └── keyboard_arrow_down_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.png ├── comp_testing.md ├── doc └── assets │ ├── enum_device_list.png │ ├── main_window.png │ └── menu_target_chip.png ├── main.qrc ├── resources └── io.github.ma6254.qdap.desktop ├── src ├── DAP │ └── debug_cm.h ├── FlashOS.h ├── config │ ├── chips_config.cpp │ ├── chips_config.h │ ├── config.cpp │ └── config.h ├── devices │ ├── cmsis-dap │ │ ├── dap.cpp │ │ ├── dap.h │ │ ├── dap_usb_bulk.cpp │ │ ├── dap_usb_bulk.h │ │ ├── dap_usb_hid.cpp │ │ └── dap_usb_hid.h │ ├── device_list.cpp │ ├── device_list.h │ ├── devices.cpp │ └── devices.h ├── flash_algo.cpp ├── flash_algo.h ├── glibc_elf.h ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── program_worker.cpp ├── program_worker.h ├── ui_components │ ├── chip_selecter.cpp │ ├── chip_selecter.h │ ├── chip_selecter.ui │ ├── hex_viewer.cpp │ ├── hex_viewer.h │ └── hex_viewer.ui ├── utils.cpp ├── utils.h ├── views │ ├── chips_config_dialog │ │ ├── chips_config_dialog.cpp │ │ ├── chips_config_dialog.h │ │ └── chips_config_dialog.ui │ ├── device_selector │ │ ├── cmsis-dap │ │ │ ├── enum_dap.cpp │ │ │ ├── enum_dap.h │ │ │ └── enum_dap.ui │ │ ├── enum_writer_list.cpp │ │ ├── enum_writer_list.h │ │ └── enum_writer_list.ui │ └── input_box_dialog │ │ ├── input_box_dialog.cpp │ │ ├── input_box_dialog.h │ │ └── input_box_dialog.ui └── win_hotplug_notify │ ├── win_hotplug_notify.cpp │ └── win_hotplug_notify.h └── vendor.py /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | .directory 25 | *.debug 26 | Makefile* 27 | *.prl 28 | *.app 29 | moc_*.cpp 30 | ui_*.h 31 | qrc_*.cpp 32 | Thumbs.db 33 | *.res 34 | *.rc 35 | /.qmake.cache 36 | /.qmake.stash 37 | 38 | # qtcreator generated files 39 | *.pro.user* 40 | CMakeLists.txt.user 41 | CMakeLists.txt.user.* 42 | /build 43 | QDAP_*.ts 44 | 45 | # xemacs temporary files 46 | *.flc 47 | 48 | # Vim temporary files 49 | .*.swp 50 | 51 | # Visual Studio generated files 52 | *.ib_pdb_index 53 | *.idb 54 | *.ilk 55 | *.pdb 56 | *.sln 57 | *.suo 58 | *.vcproj 59 | *vcproj.*.*.user 60 | *.ncb 61 | *.sdf 62 | *.opensdf 63 | *.vcxproj 64 | *vcxproj.* 65 | 66 | # MinGW generated files 67 | *.Debug 68 | *.Release 69 | 70 | # Python byte code 71 | *.pyc 72 | 73 | # Binaries 74 | # -------- 75 | # *.dll 76 | # *.exe 77 | /release 78 | 79 | # libusb 80 | # /libusb_hid_api/x86 81 | # /libusb_hid_api/x64 82 | /vendor/libusb/ 83 | /vendor/libusb_hid_api/ 84 | /vendor/openssl/ 85 | 86 | # WCH ch341 ch347 87 | /ch341_ch347_lib 88 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/yaml-cpp"] 2 | path = vendor/yaml-cpp 3 | url = https://github.com/jbeder/yaml-cpp.git 4 | branch = yaml-cpp-0.7.0 5 | [submodule "vendor/QHexView"] 6 | path = vendor/QHexView 7 | url = https://github.com/Dax89/QHexView.git 8 | branch = 5.0 9 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "QT", 5 | "includePath": [ 6 | "C:\\Qt\\Qt5.14.2\\5.14.2\\mingw73_64\\include", 7 | "C:\\Qt\\Qt5.14.2\\5.14.2\\mingw73_64\\include\\*\\**", 8 | "D:\\qt_online\\5.15.2\\mingw81_64\\include", 9 | "D:\\qt_online\\5.15.2\\mingw81_64\\include\\*\\**", 10 | "${workspaceFolder}/src", 11 | "${workspaceFolder}/vendor/libusb_hid_api/include", 12 | "${workspaceFolder}/vendor/libusb/include", 13 | "${workspaceFolder}/vendor/yaml-cpp/include", 14 | "${workspaceFolder}/vendor/QHexView/include", 15 | "${workspaceFolder}/src/DAP", 16 | "${workspaceFolder}/src/config", 17 | "${workspaceFolder}/src/ui_components", 18 | "${workspaceFolder}/src/devices/cmsis-dap", 19 | "${workspaceFolder}/src/devices/", 20 | "${workspaceFolder}/src/views/device_selector/cmsis-dap", 21 | "${workspaceFolder}/src/views/device_selector", 22 | "${workspaceFolder}/src/views/input_box_dialog", 23 | "${workspaceFolder}/src/views/chips_config_dialog", 24 | "${workspaceFolder}/src/win_hotplug_notify", 25 | "${workspaceFolder}/build/Desktop_Qt_5_15_2_MinGW_64_bit-Debug/QDAP_autogen/include" 26 | // "${workspaceFolder}/../build-QDAP-(2)-Desktop_Qt_5_14_2_MinGW_64_bit-Debug/QDAP_autogen/include" 27 | ], 28 | "defines": [ 29 | "_DEBUG", 30 | "UNICODE", 31 | "_UNICODE", 32 | "__STATIC_INLINE" 33 | ] 34 | } 35 | ], 36 | "version": 4 37 | } -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "MS-CEINTL.vscode-language-pack-zh-hans", 6 | "ms-vscode.cpptools", 7 | "wayou.vscode-todo-highlight" 8 | ], 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.encoding": "utf8", 3 | "editor.rulers": [ 4 | 80, 5 | 120, 6 | ], 7 | "files.autoGuessEncoding": true, 8 | "files.exclude": { 9 | "build": true, 10 | }, 11 | "files.associations": { 12 | "*.H": "c", 13 | "Caddyfile": "caddyfile", 14 | "*.j2": "jinja", 15 | "*.ts": "xml", 16 | "*.h": "cpp", 17 | "hidapi.h": "c", 18 | "hidapi_winapi.h": "c", 19 | "dap_hid.h": "cpp", 20 | "enum_writer_list.h": "cpp", 21 | "atomic": "cpp", 22 | "ios": "cpp", 23 | "list": "cpp", 24 | "system_error": "cpp", 25 | "vector": "cpp", 26 | "xhash": "cpp", 27 | "xiosbase": "cpp", 28 | "xstring": "cpp", 29 | "xtree": "cpp", 30 | "xutility": "cpp", 31 | "chrono": "cpp", 32 | "qfiledialog": "cpp", 33 | "initializer_list": "cpp", 34 | "type_traits": "cpp", 35 | "xlocale": "cpp", 36 | "qtimer": "cpp", 37 | "chip_selecter.h": "cpp", 38 | "ui_chip_selecter.h": "cpp", 39 | "resumable": "cpp", 40 | "xmemory": "cpp", 41 | "utils.h": "cpp", 42 | "array": "cpp", 43 | "deque": "cpp", 44 | "queue": "cpp", 45 | "stack": "cpp", 46 | "valarray": "cpp", 47 | "elf.h": "cpp", 48 | "qdialog": "cpp", 49 | "qstring": "c", 50 | "flash_algo.h": "cpp", 51 | "glibc_elf.h": "cpp", 52 | "flashos.h": "cpp", 53 | "xlocmon": "cpp", 54 | "future": "cpp", 55 | "hex_viewer.h": "cpp", 56 | "qbytearray": "cpp", 57 | "qbytearray.h": "cpp", 58 | "memory": "cpp", 59 | "ui_hex_viewer.h": "cpp", 60 | "qgridlayout": "cpp", 61 | "sstream": "cpp", 62 | "forward_list": "cpp", 63 | "qthread": "cpp", 64 | "qdebug": "cpp", 65 | "qapplication": "cpp", 66 | "ostream": "cpp", 67 | "fstream": "cpp", 68 | "algorithm": "cpp", 69 | "any": "cpp", 70 | "cctype": "cpp", 71 | "cmath": "cpp", 72 | "concepts": "cpp", 73 | "condition_variable": "cpp", 74 | "cstddef": "cpp", 75 | "cstdint": "cpp", 76 | "cstdio": "cpp", 77 | "cstdlib": "cpp", 78 | "cstring": "cpp", 79 | "ctime": "cpp", 80 | "cwchar": "cpp", 81 | "exception": "cpp", 82 | "functional": "cpp", 83 | "iomanip": "cpp", 84 | "iosfwd": "cpp", 85 | "iostream": "cpp", 86 | "istream": "cpp", 87 | "iterator": "cpp", 88 | "limits": "cpp", 89 | "locale": "cpp", 90 | "map": "cpp", 91 | "mutex": "cpp", 92 | "new": "cpp", 93 | "numeric": "cpp", 94 | "optional": "cpp", 95 | "ratio": "cpp", 96 | "set": "cpp", 97 | "stdexcept": "cpp", 98 | "streambuf": "cpp", 99 | "string": "cpp", 100 | "thread": "cpp", 101 | "tuple": "cpp", 102 | "typeinfo": "cpp", 103 | "unordered_map": "cpp", 104 | "unordered_set": "cpp", 105 | "utility": "cpp", 106 | "variant": "cpp", 107 | "xfacet": "cpp", 108 | "xlocbuf": "cpp", 109 | "xlocinfo": "cpp", 110 | "xlocmes": "cpp", 111 | "xlocnum": "cpp", 112 | "xloctime": "cpp", 113 | "xstddef": "cpp", 114 | "xtr1common": "cpp", 115 | "qmessagebox": "cpp", 116 | "qmainwindow": "cpp", 117 | "qscrollbar": "cpp", 118 | "qdir": "cpp", 119 | "bit": "cpp", 120 | "*.tcc": "cpp", 121 | "charconv": "cpp", 122 | "clocale": "cpp", 123 | "compare": "cpp", 124 | "cstdarg": "cpp", 125 | "cwctype": "cpp", 126 | "memory_resource": "cpp", 127 | "random": "cpp", 128 | "string_view": "cpp", 129 | "format": "cpp", 130 | "numbers": "cpp", 131 | "semaphore": "cpp", 132 | "span": "cpp", 133 | "stop_token": "cpp", 134 | "cinttypes": "cpp", 135 | "qelapsedtimer": "cpp", 136 | "qvboxlayout": "cpp", 137 | "qcombobox": "cpp", 138 | "qgroupbox": "cpp", 139 | "qcoreapplication": "cpp", 140 | "qobject": "cpp", 141 | "qfile": "cpp", 142 | "qlabel": "c", 143 | "qhboxlayout": "c", 144 | "qsharedpointer": "c", 145 | "qlist": "c" 146 | }, 147 | "git.ignoreLimitWarning": true 148 | } 149 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(QDAP LANGUAGES CXX) 4 | 5 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 6 | set(CMAKE_AUTOUIC ON) 7 | set(CMAKE_AUTOMOC ON) 8 | set(CMAKE_AUTORCC ON) 9 | 10 | set(CMAKE_CXX_STANDARD 11) 11 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 12 | 13 | # QtCreator supports the following variables for Android, which are identical to 14 | # qmake Android variables. Check http://doc.qt.io/qt-5/deployment-android.html 15 | # for more information. They need to be set before the find_package(Qt5 ...) 16 | # call. 17 | 18 | # if(ANDROID) set(ANDROID_PACKAGE_SOURCE_DIR 19 | # "${CMAKE_CURRENT_SOURCE_DIR}/android") if (ANDROID_ABI STREQUAL "armeabi-v7a") 20 | # set(ANDROID_EXTRA_LIBS ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so 21 | # ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so) endif() endif() 22 | find_package( 23 | Qt5 24 | COMPONENTS 25 | Gui 26 | Widgets 27 | Network 28 | LinguistTools 29 | REQUIRED) 30 | 31 | include_directories(${QT_INCLUDE_DIRS}) 32 | 33 | set(TS_FILES ${CMAKE_SOURCE_DIR} QDAP_zh_CN.ts) 34 | 35 | qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES}) 36 | 37 | set(QM_FILES main.qrc) 38 | 39 | find_program(GIT_EXECUTABLE git DOC "Git executable path") 40 | 41 | if(GIT_EXECUTABLE) 42 | message(STATUS "Found Git executable at: ${GIT_EXECUTABLE}") 43 | else() 44 | message( 45 | WARNING "Git executable not found. Submodule operations will be skipped.") 46 | endif() 47 | 48 | if(WIN32 AND GIT_EXECUTABLE) 49 | message(STATUS "Initializing and updating submodules on Windows...") 50 | 51 | execute_process( 52 | COMMAND "${GIT_EXECUTABLE}" submodule update --init --recursive 53 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 54 | RESULT_VARIABLE GIT_SUBMODULE_RESULT) 55 | 56 | if(NOT GIT_SUBMODULE_RESULT EQUAL 0) 57 | message(FATAL_ERROR "Failed to initialize and update submodules.") 58 | endif() 59 | 60 | # add_custom_target(update_submodules) add_custom_command( TARGET 61 | # update_submodules POSTBUILD COMMAND "${GIT_EXECUTABLE}" submodule update 62 | # --recursive WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) 63 | else() 64 | message(STATUS "Skipping submodule initialization and update.") 65 | endif() 66 | 67 | include_directories( 68 | src 69 | src/DAP 70 | src/config 71 | src/devices 72 | src/devices/cmsis-dap 73 | src/ui_components 74 | src/views/device_selector/cmsis-dap 75 | src/views/device_selector 76 | src/views/input_box_dialog 77 | src/views/chips_config_dialog 78 | ) 79 | 80 | file( 81 | GLOB 82 | SRC_FILES 83 | src/*.cpp 84 | src/DAP/*.cpp 85 | src/config/*.cpp 86 | src/devices/*.cpp 87 | src/devices/cmsis-dap/*.cpp 88 | src/ui_components/*.cpp 89 | src/views/device_selector/*.cpp 90 | src/views/device_selector/cmsis-dap/*.cpp 91 | src/views/input_box_dialog/*.cpp 92 | src/views/chips_config_dialog/*.cpp 93 | ) 94 | 95 | file( 96 | GLOB 97 | UI_FILES 98 | src/*.ui 99 | src/ui_components/*.ui 100 | src/views/device_selector/*.ui 101 | src/views/device_selector/cmsis-dap/*.ui 102 | src/views/input_box_dialog/*.ui 103 | src/views/chips_config_dialog/*.ui 104 | ) 105 | 106 | if(ANDROID) 107 | # ############################################################################ 108 | # ANDROID 109 | # ############################################################################ 110 | message(STATUS "Building for Android") 111 | add_library(QDAP SHARED ${SRC_FILES} ${UI_FILES} ${QM_FILES}) 112 | elseif(WIN32) 113 | # ############################################################################ 114 | # Windows 115 | # ############################################################################ 116 | message(STATUS "Building for Windows") 117 | 118 | include_directories( 119 | src/win_hotplug_notify 120 | ) 121 | 122 | file( 123 | GLOB 124 | WIN_SRC_FILES 125 | src/win_hotplug_notify/*.cpp 126 | ) 127 | 128 | # yaml-cpp 129 | add_subdirectory("vendor/yaml-cpp") 130 | set(yaml-cpp_LIBRARIES yaml-cpp) 131 | 132 | # QHexView 133 | add_subdirectory("vendor/QHexView") 134 | set(QHexView_LIBRARIES QHexView) 135 | 136 | include_directories( 137 | ${Qt5Core_INCLUDE_DIRS} 138 | ${Qt5Widgets_INCLUDE_DIRS} 139 | ${Qt5Gui_PRIVATE_INCLUDE_DIRS} 140 | vendor/libusb_hid_api/include 141 | vendor/libusb/include 142 | vendor/yaml-cpp/include 143 | vendor/QHexView/include 144 | ) 145 | 146 | include_directories(ch341_ch347_lib/CH341PAR/LIB/CH347) 147 | 148 | add_executable(QDAP ${SRC_FILES} ${WIN_SRC_FILES} ${UI_FILES} ${QM_FILES}) 149 | target_link_libraries( 150 | QDAP 151 | PRIVATE 152 | Qt5::Core 153 | Qt5::Gui 154 | Qt5::Widgets 155 | Qt5::Network 156 | # OpenSSL::SSL OpenSSL::Crypto 157 | ${CMAKE_SOURCE_DIR}/vendor/libusb_hid_api/x64/hidapi.lib 158 | ${CMAKE_SOURCE_DIR}/vendor/libusb/MinGW64/static/libusb-1.0.a 159 | yaml-cpp 160 | QHexView 161 | ) 162 | elseif(UNIX AND NOT APPLE) 163 | # ############################################################################ 164 | # UNIX 165 | # ############################################################################ 166 | message(STATUS "Building for Linux") 167 | find_package(PkgConfig REQUIRED) 168 | pkg_check_modules(YAML_CPP REQUIRED yaml-cpp) 169 | pkg_check_modules(LIBUSB REQUIRED libusb-1.0) 170 | pkg_check_modules(LIBHIDAPI REQUIRED hidapi-hidraw) 171 | 172 | # QHexView 173 | add_subdirectory("vendor/QHexView") 174 | set(QHexView_LIBRARIES QHexView) 175 | 176 | include_directories( 177 | ${Qt5Core_INCLUDE_DIRS} 178 | ${Qt5Widgets_INCLUDE_DIRS} 179 | ${Qt5Gui_PRIVATE_INCLUDE_DIRS} 180 | ${LIBUSB_INCLUDE_DIRS} 181 | ${YAML_CPP_INCLUDE_DIRS} 182 | ${LIBHIDAPI_LIBRARIES} 183 | vendor/QHexView/include 184 | ) 185 | 186 | add_executable(QDAP ${SRC_FILES} ${UI_FILES} ${QM_FILES}) 187 | target_link_libraries( 188 | QDAP 189 | PRIVATE 190 | Qt5::Core 191 | Qt5::Gui 192 | Qt5::Widgets 193 | Qt5::Network 194 | ${LIBUSB_LIBRARIES} 195 | ${YAML_CPP_LIBRARIES} 196 | ${LIBHIDAPI_LIBRARIES} 197 | QHexView 198 | ) 199 | 200 | target_include_directories(QDAP PRIVATE ${QT_INCLUDE_DIRS}) 201 | 202 | # 添加 Linux 特定的安装规则 203 | install(TARGETS QDAP DESTINATION bin) 204 | install(DIRECTORY resources/ DESTINATION share/applications) 205 | 206 | # install(FILES qdap.desktop DESTINATION share/applications) install(FILES 207 | # qdap.png DESTINATION share/icons) install(FILES qdap.service DESTINATION 208 | # etc/systemd/system) install(DIRECTORY contrib/icons/ DESTINATION 209 | # share/icons/hicolor) 210 | else() 211 | # ############################################################################ 212 | # Unsupported 213 | # ############################################################################ 214 | message(FATAL_ERROR "Unsupported platform") 215 | endif() 216 | 217 | add_definitions(-DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB) 218 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Q-DAP 2 | 3 | 4 | 5 | [![License](https://img.shields.io/github/license/ma6254/qdap.svg)](https://raw.githubusercontent.com/ma6254/qdap/master/LICENSE) 6 | [![release_version](https://img.shields.io/github/release/ma6254/qdap.svg)](https://github.com/ma6254/qdap/releases) 7 | [![last-commit](https://img.shields.io/github/last-commit/ma6254/qdap.svg)](https://github.com/ma6254/qdap/commits) 8 | 9 | ![qt_version](https://img.shields.io/badge/Qt-5.15.2_MinGW_64Bit-41cd52.svg) 10 | ![qt_make](https://img.shields.io/badge/Qt-cmake-green.svg) 11 | 12 | [![QQ群](https://img.shields.io/badge/QQ%E7%BE%A4-495477288-orange.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DkzYlCZ9VSQEq6CqUtqGiqYBZh1V5CKK&authKey=btu30mBqaqx6GSVS3futp%2BhYitMfhtAltmp%2B84Kob9xS%2F6J5yQkd0dSeozzxbclT&noverify=0&group_code=495477288) 13 | 14 | [![Packaging status](https://repology.org/badge/vertical-allrepos/qdap.svg)](https://repology.org/project/qdap/versions) 15 | 16 | [DAP-Link](https://github.com/ARM-software/CMSIS-DAP) upper by [Qt](http://qt.io) 17 | 18 | chip device libray: 19 | 20 | ## Development Progress 21 | 22 | | 名称 | Status | 介绍 | 23 | | ------------------------ | ------- | ----------------------------------- | 24 | | 设备驱动 DAP_V1 usb_hid | ✅已完成 | | 25 | | 设备驱动 DAP_V2 usb_bulk | 🚧开发中 | 设备枚举已完成,通讯已完成,DEBUG中 | 26 | | 设备驱动 CH347 usb | 📦搁置 | 等WCH开放CH347的SWD相关的API接口 | 27 | | 设备驱动 FT2232 | 📦搁置 | | 28 | | 设备驱动 JLink | 📦搁置 | JLink有Segger全套上位机支持 | 29 | | 芯片器件库的加载 | ✅已完成 | | 30 | | 芯片器件库的同步 | 🚧开发中 | 已完成zip的下载和解压 | 31 | | 芯片型号选择界面 | ✅已完成 | | 32 | | RTT Viewer界面 | 📦搁置 | | 33 | | HexEdit界面 | ✅已完成 | | 34 | | 固件打开历史记录 | 📦搁置 | | 35 | 36 | ## UI Preview 37 | 38 | ![main_window](./doc/assets/main_window.png) 39 | 40 | ![menu_target_chip](./doc/assets/menu_target_chip.png) 41 | 42 | ![enum_device_list](./doc/assets/enum_device_list.png) 43 | 44 | ## Build 45 | 46 | ### Windows 47 | 48 | ```bash 49 | git clone --recursive https://github.com/ma6254/QDAP.git 50 | python vendor.py download 51 | ``` 52 | 53 | 1. Download and install QT: [qt-unified-windows-x64-online.exe](https://qtproject.mirror.liquidtelecom.com/official_releases/online_installers/qt-unified-windows-x64-online.exe) 54 | 2. 文件 -> 打开文件或项目 -> CMakeLists.txt 55 | 3. 等待工程加载完成 56 | 4. 点击`运行(Ctrl+R)` 57 | 58 | ### Linux 59 | 60 | 1. 项目依赖:`git` `qt5` `libusb` `hidapi (hidraw)` `yaml-cpp` `cmake` `ninja` 61 | 2. 编译和安装 62 | 63 | ```bash 64 | git clone https://github.com/ma6254/QDAP.git 65 | 66 | cmake -S QDAP \ 67 | -DCMAKE_BUILD_TYPE=None \ 68 | -DCMAKE_INSTALL_PREFIX=/usr \ 69 | -B build \ 70 | -G Ninja 71 | 72 | ninja -C build 73 | 74 | ninja -C build install 75 | ``` 76 | 77 | ### Arch Linux 或衍生版 78 | 79 | 1. 可以通过 [AUR 仓库](https://aur.archlinux.org/packages/qdap-git)或[自建源](https://github.com/taotieren/aur-repo)安装 `qdap` 80 | 81 | ```bash 82 | yay -Syu qdap 83 | ``` 84 | 85 | 注意: 包名 `qdap-git` 是开发版 `qdap` 是发行版 86 | 87 | ## Reference 88 | 89 | - 90 | - 91 | - 92 | - 93 | - 94 | - 95 | - 96 | - 97 | - 98 | 99 | assets icons: 100 | 101 | [glic_elf.h](./src/glibc_elf.h) from 102 | 103 | [FlashOS.h](./src/FlashOS.h) from 104 | -------------------------------------------------------------------------------- /assets/chevron_right_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ma6254/QDAP/6455eca3a253735e0e7092a713b7ea0f3c41f909/assets/chevron_right_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.png -------------------------------------------------------------------------------- /assets/gitea_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ma6254/QDAP/6455eca3a253735e0e7092a713b7ea0f3c41f909/assets/gitea_favicon.png -------------------------------------------------------------------------------- /assets/gitee_favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ma6254/QDAP/6455eca3a253735e0e7092a713b7ea0f3c41f909/assets/gitee_favicon.ico -------------------------------------------------------------------------------- /assets/github_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ma6254/QDAP/6455eca3a253735e0e7092a713b7ea0f3c41f909/assets/github_favicon.png -------------------------------------------------------------------------------- /assets/keyboard_arrow_down_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ma6254/QDAP/6455eca3a253735e0e7092a713b7ea0f3c41f909/assets/keyboard_arrow_down_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.png -------------------------------------------------------------------------------- /comp_testing.md: -------------------------------------------------------------------------------- 1 | # Compatibility testing 2 | 3 | | Product | naoDAP v2.3 | nanoDAP-hs v1.3 | Air32 DAP | Combo 8 | H7-Tool | PicoXtools | 4 | | -------------------------- | ------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | --------------------------------------- | 5 | | Vendor | MUSE LAB | MUSE LAB | 合宙LuatOS | 矽速SIPEEDSlogic | 安富莱armfly | ppvision | 6 | | HomePage | [Click to jump](https://github.com/wuxx/nanoDAP/) | [Click to jump](https://github.com/wuxx/nanoDAP-HS) | [Click to jump](https://wiki.luatos.com/chips/air32f103/daplink.html) | [Click to jump](https://wiki.sipeed.com/hardware/zh/logic_analyzer/combo8/index.html) | [Click to jump](https://www.armfly.com/product/H7-TOOL/H7-TOOL.shtml) | [Click to jump](https://www.cnsee.net/) | 7 | | USB VID PID | | | | | | | 8 | | CMSIS-DAP_Protocol_Version | 1.10 | 0254 | | | | | 9 | | | | | | | | | 10 | | | | | | | | | 11 | | | | | | | | | 12 | | | | | | | | | 13 | | | | | | | | | 14 | | | | | | | | | 15 | | | | | | | | | 16 | | | | | | | | | 17 | | | | | | | | | 18 | -------------------------------------------------------------------------------- /doc/assets/enum_device_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ma6254/QDAP/6455eca3a253735e0e7092a713b7ea0f3c41f909/doc/assets/enum_device_list.png -------------------------------------------------------------------------------- /doc/assets/main_window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ma6254/QDAP/6455eca3a253735e0e7092a713b7ea0f3c41f909/doc/assets/main_window.png -------------------------------------------------------------------------------- /doc/assets/menu_target_chip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ma6254/QDAP/6455eca3a253735e0e7092a713b7ea0f3c41f909/doc/assets/menu_target_chip.png -------------------------------------------------------------------------------- /main.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | assets/chevron_right_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.png 4 | assets/keyboard_arrow_down_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.png 5 | assets/github_favicon.png 6 | assets/gitea_favicon.png 7 | assets/gitee_favicon.ico 8 | 9 | 10 | -------------------------------------------------------------------------------- /resources/io.github.ma6254.qdap.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Type=Application 4 | Terminal=false 5 | Name=QDAP 6 | Exec=/usr/bin/QDAP 7 | Comment=cmsis-dap upper by a Qt 8 | Icon=qdap 9 | StartupNotify=false 10 | Encoding=UTF-8 11 | Categories=Development 12 | 13 | -------------------------------------------------------------------------------- /src/DAP/debug_cm.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file debug_cm.h 3 | * @brief Access to ARM DAP (Cortex-M) using CMSIS-DAP protocol 4 | */ 5 | #ifndef DEBUG_CM_H 6 | #define DEBUG_CM_H 7 | 8 | // #include "DAP.h" 9 | 10 | 11 | // Abort Register definitions 12 | #define DAPABORT 0x00000001 // DAP Abort 13 | #define STKCMPCLR 0x00000002 // Clear STICKYCMP Flag (SW Only) 14 | #define STKERRCLR 0x00000004 // Clear STICKYERR Flag (SW Only) 15 | #define WDERRCLR 0x00000008 // Clear WDATAERR Flag (SW Only) 16 | #define ORUNERRCLR 0x00000010 // Clear STICKYORUN Flag (SW Only) 17 | 18 | // Debug Control and Status definitions 19 | #define ORUNDETECT 0x00000001 // Overrun Detect 20 | #define STICKYORUN 0x00000002 // Sticky Overrun 21 | #define TRNMODE 0x0000000C // Transfer Mode Mask 22 | #define TRNNORMAL 0x00000000 // Transfer Mode: Normal 23 | #define TRNVERIFY 0x00000004 // Transfer Mode: Pushed Verify 24 | #define TRNCOMPARE 0x00000008 // Transfer Mode: Pushed Compare 25 | #define STICKYCMP 0x00000010 // Sticky Compare 26 | #define STICKYERR 0x00000020 // Sticky Error 27 | #define READOK 0x00000040 // Read OK (SW Only) 28 | #define WDATAERR 0x00000080 // Write Data Error (SW Only) 29 | #define MASKLANE 0x00000F00 // Mask Lane Mask 30 | #define MASKLANE0 0x00000100 // Mask Lane 0 31 | #define MASKLANE1 0x00000200 // Mask Lane 1 32 | #define MASKLANE2 0x00000400 // Mask Lane 2 33 | #define MASKLANE3 0x00000800 // Mask Lane 3 34 | #define TRNCNT 0x001FF000 // Transaction Counter Mask 35 | #define CDBGRSTREQ 0x04000000 // Debug Reset Request 36 | #define CDBGRSTACK 0x08000000 // Debug Reset Acknowledge 37 | #define CDBGPWRUPREQ 0x10000000 // Debug Power-up Request 38 | #define CDBGPWRUPACK 0x20000000 // Debug Power-up Acknowledge 39 | #define CSYSPWRUPREQ 0x40000000 // System Power-up Request 40 | #define CSYSPWRUPACK 0x80000000 // System Power-up Acknowledge 41 | 42 | // Debug Select Register definitions 43 | #define CTRLSEL 0x00000001 // CTRLSEL (SW Only) 44 | #define APBANKSEL 0x000000F0 // APBANKSEL Mask 45 | #define APSEL 0xFF000000 // APSEL Mask 46 | 47 | // Access Port Register Addresses 48 | #define AP_CSW 0x00 // Control and Status Word 49 | #define AP_TAR 0x04 // Transfer Address 50 | #define AP_DRW 0x0C // Data Read/Write 51 | #define AP_BD0 0x10 // Banked Data 0 52 | #define AP_BD1 0x14 // Banked Data 1 53 | #define AP_BD2 0x18 // Banked Data 2 54 | #define AP_BD3 0x1C // Banked Data 3 55 | #define AP_ROM 0xF8 // Debug ROM Address 56 | #define AP_IDR 0xFC // Identification Register 57 | 58 | // AP Control and Status Word definitions 59 | #define CSW_SIZE 0x00000007 // Access Size: Selection Mask 60 | #define CSW_SIZE8 0x00000000 // Access Size: 8-bit 61 | #define CSW_SIZE16 0x00000001 // Access Size: 16-bit 62 | #define CSW_SIZE32 0x00000002 // Access Size: 32-bit 63 | #define CSW_ADDRINC 0x00000030 // Auto Address Increment Mask 64 | #define CSW_NADDRINC 0x00000000 // No Address Increment 65 | #define CSW_SADDRINC 0x00000010 // Single Address Increment 66 | #define CSW_PADDRINC 0x00000020 // Packed Address Increment 67 | #define CSW_DBGSTAT 0x00000040 // Debug Status 68 | #define CSW_TINPROG 0x00000080 // Transfer in progress 69 | #define CSW_HPROT 0x02000000 // User/Privilege Control 70 | #define CSW_MSTRTYPE 0x20000000 // Master Type Mask 71 | #define CSW_MSTRCORE 0x00000000 // Master Type: Core 72 | #define CSW_MSTRDBG 0x20000000 // Master Type: Debug 73 | #define CSW_RESERVED 0x01000000 // Reserved Value 74 | 75 | // Core Debug Register Address Offsets 76 | #define DBG_OFS 0x0DF0 // Debug Register Offset inside NVIC 77 | #define DBG_HCSR_OFS 0x00 // Debug Halting Control & Status Register 78 | #define DBG_CRSR_OFS 0x04 // Debug Core Register Selector Register 79 | #define DBG_CRDR_OFS 0x08 // Debug Core Register Data Register 80 | #define DBG_EMCR_OFS 0x0C // Debug Exception & Monitor Control Register 81 | 82 | // Core Debug Register Addresses 83 | #define DBG_HCSR (DBG_Addr + DBG_HCSR_OFS) 84 | #define DBG_CRSR (DBG_Addr + DBG_CRSR_OFS) 85 | #define DBG_CRDR (DBG_Addr + DBG_CRDR_OFS) 86 | #define DBG_EMCR (DBG_Addr + DBG_EMCR_OFS) 87 | 88 | // Debug Halting Control and Status Register definitions 89 | #define C_DEBUGEN 0x00000001 // Debug Enable 90 | #define C_HALT 0x00000002 // Halt 91 | #define C_STEP 0x00000004 // Step 92 | #define C_MASKINTS 0x00000008 // Mask Interrupts 93 | #define C_SNAPSTALL 0x00000020 // Snap Stall 94 | #define S_REGRDY 0x00010000 // Register R/W Ready Flag 95 | #define S_HALT 0x00020000 // Halt Flag 96 | #define S_SLEEP 0x00040000 // Sleep Flag 97 | #define S_LOCKUP 0x00080000 // Lockup Flag 98 | #define S_RETIRE_ST 0x01000000 // Sticky Retire Flag 99 | #define S_RESET_ST 0x02000000 // Sticky Reset Flag 100 | #define DBGKEY 0xA05F0000 // Debug Key 101 | 102 | // Debug Exception and Monitor Control Register definitions 103 | #define VC_CORERESET 0x00000001 // Reset Vector Catch 104 | #define VC_MMERR 0x00000010 // Debug Trap on MMU Fault 105 | #define VC_NOCPERR 0x00000020 // Debug Trap on No Coprocessor Fault 106 | #define VC_CHKERR 0x00000040 // Debug Trap on Checking Error Fault 107 | #define VC_STATERR 0x00000080 // Debug Trap on State Error Fault 108 | #define VC_BUSERR 0x00000100 // Debug Trap on Bus Error Fault 109 | #define VC_INTERR 0x00000200 // Debug Trap on Interrupt Error Fault 110 | #define VC_HARDERR 0x00000400 // Debug Trap on Hard Fault 111 | #define MON_EN 0x00010000 // Monitor Enable 112 | #define MON_PEND 0x00020000 // Monitor Pend 113 | #define MON_STEP 0x00040000 // Monitor Step 114 | #define MON_REQ 0x00080000 // Monitor Request 115 | #define TRCENA 0x01000000 // Trace Enable (DWT, ITM, ETM, TPIU) 116 | 117 | // NVIC: Interrupt Controller Type Register 118 | #define NVIC_ICT (NVIC_Addr + 0x0004) 119 | #define INTLINESNUM 0x0000001F // Interrupt Line Numbers 120 | 121 | // NVIC: CPUID Base Register 122 | #define NVIC_CPUID (NVIC_Addr + 0x0D00) 123 | #define CPUID_PARTNO 0x0000FFF0 // Part Number Mask 124 | #define CPUID_REVISION 0x0000000F // Revision Mask 125 | #define CPUID_VARIANT 0x00F00000 // Variant Mask 126 | 127 | // NVIC: Application Interrupt/Reset Control Register 128 | #define NVIC_AIRCR (NVIC_Addr + 0x0D0C) 129 | #define VECTRESET 0x00000001 // Reset Cortex-M (except Debug) 130 | #define VECTCLRACTIVE 0x00000002 // Clear Active Vector Bit 131 | #define SYSRESETREQ 0x00000004 // Reset System (except Debug) 132 | #define VECTKEY 0x05FA0000 // Write Key 133 | 134 | // NVIC: Debug Fault Status Register 135 | #define NVIC_DFSR (NVIC_Addr + 0x0D30) 136 | #define HALTED 0x00000001 // Halt Flag 137 | #define BKPT 0x00000002 // BKPT Flag 138 | #define DWTTRAP 0x00000004 // DWT Match 139 | #define VCATCH 0x00000008 // Vector Catch Flag 140 | #define EXTERNAL 0x00000010 // External Debug Request 141 | 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /src/FlashOS.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2003 - 2015 ARM LIMITED 2 | 3 | All rights reserved. 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | - Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | - Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | - Neither the name of ARM nor the names of its contributors may be used 12 | to endorse or promote products derived from this software without 13 | specific prior written permission. 14 | * 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE 19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | POSSIBILITY OF SUCH DAMAGE. 26 | ---------------------------------------------------------------------------*/ 27 | /***********************************************************************/ 28 | /* */ 29 | /* FlashOS.H: Data structures and entries */ 30 | /* for Flash Programming Functions */ 31 | /* */ 32 | /***********************************************************************/ 33 | 34 | #define VERS 1 // Interface Version 1.01 35 | 36 | #define UNKNOWN 0 // Unknown 37 | #define ONCHIP 1 // On-chip Flash Memory 38 | #define EXT8BIT 2 // External Flash Device on 8-bit Bus 39 | #define EXT16BIT 3 // External Flash Device on 16-bit Bus 40 | #define EXT32BIT 4 // External Flash Device on 32-bit Bus 41 | #define EXTSPI 5 // External Flash Device on SPI 42 | 43 | #define SECTOR_NUM 512 // Max Number of Sector Items 44 | #define PAGE_MAX 65536 // Max Page Size for Programming 45 | 46 | struct FlashSectors { 47 | unsigned long szSector; // Sector Size in Bytes 48 | unsigned long AddrSector; // Address of Sector 49 | }; 50 | 51 | #define SECTOR_END 0xFFFFFFFF, 0xFFFFFFFF 52 | 53 | struct FlashDevice { 54 | unsigned short Vers; // Version Number and Architecture 55 | char DevName[128]; // Device Name and Description 56 | unsigned short DevType; // Device Type: ONCHIP, EXT8BIT, EXT16BIT, ... 57 | unsigned long DevAdr; // Default Device Start Address 58 | unsigned long szDev; // Total Size of Device 59 | unsigned long szPage; // Programming Page Size 60 | unsigned long Res; // Reserved for future Extension 61 | unsigned char valEmpty; // Content of Erased Memory 62 | 63 | unsigned long toProg; // Time Out of Program Page Function 64 | unsigned long toErase; // Time Out of Erase Sector Function 65 | 66 | struct FlashSectors sectors[SECTOR_NUM]; 67 | }; 68 | 69 | #define FLASH_DRV_VERS (0x0100+VERS) // Driver Version, do not modify! 70 | 71 | // Flash Programming Functions (Called by FlashOS) 72 | extern int Init (unsigned long adr, // Initialize Flash 73 | unsigned long clk, 74 | unsigned long fnc); 75 | extern int UnInit (unsigned long fnc); // De-initialize Flash 76 | extern int BlankCheck (unsigned long adr, // Blank Check 77 | unsigned long sz, 78 | unsigned char pat); 79 | extern int EraseChip (void); // Erase complete Device 80 | extern int EraseSector (unsigned long adr); // Erase Sector Function 81 | extern int ProgramPage (unsigned long adr, // Program Page Function 82 | unsigned long sz, 83 | unsigned char *buf); 84 | extern unsigned long Verify (unsigned long adr, // Verify Function 85 | unsigned long sz, 86 | unsigned char *buf); 87 | -------------------------------------------------------------------------------- /src/config/chips_config.cpp: -------------------------------------------------------------------------------- 1 | #include "chips_config.h" 2 | 3 | ChipsConfig::ChipsConfig() 4 | { 5 | } 6 | 7 | ChipsConfig::~ChipsConfig() 8 | { 9 | } 10 | 11 | /******************************************************************************* 12 | * @brief 默认参数的配置文件 13 | * @param None 14 | * @return None 15 | ******************************************************************************/ 16 | ChipsConfig *ChipsConfig::get_default() 17 | { 18 | ChipsConfig *config = new ChipsConfig(); 19 | 20 | config->url = "https://github.com/ma6254/qdap_chips/archive/refs/heads/main.zip"; 21 | // config->url = "https://github.com/ma6254/qdap_chips/archive/refs/tags/v0.1.zip"; 22 | // config->url = "http://127.0.0.1:8000/main.zipConnectionRefusedError"; 23 | // config->url = "https://git.s2.ma6254.com/qdap/qdap_chips/archive/main.zip"; 24 | 25 | return config; 26 | } 27 | 28 | /******************************************************************************* 29 | * @brief 从YAML节点中加载 30 | * @param None 31 | * @return None 32 | ******************************************************************************/ 33 | int ChipsConfig::from_node(YAML::Node node) 34 | { 35 | YAML::Node tmp_node; 36 | int n = 0; 37 | // int err; 38 | 39 | if (node.IsMap() == false) 40 | return -1; 41 | 42 | tmp_node = node["url"]; 43 | if (tmp_node.IsScalar() == false) 44 | return -1; 45 | url = QString(tmp_node.as().c_str()); 46 | 47 | tmp_node = node["latest"]; 48 | if (tmp_node.IsScalar() == false) 49 | return -1; 50 | latest = QString(tmp_node.as().c_str()); 51 | 52 | return n; 53 | } 54 | 55 | /******************************************************************************* 56 | * @brief 保存到YAML节点中 57 | * @param None 58 | * @return None 59 | ******************************************************************************/ 60 | int ChipsConfig::to_node(YAML::Node *node) 61 | { 62 | int n = 0; 63 | if (node == nullptr) 64 | return -1; 65 | 66 | (*node)["url"] = qPrintable(url); 67 | n++; 68 | 69 | (*node)["latest"] = qPrintable(latest); 70 | n++; 71 | 72 | return n; 73 | } 74 | -------------------------------------------------------------------------------- /src/config/chips_config.h: -------------------------------------------------------------------------------- 1 | #ifndef CHIPS_CONFIG_H 2 | #define CHIPS_CONFIG_H 3 | 4 | #include 5 | #include 6 | #include "devices.h" 7 | 8 | class ChipsConfig : public QObject 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | ChipsConfig(); 14 | ~ChipsConfig(); 15 | 16 | static ChipsConfig *get_default(); 17 | 18 | int from_file(QString file_path = ""); 19 | int from_node(YAML::Node node); 20 | 21 | int to_file(QString file_path = ""); 22 | int to_node(YAML::Node *node); 23 | 24 | uint32_t get_cmsis_dap_clock(); 25 | 26 | QString url; 27 | QString latest; 28 | 29 | 30 | // private: 31 | }; 32 | 33 | #endif // CHIPS_CONFIG_H 34 | -------------------------------------------------------------------------------- /src/config/config.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "config.h" 6 | 7 | Config::Config() 8 | { 9 | chips = NULL; 10 | } 11 | 12 | Config::~Config() 13 | { 14 | } 15 | 16 | /******************************************************************************* 17 | * @brief 默认参数的配置文件 18 | * @param None 19 | * @return None 20 | ******************************************************************************/ 21 | Config *Config::get_default() 22 | { 23 | Config *config = new Config(); 24 | config->firmware_file_path = ""; 25 | config->auto_refresh_enum_devices = false; 26 | config->chip_vendor_name = ""; 27 | config->chip_series_name = ""; 28 | config->chip_name = ""; 29 | 30 | if (config->chips) 31 | { 32 | delete config->chips; 33 | config->chips = NULL; 34 | } 35 | config->chips = ChipsConfig::get_default(); 36 | 37 | config->cmsis_dap_port_str = "swd"; 38 | config->cmsis_dap_swj = true; 39 | config->cmsis_dap_clock_str = "1M"; 40 | config->cmsis_dap_clock = 1; 41 | config->cmsis_dap_clock_unit = Devices::MHz; 42 | config->hexview_line_bytes = 16; 43 | config->hexview_line_bytes = 1; 44 | 45 | return config; 46 | } 47 | 48 | /******************************************************************************* 49 | * @brief 配置文件默认路径 50 | * @param None 51 | * @return None 52 | ******************************************************************************/ 53 | QString Config::get_default_path() 54 | { 55 | // QStringList path; 56 | // path.append(QCoreApplication::applicationDirPath()); 57 | // path.append("config.yml"); 58 | // return path.join(QDir::separator()); 59 | return QCoreApplication::applicationDirPath() + QDir::separator() + "config.yml"; 60 | } 61 | 62 | /******************************************************************************* 63 | * @brief 从文件中加载 64 | * @param None 65 | * @return None 66 | ******************************************************************************/ 67 | int Config::from_file(QString file_path) 68 | { 69 | QFile file; 70 | QByteArray config_file_buf; 71 | bool ok; 72 | 73 | if (file_path.isEmpty()) 74 | { 75 | file_path = get_default_path(); 76 | } 77 | 78 | file.setFileName(file_path); 79 | if (file.exists() == false) 80 | return -1; 81 | 82 | ok = file.open(QIODevice::ReadOnly); 83 | config_file_buf = file.readAll(); 84 | file.close(); 85 | 86 | YAML::Node node = YAML::Load(config_file_buf.constData()); 87 | return from_node(node); 88 | } 89 | 90 | /******************************************************************************* 91 | * @brief 从YAML节点中加载 92 | * @param None 93 | * @return None 94 | ******************************************************************************/ 95 | int Config::from_node(YAML::Node node) 96 | { 97 | YAML::Node tmp_node; 98 | int err; 99 | 100 | if (node.IsMap() == false) 101 | return -1; 102 | 103 | tmp_node = node["firmware_file_path"]; 104 | if (tmp_node.IsScalar() == false) 105 | return -1; 106 | firmware_file_path = QString(tmp_node.as().c_str()); 107 | 108 | if (firmware_file_path.startsWith(QCoreApplication::applicationDirPath())) 109 | { 110 | QDir baseDir = QDir(QCoreApplication::applicationDirPath()); 111 | firmware_file_path = baseDir.relativeFilePath(firmware_file_path); 112 | } 113 | // qDebug("[cfg] firmware_file_path: %s", qPrintable(firmware_file_path)); 114 | 115 | // 自动刷新枚举设备 116 | tmp_node = node["auto_refresh_enum_devices"]; 117 | if (tmp_node.IsScalar() == false) 118 | return -1; 119 | auto_refresh_enum_devices = tmp_node.as(); 120 | 121 | YAML::Node node_hex_view = node["hex_view"]; 122 | if (node_hex_view.IsMap() == false) 123 | return -1; 124 | // qDebug("[cfg] from_node hex_view"); 125 | 126 | tmp_node = node_hex_view["line_bytes"]; 127 | if (tmp_node.IsScalar() == false) 128 | return -1; 129 | hexview_line_bytes = tmp_node.as(); 130 | 131 | tmp_node = node_hex_view["group_bytes"]; 132 | if (tmp_node.IsScalar() == false) 133 | return -1; 134 | hexview_group_bytes = tmp_node.as(); 135 | 136 | YAML::Node node_chip_selected = node["chip_selected"]; 137 | if (node_chip_selected.IsMap() == false) 138 | return -1; 139 | // qDebug("[cfg] from_node chip_selected"); 140 | 141 | tmp_node = node_chip_selected["vendor_name"]; 142 | if (tmp_node.IsScalar() == false) 143 | return -1; 144 | chip_vendor_name = QString(tmp_node.as().c_str()); 145 | 146 | tmp_node = node_chip_selected["series_name"]; 147 | if (tmp_node.IsScalar() == false) 148 | return -1; 149 | chip_series_name = QString(tmp_node.as().c_str()); 150 | 151 | tmp_node = node_chip_selected["chip_name"]; 152 | if (tmp_node.IsScalar() == false) 153 | return -1; 154 | chip_name = QString(tmp_node.as().c_str()); 155 | 156 | // qDebug("[cfg] chip_selected: [%s] [%s] [%s]", 157 | // qUtf8Printable(chip_vendor_name), 158 | // qUtf8Printable(chip_series_name), 159 | // qUtf8Printable(chip_name)); 160 | 161 | YAML::Node node_chips_library = node["chips_library"]; 162 | if (node_chips_library.IsMap() == false) 163 | return -1; 164 | // qDebug("[cfg] from_node chips_library"); 165 | 166 | if (chips) 167 | delete chips; 168 | chips = ChipsConfig::get_default(); 169 | err = chips->from_node(node_chips_library); 170 | if (err < 0) 171 | return -1; 172 | 173 | YAML::Node node_devices = node["devices"]; 174 | if (node_devices.IsMap() == false) 175 | return -1; 176 | // qDebug("[cfg] from_node devices"); 177 | 178 | YAML::Node node_devices_dap = node_devices["cmsis_dap"]; 179 | if (node_devices_dap.IsMap() == false) 180 | return -1; 181 | // qDebug("[cfg] from_node devices>> cmsis_dap"); 182 | 183 | tmp_node = node_devices_dap["port"]; 184 | if (tmp_node.IsScalar() == false) 185 | return -1; 186 | cmsis_dap_port_str = QString(tmp_node.as().c_str()); 187 | CMSIS_DAP_Base::parse_port_str(cmsis_dap_port_str, &cmsis_dap_port); 188 | // qDebug("[Config] port: %s", qPrintable(QVariant::fromValue(cmsis_dap_port).toString())); 189 | 190 | tmp_node = node_devices_dap["swj"]; 191 | if (tmp_node.IsScalar() == false) 192 | return -1; 193 | cmsis_dap_swj = tmp_node.as(); 194 | // node_devices_dap["clock"] = "1M"; 195 | 196 | tmp_node = node_devices_dap["clock"]; 197 | if (tmp_node.IsScalar() == false) 198 | return -1; 199 | cmsis_dap_clock_str = QString(tmp_node.as().c_str()); 200 | Devices::parse_clock_str(cmsis_dap_clock_str, &cmsis_dap_clock, &cmsis_dap_clock_unit); 201 | // qDebug("[Config] clock: %d %s", cmsis_dap_clock, qPrintable(QVariant::fromValue(cmsis_dap_clock_unit).toString())); 202 | 203 | // qDebug("[Config] load ok"); 204 | return 0; 205 | } 206 | 207 | /******************************************************************************* 208 | * @brief 保存到文件中 209 | * @param None 210 | * @return None 211 | ******************************************************************************/ 212 | int Config::to_file(QString file_path) 213 | { 214 | int err; 215 | YAML::Node node; 216 | 217 | err = to_node(&node); 218 | if (err < 0) 219 | return err; 220 | 221 | if (file_path.isEmpty()) 222 | { 223 | file_path = get_default_path(); 224 | } 225 | 226 | qDebug("[cfg] emitter"); 227 | YAML::Emitter emitter; 228 | // emitter.SetIndent(4); 229 | emitter << node; 230 | 231 | QFile file; 232 | file.setFileName(file_path); 233 | if (file.exists()) 234 | file.remove(); 235 | 236 | file.open(QIODevice::ReadWrite); 237 | file.write(emitter.c_str()); 238 | file.flush(); 239 | file.close(); 240 | 241 | qDebug("[cfg] config_save"); 242 | return 0; 243 | } 244 | 245 | /******************************************************************************* 246 | * @brief 保存到YAML节点中 247 | * @param None 248 | * @return None 249 | ******************************************************************************/ 250 | int Config::to_node(YAML::Node *node) 251 | { 252 | int err; 253 | 254 | if (node == nullptr) 255 | return -1; 256 | 257 | qDebug("[cfg] config_save start"); 258 | 259 | QDateTime now_date_time = QDateTime::currentDateTime(); 260 | QString now_datetime_str = now_date_time.toString("yyyy/MM/dd hh:mm:ss"); 261 | 262 | YAML::Node node_fimware_history; 263 | node_fimware_history.push_back("123"); 264 | node_fimware_history.push_back("456"); 265 | 266 | // QDir baseDir = QDir(QCoreApplication::applicationDirPath()); 267 | // firmware_file_path = baseDir.relativeFilePath(firmware_file_path); 268 | 269 | if (firmware_file_path.startsWith(QCoreApplication::applicationDirPath())) 270 | { 271 | QDir baseDir = QDir(QCoreApplication::applicationDirPath()); 272 | firmware_file_path = baseDir.relativeFilePath(firmware_file_path); 273 | } 274 | // qDebug("[cfg] firmware_file_path: %s", qPrintable(firmware_file_path)); 275 | 276 | // YAML::Node node; 277 | (*node)["notes"] = "Please do not edit this file manually."; 278 | (*node)["notes_zh_cn"] = "请不要手动编辑该文件"; 279 | (*node)["latest"] = qPrintable(now_datetime_str); 280 | (*node)["firmware_file_path"] = qPrintable(firmware_file_path); 281 | (*node)["firmware_history"] = node_fimware_history; 282 | (*node)["auto_refresh_enum_devices"] = auto_refresh_enum_devices; 283 | 284 | // hex_view 285 | // qDebug("[cfg] hex_view"); 286 | YAML::Node node_hex_view; 287 | node_hex_view["line_bytes"] = qPrintable(QString::number(hexview_line_bytes)); 288 | node_hex_view["group_bytes"] = qPrintable(QString::number(hexview_group_bytes)); 289 | (*node)["hex_view"] = node_hex_view; 290 | 291 | // 已选中的芯片 292 | // qDebug("[cfg] node_chip_selected"); 293 | YAML::Node node_chip_selected; 294 | node_chip_selected["vendor_name"] = qUtf8Printable(chip_vendor_name); 295 | node_chip_selected["series_name"] = qUtf8Printable(chip_series_name); 296 | node_chip_selected["chip_name"] = qUtf8Printable(chip_name); 297 | (*node)["chip_selected"] = node_chip_selected; 298 | 299 | // 芯片器件库 300 | // qDebug("[cfg] node_chips_library"); 301 | if (chips == NULL) 302 | return -1; 303 | YAML::Node node_chips_library; 304 | err = chips->to_node(&node_chips_library); 305 | if (err < 0) 306 | return -1; 307 | (*node)["chips_library"] = node_chips_library; 308 | 309 | // 已选中的设备 310 | // qDebug("[cfg] node_devices_selected"); 311 | YAML::Node node_devices_selected; 312 | node_devices_selected["any"] = ""; 313 | node_devices_selected["type"] = ""; 314 | node_devices_selected["manufacturer"] = ""; 315 | node_devices_selected["product"] = ""; 316 | node_devices_selected["serial"] = ""; 317 | (*node)["devices_selected"] = node_devices_selected; 318 | 319 | // 设备参数 320 | // qDebug("[cfg] node_devices_selected"); 321 | 322 | YAML::Node node_devices; 323 | 324 | YAML::Node node_devices_dap; 325 | node_devices_dap["port"] = qPrintable(QVariant::fromValue(cmsis_dap_port).toString()); 326 | node_devices_dap["swj"] = cmsis_dap_swj; 327 | node_devices_dap["clock"] = qPrintable(QString::number(cmsis_dap_clock) + Devices::get_clock_unit_str(cmsis_dap_clock_unit)); 328 | node_devices["cmsis_dap"] = node_devices_dap; 329 | 330 | (*node)["devices"] = node_devices; 331 | 332 | // QDir dir_config(config_dir_path); 333 | // if (!dir_config.exists()) 334 | // { 335 | // dir_config.mkdir("."); 336 | // } 337 | 338 | return 0; 339 | } 340 | 341 | uint32_t Config::get_cmsis_dap_clock() 342 | { 343 | switch (cmsis_dap_clock_unit) 344 | { 345 | case Devices::Hz: 346 | return cmsis_dap_clock; 347 | case Devices::KHz: 348 | return cmsis_dap_clock * 1000; 349 | case Devices::MHz: 350 | return cmsis_dap_clock * 1000 * 1000; 351 | case Devices::GHz: 352 | return cmsis_dap_clock * 1000 * 1000 * 1000; 353 | } 354 | 355 | return cmsis_dap_clock; 356 | } 357 | -------------------------------------------------------------------------------- /src/config/config.h: -------------------------------------------------------------------------------- 1 | #ifndef QDAP_CONFIG_H 2 | #define QDAP_CONFIG_H 3 | 4 | #include 5 | #include 6 | #include "devices.h" 7 | #include "chips_config.h" 8 | 9 | class Config : public QObject 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | Config(); 15 | ~Config(); 16 | 17 | static QString get_default_path(); 18 | static Config *get_default(); 19 | 20 | int from_file(QString file_path = ""); 21 | int from_node(YAML::Node node); 22 | 23 | int to_file(QString file_path = ""); 24 | int to_node(YAML::Node *node); 25 | 26 | uint32_t get_cmsis_dap_clock(); 27 | 28 | QString firmware_file_path; 29 | bool auto_refresh_enum_devices; 30 | 31 | QString chip_vendor_name; 32 | QString chip_series_name; 33 | QString chip_name; 34 | 35 | // QString chips_url; 36 | ChipsConfig *chips; 37 | 38 | QString cmsis_dap_port_str; 39 | CMSIS_DAP_Base::Port cmsis_dap_port; 40 | bool cmsis_dap_swj; 41 | QString cmsis_dap_clock_str; 42 | uint64_t cmsis_dap_clock; 43 | Devices::ClockUnit cmsis_dap_clock_unit; 44 | 45 | int hexview_line_bytes; // 每行字节数 46 | int hexview_group_bytes; // 分组字节数 47 | 48 | // private: 49 | }; 50 | 51 | #endif // QDAP_CONFIG_H 52 | -------------------------------------------------------------------------------- /src/devices/cmsis-dap/dap.h: -------------------------------------------------------------------------------- 1 | #ifndef DAP_H 2 | #define DAP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "devices.h" 8 | #include "dap.h" 9 | 10 | typedef struct 11 | { 12 | uint32_t select; 13 | uint32_t csw; 14 | } dap_state_t; 15 | 16 | typedef struct 17 | { 18 | uint32_t r[16]; 19 | uint32_t xpsr; 20 | } debug_state_t; 21 | 22 | /******************************************************************************* 23 | * @brief Information and Control commands for the CMSIS-DAP Debug Unit. 24 | ******************************************************************************/ 25 | typedef enum 26 | { 27 | DAP_CMD_INFO = 0, // DAP_Info : Get Information about CMSIS-DAP Debug Unit. 28 | DAP_CMD_HOST_STATUS = 0x01, // DAP_HostStatus : Sent status information of the debugger to Debug Unit. 29 | DAP_CMD_CONNECT = 0x02, // DAP_Connect : Connect to Device and selected DAP mode. 30 | DAP_CMD_DISCONNECT = 0x03, // DAP_Disconnect : Disconnect from active Debug Port. 31 | DAP_CMD_WRITE_ABORT = 0x08, // DAP_WriteABORT : Write ABORT Register. 32 | DAP_CMD_DELAY = 0x09, // DAP_Delay : Wait for specified delay. 33 | DAP_CMD_RESET_TARGET = 0x0A, // DAP_ResetTarget: Reset Target with Device specific sequence. 34 | } dap_gen_cmd_t; 35 | 36 | /******************************************************************************* 37 | * @brief The DAP_Info Command provides configuration information about the Debug Unit itself and the capabilities. 38 | ******************************************************************************/ 39 | typedef enum 40 | { 41 | DAP_GEN_INFO_CMD_VENDER_NAME = 1, // 0x01 = Get the Vendor Name (string). 42 | DAP_GEN_INFO_CMD_PRODUCT_NAME, // 0x02 = Get the Product Name (string). 43 | DAP_GEN_INFO_CMD_SERIAL_NNBER, // 0x03 = Get the Serial Number (string). 44 | DAP_GEN_INFO_CMD_PROTOCOL_VER, // 0x04 = Get the CMSIS-DAP Protocol Version (string). 45 | DAP_GEN_INFO_CMD_TARGET_DEV_VENDOR, // 0x05 = Get the Target Device Vendor (string). 46 | DAP_GEN_INFO_CMD_TARGET_DEV_NAME, // 0x06 = Get the Target Device Name (string). 47 | DAP_GEN_INFO_CMD_TARGET_BOARD_VENDOR, // 0x07 = Get the Target Board Vendor (string). 48 | DAP_GEN_INFO_CMD_TARGET_BOARD_NAME, // 0x08 = Get the Target Board Name (string). 49 | DAP_GEN_INFO_CMD_PRODUCT_FIRMWARE_VER, // 0x09 = Get the Product Firmware Version (string, vendor-specific format). 50 | DAP_GEN_INFO_CMD_CAPS = 0xF0, // 0xF0 = Get information about the Capabilities (BYTE) of the Debug Unit (see below for details). 51 | DAP_GEN_INFO_CMD_FREQ = 0xF1, // 0xF1 = Get the Test Domain Timer parameter information (see below for details). 52 | DAP_GEN_INFO_CMD_UART_R_BUFF_SIZE = 0xFB, // 0xFB = Get the UART Receive Buffer Size (WORD). 53 | DAP_GEN_INFO_CMD_UART_T_BUFF_SIZE = 0xFC, // 0xFC = Get the UART Transmit Buffer Size (WORD). 54 | DAP_GEN_INFO_CMD_SWO_TRACK_BUFF_SIZE = 0xFD, // 0xFD = Get the SWO Trace Buffer Size (WORD). 55 | DAP_GEN_INFO_CMD_MAX_PKG_COUNT = 0xFE, // 0xFE = Get the maximum Packet Count (BYTE). 56 | DAP_GEN_INFO_CMD_MAX_PKG_SIZE = 0xFF, // 0xFF = Get the maximum Packet Size (SHORT). 57 | } dap_gen_info_cmd_t; 58 | 59 | typedef enum 60 | { 61 | DAP_CONNECT_DEFAULT = 0, // 0 = Default mode: configuration of the DAP port mode is derived from DAP_DEFAULT_PORT (zero configuration). 62 | DAP_CONNECT_SWD = 1, // 1 = SWD mode: connect with Serial Wire Debug mode. 63 | DAP_CONNECT_JTAG = 2, // 2 = JTAG mode: connect with 4/5-pin JTAG mode. 64 | } dap_connect_port_type_t; 65 | 66 | #define DAP_OK 0x00 // 0x00 = DAP_OK: Command has been successfully executed 67 | #define DAP_ERROR 0xFF // 0xFF = DAP_ERROR: Command did not execute due to communication failure with the device. 68 | 69 | #define DAP_TRANS_DP 0x00 70 | #define DAP_TRANS_AP 0x01 71 | #define DAP_TRANS_READ_REG (1 << 1) 72 | #define DAP_TRANS_WRITE_REG (0 << 1) 73 | #define DAP_TRANS_REG_ADDR(a) (a & 0x0c) 74 | 75 | #define DCRDR 0xE000EDF8 76 | #define DCRSR 0xE000EDF4 77 | #define DHCSR 0xE000EDF0 78 | #define REGWnR (1 << 16) 79 | 80 | // DAP Transfer Response 81 | #define DAP_TRANSFER_OK (1U << 0) 82 | #define DAP_TRANSFER_WAIT (1U << 1) 83 | #define DAP_TRANSFER_FAULT (1U << 2) 84 | #define DAP_TRANSFER_ERROR (1U << 3) 85 | #define DAP_TRANSFER_MISMATCH (1U << 4) 86 | 87 | // Debug Port Register Addresses 88 | #define DP_IDCODE 0x00U // IDCODE Register (SW Read only) 89 | #define DP_ABORT 0x00U // Abort Register (SW Write only) 90 | #define DP_CTRL_STAT 0x04U // Control & Status 91 | #define DP_WCR 0x04U // Wire Control Register (SW Only) 92 | #define DP_SELECT 0x08U // Select Register (JTAG R/W & SW W) 93 | #define DP_RESEND 0x08U // Resend (SW Read Only) 94 | #define DP_RDBUFF 0x0CU // Read Buffer (Read Only) 95 | 96 | // AP CSW register, base value 97 | #define CSW_VALUE (CSW_RESERVED | CSW_MSTRDBG | CSW_HPROT | CSW_DBGSTAT | CSW_SADDRINC) 98 | 99 | #define NVIC_Addr (0xe000e000) 100 | #define DBG_Addr (0xe000edf0) 101 | 102 | typedef enum 103 | { 104 | DAP_TARGET_RESET_HOLD, // Hold target in reset 105 | DAP_TARGET_RESET_PROGRAM, // Reset target and setup for flash programming. 106 | DAP_TARGET_RESET_RUN, // Reset target and run normally 107 | DAP_TARGET_NO_DEBUG, // Disable debug on running target 108 | DAP_TARGET_DEBUG, // Enable debug on running target 109 | DAP_TARGET_HALT, // Halt the target without resetting it 110 | DAP_TARGET_RUN // Resume the target without resetting it 111 | } dap_target_reset_state_t; 112 | 113 | const char *dap_state_to_string(uint8_t state); 114 | 115 | /******************************************************************************* 116 | * @brief HID设备 117 | ******************************************************************************/ 118 | class CMSIS_DAP_Base : public Devices 119 | { 120 | Q_OBJECT 121 | 122 | public: 123 | enum Port 124 | { 125 | SWD = 1, 126 | JTAG = 2, 127 | }; 128 | Q_ENUM(Port) 129 | 130 | CMSIS_DAP_Base(); 131 | ~CMSIS_DAP_Base(); 132 | 133 | int32_t connect() override; 134 | int32_t run() override; 135 | int chip_read_memory(uint32_t addr, uint8_t *data, uint32_t size) override; 136 | int chip_write_memory(uint32_t addr, uint8_t *data, uint32_t size) override; 137 | int32_t chip_syscall_exec(const program_syscall_t *sysCallParam, uint32_t entry, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4) override; 138 | 139 | static int parse_port_str(QString str, Port *port); 140 | 141 | virtual QString get_manufacturer_string() { return "Unknow"; } 142 | virtual QString get_product_string() { return "Unknow"; } 143 | virtual QString get_serial_string() { return "Unknow"; } 144 | virtual QString get_version_string() { return "Unknow"; } 145 | 146 | virtual int32_t open_device() = 0; 147 | virtual int32_t close_device() = 0; 148 | 149 | virtual int32_t dap_request(uint8_t *tx_data, uint32_t tx_len, uint8_t *rx_data, uint32_t rx_buf_size, uint32_t *rx_len) = 0; 150 | 151 | int get_info_cmsis_dap_protocol_version(QString *version); 152 | 153 | int32_t dap_connect(uint8_t port); 154 | int32_t dap_disconnect(); 155 | int32_t dap_reset_target(); 156 | int32_t dap_set_swj_clock(uint32_t clock); 157 | int32_t dap_set_target_state_hw(dap_target_reset_state_t state); 158 | int32_t dap_set_target_reset(uint8_t asserted); 159 | 160 | int32_t dap_swj_sequence(uint8_t bit_count, uint8_t *data); 161 | int32_t dap_swd_config(uint8_t cfg); 162 | int32_t dap_swd_sequence_write(uint8_t count, uint8_t *tx_data); 163 | 164 | int32_t dap_transfer_config(uint8_t idle_cyless, uint16_t wait_retry, uint16_t match_retry); 165 | int32_t dap_swd_transfer(uint8_t req, uint32_t tx_data, uint8_t *resp, uint32_t *rx_data); 166 | int32_t dap_swd_transfer_retry(uint8_t req, uint32_t tx_data, uint8_t *resp, uint32_t *rx_data); 167 | int32_t dap_swd_transfer_block(uint8_t req, uint32_t tx_data, uint8_t *resp, uint32_t *timestamp, uint32_t *rx_data); 168 | 169 | int32_t dap_swd_reset(); 170 | int32_t dap_swd_switch(uint16_t val); 171 | 172 | int32_t dap_swd_read_dp(uint8_t addr, uint32_t *val); 173 | int32_t dap_swd_write_dp(uint8_t addr, uint32_t val); 174 | int32_t dap_swd_read_ap(uint8_t addr, uint32_t *val); 175 | int32_t dap_swd_write_ap(uint8_t addr, uint32_t val); 176 | 177 | int32_t dap_read_data(uint32_t addr, uint32_t *data); 178 | int32_t dap_write_data(uint32_t addr, uint32_t data); 179 | int32_t dap_read_word(uint32_t addr, uint32_t *val); 180 | int32_t dap_write_word(uint32_t addr, uint32_t val); 181 | 182 | int32_t dap_read_byte(uint32_t addr, uint8_t *val); 183 | int32_t dap_write_byte(uint32_t addr, uint8_t val); 184 | 185 | int32_t dap_read_block(uint32_t addr, uint8_t *data, uint32_t size); 186 | int32_t dap_write_block(uint32_t addr, uint8_t *data, uint32_t size); 187 | 188 | int32_t dap_swd_read_idcode(uint32_t *idcode); 189 | int32_t dap_jtag_2_swd(); 190 | int32_t swd_init_debug(); 191 | 192 | int32_t swd_write_debug_state(debug_state_t *state); 193 | int32_t swd_wait_until_halted(void); 194 | int32_t swd_read_core_register(uint32_t n, uint32_t *val); 195 | int32_t swd_write_core_register(uint32_t n, uint32_t val); 196 | 197 | private: 198 | int32_t dap_hid_resp_status_return(uint8_t *rx_data); 199 | 200 | dap_state_t dap_state; 201 | }; 202 | 203 | #include "dap_usb_hid.h" 204 | #include "dap_usb_bulk.h" 205 | 206 | #endif // DAP_H 207 | -------------------------------------------------------------------------------- /src/devices/cmsis-dap/dap_usb_bulk.cpp: -------------------------------------------------------------------------------- 1 | #include "dap_usb_bulk.h" 2 | #include "utils.h" 3 | 4 | extern libusb_context *g_libusb_context; 5 | libusb_device **CMSIS_DAP_V2::libusb_device_list = NULL; 6 | 7 | CMSIS_DAP_V2::CMSIS_DAP_V2(libusb_device *dev, int interface_number, uint8_t ep_in_addr, uint8_t ep_out_addr) 8 | { 9 | int32_t err; 10 | int rc = 0; 11 | char buf_str_descriptor[1024]; 12 | 13 | this->dev = dev; 14 | this->interface_number = interface_number; 15 | this->ep_in_addr = ep_in_addr; 16 | this->ep_out_addr = ep_out_addr; 17 | err_code = 0; 18 | 19 | // qDebug("[CMSIS_DAP_V2] interface:%d ep_in:0x%02X ep_out:0x%02X", interface_number, ep_in_addr, ep_out_addr); 20 | 21 | rc = libusb_get_device_descriptor(this->dev, &desc); 22 | if (rc < LIBUSB_SUCCESS) 23 | { 24 | qDebug("[CMSIS_DAP_V2] libusb_get_device_descriptor fail %d", rc); 25 | err_code = -1; 26 | return; 27 | } 28 | 29 | close_device(); 30 | err = open_device(); 31 | if (err < 0) 32 | { 33 | qDebug("[CMSIS_DAP_V2] open fail"); 34 | err_code = -1; 35 | return; 36 | } 37 | 38 | memset(buf_str_descriptor, 0, sizeof(buf_str_descriptor)); 39 | rc = libusb_get_string_descriptor_ascii(handle, desc.iProduct, (unsigned char *)buf_str_descriptor, sizeof(buf_str_descriptor)); 40 | if (rc < LIBUSB_SUCCESS) 41 | { 42 | qDebug("[CMSIS_DAP_V2] libusb_get_string_descriptor_ascii iProduct fail %d", rc); 43 | err_code = -1; 44 | close_device(); 45 | return; 46 | } 47 | product_str = QString::fromUtf8(buf_str_descriptor, rc); 48 | 49 | rc = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, (unsigned char *)buf_str_descriptor, sizeof(buf_str_descriptor)); 50 | if (rc < LIBUSB_SUCCESS) 51 | { 52 | qDebug("[CMSIS_DAP_V2] libusb_get_string_descriptor_ascii iManufacturer fail %d", rc); 53 | err_code = -1; 54 | close_device(); 55 | return; 56 | } 57 | manufacturer_str = QString::fromUtf8(buf_str_descriptor, rc); 58 | 59 | char buf_str_serial[33]; 60 | rc = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, (unsigned char *)buf_str_serial, sizeof(buf_str_serial)); 61 | if (rc < LIBUSB_SUCCESS) 62 | { 63 | qDebug("[CMSIS_DAP_V2] libusb_get_string_descriptor_ascii iSerialNumber fail %d", rc); 64 | err_code = -1; 65 | close_device(); 66 | return; 67 | } 68 | serial_number_str = QString::fromUtf8(buf_str_serial, rc); 69 | 70 | struct libusb_config_descriptor *config_desc; 71 | err = libusb_get_config_descriptor(dev, 0, &config_desc); 72 | if (err < LIBUSB_SUCCESS) 73 | { 74 | err_code = -1; 75 | close_device(); 76 | return; 77 | } 78 | 79 | const struct libusb_interface_descriptor *intf_desc = &config_desc->interface[interface_number].altsetting[0]; 80 | 81 | char interface_str_buf[256] = {0}; 82 | err = libusb_get_string_descriptor_ascii( 83 | handle, intf_desc->iInterface, 84 | (uint8_t *)interface_str_buf, sizeof(interface_str_buf)); 85 | if (err < LIBUSB_SUCCESS) 86 | { 87 | err_code = -1; 88 | close_device(); 89 | return; 90 | } 91 | interface_str = QString::fromUtf8(interface_str_buf, sizeof(interface_str_buf)); 92 | 93 | err = get_info_cmsis_dap_protocol_version(&version_str); 94 | if (err > 0) 95 | { 96 | qDebug("[CMSIS_DAP_V2] get_version fail"); 97 | err_code = -1; 98 | close_device(); 99 | return; 100 | } 101 | 102 | // qDebug("[CMSIS_DAP_V2] get_version: %s", qPrintable(version_str)); 103 | 104 | // qDebug(" iProduct: %s", qPrintable(product_str)); 105 | // qDebug(" iManufacturer: %s", qPrintable(manufacturer_str)); 106 | // qDebug(" iSerialNumber: %s", qPrintable(serial_number_str)); 107 | 108 | close_device(); 109 | } 110 | 111 | CMSIS_DAP_V2::~CMSIS_DAP_V2() 112 | { 113 | close_device(); 114 | } 115 | 116 | int32_t CMSIS_DAP_V2::enum_device(DeviceList *dev_list) 117 | { 118 | libusb_device_handle *handle = NULL; 119 | int rc = 0; 120 | int err; 121 | ssize_t count = 0; 122 | char buf_product[1024]; 123 | char buf_serial[1024]; 124 | uint8_t ep_out_addr; 125 | uint8_t ep_in_addr; 126 | // char buf_manufacturer[1024]; 127 | // char buf_serial_number[1024]; 128 | 129 | if (dev_list == NULL) 130 | return -1; 131 | 132 | dev_list->clear(); 133 | 134 | if (libusb_device_list) 135 | { 136 | libusb_free_device_list(libusb_device_list, 1); 137 | libusb_device_list = NULL; 138 | } 139 | 140 | // count = libusb_get_device_list(context, &list); 141 | count = libusb_get_device_list(g_libusb_context, &libusb_device_list); 142 | 143 | // qDebug("[CMSIS_DAP_V2] ====================================================="); 144 | // qDebug("[CMSIS_DAP_V2] libusb_get_device_list %d", count); 145 | 146 | for (size_t idx = 0; idx < count; idx++) 147 | { 148 | libusb_device *device = libusb_device_list[idx]; 149 | libusb_device_descriptor dev_desc = {0}; 150 | int interface_number = -1; 151 | bool is_find = false; 152 | 153 | rc = libusb_get_device_descriptor(device, &dev_desc); 154 | if (rc != LIBUSB_SUCCESS) 155 | { 156 | qDebug("[CMSIS_DAP_V2] libusb_get_device_descriptor fail %d", rc); 157 | continue; 158 | } 159 | // qDebug("Vendor:Device = 0x%04X:0x%04X", desc.idVendor, desc.idProduct); 160 | 161 | rc = libusb_open(device, &handle); 162 | if (rc != LIBUSB_SUCCESS) 163 | { 164 | if (rc == LIBUSB_ERROR_NOT_SUPPORTED) 165 | continue; 166 | 167 | qDebug("[CMSIS_DAP_V2] libusb_open fail %d %s", rc, libusb_error_name(rc)); 168 | continue; 169 | } 170 | 171 | // memset(buf_manufacturer, 0, sizeof(buf_manufacturer)); 172 | memset(buf_product, 0, sizeof(buf_product)); 173 | // memset(buf_serial_number, 0, sizeof(buf_serial_number)); 174 | 175 | if (dev_desc.iProduct == 0) 176 | { 177 | qDebug("[CMSIS_DAP_V2] iProduct empty"); 178 | libusb_close(handle); 179 | continue; 180 | } 181 | 182 | rc = libusb_get_string_descriptor_ascii(handle, dev_desc.iSerialNumber, (unsigned char *)buf_serial, sizeof(buf_serial)); 183 | if (rc < LIBUSB_SUCCESS) 184 | { 185 | // qDebug("[CMSIS_DAP_V2] libusb_get_string_descriptor_ascii iSerialNumber fail %d", rc); 186 | libusb_close(handle); 187 | continue; 188 | } 189 | 190 | rc = libusb_get_string_descriptor_ascii(handle, dev_desc.iProduct, (unsigned char *)buf_product, sizeof(buf_product)); 191 | if (rc < LIBUSB_SUCCESS) 192 | { 193 | // qDebug("[CMSIS_DAP_V2] libusb_get_string_descriptor_ascii iProduct fail %d", rc); 194 | libusb_close(handle); 195 | continue; 196 | } 197 | 198 | // qDebug("[CMSIS_DAP_V2] iProduct %s", buf_product); 199 | 200 | if (strstr(buf_product, "CMSIS-DAP") == NULL) 201 | { 202 | libusb_close(handle); 203 | continue; 204 | } 205 | 206 | for (int config = 0; config < dev_desc.bNumConfigurations; config++) 207 | { 208 | struct libusb_config_descriptor *config_desc; 209 | err = libusb_get_config_descriptor(device, config, &config_desc); 210 | if (err != LIBUSB_SUCCESS) 211 | { 212 | qDebug("[CMSIS_DAP_V2] libusb_get_config_descriptor fail %d", err); 213 | libusb_close(handle); 214 | continue; 215 | } 216 | 217 | for (int interface = 0; interface < config_desc->bNumInterfaces; interface++) 218 | { 219 | const struct libusb_interface_descriptor *intf_desc = &config_desc->interface[interface].altsetting[0]; 220 | 221 | if (intf_desc->iInterface != 0) 222 | { 223 | char interface_str[256] = {0}; 224 | 225 | err = libusb_get_string_descriptor_ascii( 226 | handle, intf_desc->iInterface, 227 | (uint8_t *)interface_str, sizeof(interface_str)); 228 | if (err < LIBUSB_SUCCESS) 229 | { 230 | continue; 231 | } 232 | 233 | if (strstr(interface_str, "CMSIS-DAP") == NULL) 234 | { 235 | continue; 236 | } 237 | 238 | if (intf_desc->bNumEndpoints < 2) 239 | { 240 | continue; 241 | } 242 | 243 | if ((intf_desc->endpoint[0].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK || 244 | (intf_desc->endpoint[0].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_OUT) 245 | { 246 | continue; 247 | } 248 | 249 | if ((intf_desc->endpoint[1].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK || 250 | (intf_desc->endpoint[1].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_IN) 251 | { 252 | continue; 253 | } 254 | 255 | ep_out_addr = intf_desc->endpoint[0].bEndpointAddress; 256 | ep_in_addr = intf_desc->endpoint[1].bEndpointAddress; 257 | 258 | interface_number = intf_desc->bInterfaceNumber; 259 | 260 | // qDebug("[CMSIS_DAP_V2] found interface %d string '%s'", intf_desc->bInterfaceNumber, interface_str); 261 | 262 | is_find = true; 263 | break; 264 | } 265 | 266 | if (is_find) 267 | break; 268 | } 269 | } 270 | libusb_close(handle); 271 | 272 | if (interface_number == -1) 273 | continue; 274 | 275 | CMSIS_DAP_V2 *tmp_dev = new CMSIS_DAP_V2(device, interface_number, ep_in_addr, ep_out_addr); 276 | if (tmp_dev->error() == -1) 277 | { 278 | delete tmp_dev; 279 | continue; 280 | } 281 | 282 | dev_list->push_back(tmp_dev); 283 | } 284 | 285 | // if (dev_list->count() != 0) 286 | // { 287 | // qDebug("[CMSIS_DAP_V2] ====================================================="); 288 | // qDebug("[CMSIS_DAP_V2] dev_list %d", dev_list->count()); 289 | // } 290 | 291 | return dev_list->count(); 292 | } 293 | 294 | bool CMSIS_DAP_V2::equal(const Devices &device) 295 | { 296 | CMSIS_DAP_V2 *dap_v2 = (CMSIS_DAP_V2 *)&device; 297 | bool result; 298 | 299 | if ((interface_number == dap_v2->interface_number) && // 接口号 300 | (interface_str == dap_v2->interface_str) && // 接口名称 301 | (serial_number_str == dap_v2->serial_number_str) && // 序列号 302 | (manufacturer_str == dap_v2->manufacturer_str) && // 厂商 303 | (product_str == dap_v2->product_str) // 产品 304 | ) 305 | { 306 | result = true; 307 | } 308 | else 309 | { 310 | result = false; 311 | } 312 | 313 | return result; 314 | } 315 | 316 | int32_t CMSIS_DAP_V2::open_device() 317 | { 318 | int err; 319 | 320 | close_device(); 321 | err = libusb_open(dev, &handle); 322 | if (err != LIBUSB_SUCCESS) 323 | { 324 | QString err_info = QString::fromUtf8(libusb_error_name(err)); 325 | qDebug("[CMSIS_DAP_V2] libusb_open fail: %s", qUtf8Printable(err_info)); 326 | return -1; 327 | } 328 | 329 | err = libusb_claim_interface(handle, interface_number); 330 | if (err != LIBUSB_SUCCESS) 331 | { 332 | QString err_info = QString::fromUtf8(libusb_error_name(err)); 333 | qDebug("[CMSIS_DAP_V2] libusb_claim_interface fail: %s", qUtf8Printable(err_info)); 334 | return -1; 335 | } 336 | 337 | return 0; 338 | } 339 | 340 | int32_t CMSIS_DAP_V2::close_device() 341 | { 342 | 343 | if (handle == NULL) 344 | return -1; 345 | 346 | libusb_release_interface(handle, interface_number); 347 | libusb_close(handle); 348 | handle = NULL; 349 | 350 | return 0; 351 | } 352 | 353 | int32_t CMSIS_DAP_V2::dap_request(uint8_t *tx_data, uint32_t tx_len, uint8_t *rx_data, uint32_t rx_buf_size, uint32_t *rx_len) 354 | { 355 | // qDebug("[CMSIS_DAP_V2] dap_request"); 356 | 357 | int err; 358 | int actual_length; 359 | // uint8_t tx_buf[512] = {0}; 360 | // uint8_t rx_buf[512] = {0}; 361 | 362 | if (handle == NULL) 363 | { 364 | qDebug("[CMSIS_DAP_V2] dap_request handle is nullptr"); 365 | return -1; 366 | } 367 | 368 | // 输出端点 369 | err = libusb_bulk_transfer(handle, ep_out_addr, tx_data, tx_len, &actual_length, 1000); 370 | if (err < 0) 371 | { 372 | QString err_info = QString::fromUtf8(libusb_error_name(err)); 373 | qDebug("[CMSIS_DAP_V2] dap_request out fail: %s", qUtf8Printable(err_info)); 374 | return DEVICE_ERR_DAP_REQUEST_FAIL; 375 | } 376 | 377 | // QThread::msleep(20); 378 | 379 | // 输入端点 380 | err = libusb_bulk_transfer(handle, ep_in_addr, rx_data, rx_buf_size, &actual_length, 1000); 381 | if (err < 0) 382 | { 383 | QString err_info = QString::fromUtf8(libusb_error_name(err)); 384 | qDebug("[CMSIS_DAP_V2] dap_request in fail: %s", qUtf8Printable(err_info)); 385 | 386 | if (err == LIBUSB_ERROR_TIMEOUT) 387 | { 388 | return Devices::Error::DEVICE_ERR_DAP_REQUEST_TIMEOUT; 389 | } 390 | else 391 | return -1; 392 | } 393 | 394 | if (actual_length == 0) 395 | { 396 | qDebug("[CMSIS_DAP_V2] dap_request response is empty"); 397 | return -1; 398 | } 399 | 400 | // hexdump(rx_data, actual_length); 401 | 402 | // qDebug("[CMSIS_DAP_V2] dap_request ok"); 403 | // 首字节一定与发送相等 404 | if (rx_data[0] != tx_data[0]) 405 | { 406 | qDebug("[CMSIS_DAP_V2] dap_request out&in cmd not equal: 0x%02X 0x%02x", tx_data[0], rx_data[0]); 407 | return -1; 408 | } 409 | 410 | *rx_len = actual_length; 411 | return 0; 412 | } 413 | -------------------------------------------------------------------------------- /src/devices/cmsis-dap/dap_usb_bulk.h: -------------------------------------------------------------------------------- 1 | #ifndef DAP_USB_BULK_H 2 | #define DAP_USB_BULK_H 3 | 4 | #include 5 | #include 6 | #include "devices.h" 7 | 8 | /******************************************************************************* 9 | * @brief DAP_USB_Bulk CMSIS-DAP v2 uses USB bulk endpoints 10 | ******************************************************************************/ 11 | class CMSIS_DAP_V2 : public CMSIS_DAP_Base 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | CMSIS_DAP_V2(libusb_device *dev, int interface_number, uint8_t ep_in_addr, uint8_t ep_out_addr); 17 | ~CMSIS_DAP_V2(); 18 | 19 | static int32_t enum_device(DeviceList *dev_list); 20 | static bool device_list_compare(QList *now_list, QList *prev_list); 21 | 22 | bool equal(const Devices &device) override; 23 | 24 | int32_t open_device() override; 25 | int32_t close_device() override; 26 | 27 | int32_t error() { return err_code; } 28 | 29 | DeviceType type() const override { return DAP_USB_Bulk; } 30 | QString get_manufacturer_string() override { return manufacturer_str; } 31 | QString get_product_string() override { return interface_str; } 32 | QString get_serial_string() override { return serial_number_str; } 33 | QString get_version_string() override { return version_str; } 34 | QString get_interface_string() { return interface_str; } 35 | // QString get_version_string() override { return hid_version; } 36 | 37 | int32_t dap_request(uint8_t *tx_data, uint32_t tx_len, uint8_t *rx_data, uint32_t rx_buf_size, uint32_t *rx_len) override; 38 | 39 | private: 40 | static libusb_device **libusb_device_list; 41 | 42 | libusb_device *dev = NULL; 43 | libusb_device_handle *handle = NULL; 44 | libusb_device_descriptor desc = {0}; 45 | int interface_number; 46 | uint8_t ep_in_addr; 47 | uint8_t ep_out_addr; 48 | 49 | QString product_str; 50 | QString manufacturer_str; 51 | QString serial_number_str; 52 | QString version_str; 53 | QString interface_str; 54 | 55 | int32_t err_code; 56 | }; 57 | 58 | #endif // DAP_USB_BULK_H 59 | -------------------------------------------------------------------------------- /src/devices/cmsis-dap/dap_usb_hid.h: -------------------------------------------------------------------------------- 1 | #ifndef DAP_USB_HID_H 2 | #define DAP_USB_HID_H 3 | 4 | #ifdef _WIN32 5 | #include 6 | #include 7 | #else 8 | #include 9 | #include 10 | #endif // _WIN32 11 | #include "dap.h" 12 | #include "flash_algo.h" 13 | #include "devices.h" 14 | #include "device_list.h" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #define DAP_HID_VID 0x0D28 21 | #define DAP_HID_PID 0x0204 22 | 23 | /******************************************************************************* 24 | * @brief HID设备 25 | ******************************************************************************/ 26 | class DAP_HID : public CMSIS_DAP_Base 27 | { 28 | Q_OBJECT 29 | 30 | public: 31 | DAP_HID(QString usb_path); 32 | DAP_HID(Devices *devices); 33 | ~DAP_HID(); 34 | 35 | static int32_t enum_device_id(DeviceList *dev_list, uint16_t vid = DAP_HID_VID, uint16_t pid = DAP_HID_PID); 36 | static int32_t enum_device(DeviceList *dev_list); 37 | 38 | bool equal(const Devices &device) override; 39 | 40 | DeviceType type() const override 41 | { 42 | return DAP_USB_HID; 43 | } 44 | QString get_manufacturer_string() override { return hid_manufacturer; } 45 | QString get_product_string() override { return hid_product; } 46 | QString get_serial_string() override { return hid_serial; } 47 | QString get_version_string() override { return hid_version; } 48 | 49 | int32_t error() { return err_code; } 50 | QString get_usb_path() { return usb_path; } 51 | 52 | int32_t open_device() override; 53 | int32_t close_device() override; 54 | 55 | // int32_t connect(); 56 | int32_t run(); 57 | 58 | QString dap_hid_get_manufacturer_string(); 59 | QString dap_hid_get_product_string(); 60 | int32_t dap_hid_get_info(); 61 | 62 | uint32_t idcode() { return tmp_idcode; } 63 | 64 | int32_t dap_request(uint8_t *tx_data, uint32_t tx_len, uint8_t *rx_data, uint32_t rx_buf_size, uint32_t *rx_len) override; 65 | 66 | int32_t dap_hid_request(uint8_t *tx_data, uint8_t *rx_data); 67 | int32_t dap_hid_resp_status_return(uint8_t *rx_data); 68 | 69 | QString dap_get_info_vendor_name(); 70 | QString dap_get_info_product_name(); 71 | QString dap_get_info_serial_number(); 72 | QString dap_get_info_cmsis_dap_protocol_version(); 73 | int32_t dap_get_info_caps(); 74 | int32_t dap_get_info_freq(); 75 | 76 | private: 77 | hid_device *dev; 78 | QString usb_path; // 79 | dap_state_t dap_state; 80 | 81 | QString hid_manufacturer; 82 | QString hid_product; 83 | QString hid_serial; 84 | QString hid_version; 85 | 86 | uint32_t tmp_idcode; 87 | int32_t err_code; 88 | }; 89 | 90 | #endif // DAP_USB_HID_H 91 | -------------------------------------------------------------------------------- /src/devices/device_list.cpp: -------------------------------------------------------------------------------- 1 | #include "device_list.h" 2 | 3 | DeviceList::DeviceList() 4 | { 5 | } 6 | 7 | DeviceList::~DeviceList() 8 | { 9 | } 10 | 11 | // bool DeviceList::remove_device(Devices device, DeviceList *fixed_list) 12 | // { 13 | // // qDebug("[DeviceList] remove_device one this_len:%d", count()); 14 | 15 | // if (count() == 0) 16 | // { 17 | // // qDebug("[DeviceList] remove_device one this_len:0 result:false"); 18 | // return false; 19 | // } 20 | 21 | // bool is_found = false; 22 | // int i = 0; 23 | 24 | // while (i != count()) 25 | // { 26 | 27 | // if (device.equal(at(i))) 28 | // { 29 | // // removeAt(i); 30 | // Devices *fixed_device = takeAt(i); 31 | 32 | // if (fixed_list) 33 | // fixed_list->append(fixed_device); 34 | 35 | // is_found = true; 36 | 37 | // continue; 38 | // } 39 | 40 | // i++; 41 | // } 42 | 43 | // // qDebug("[DeviceList] remove_device one result:%d", is_found); 44 | 45 | // return is_found; 46 | // } 47 | 48 | bool DeviceList::remove_device(Devices *p_device, DeviceList *fixed_list) 49 | { 50 | // if (p_device == NULL) 51 | // return false; 52 | 53 | // return remove_device(*p_device, fixed_list); 54 | 55 | // qDebug("[DeviceList] remove_device one this_len:%d", count()); 56 | 57 | if (count() == 0) 58 | { 59 | // qDebug("[DeviceList] remove_device one this_len:0 result:false"); 60 | return false; 61 | } 62 | 63 | bool is_found = false; 64 | int i = 0; 65 | 66 | while (i != count()) 67 | { 68 | 69 | if (p_device->equal(*at(i))) 70 | { 71 | // removeAt(i); 72 | Devices *fixed_device = takeAt(i); 73 | 74 | if (fixed_list) 75 | fixed_list->append(fixed_device); 76 | 77 | is_found = true; 78 | 79 | continue; 80 | } 81 | 82 | i++; 83 | } 84 | 85 | // qDebug("[DeviceList] remove_device one result:%d", is_found); 86 | 87 | return is_found; 88 | } 89 | 90 | bool DeviceList::remove_device(DeviceList device_list, DeviceList *fixed_list) 91 | { 92 | 93 | // qDebug("[DeviceList] remove_device this_len:%d list_len:%d", count(), device_list.count()); 94 | 95 | for (int i = 0; i < device_list.count(); i++) 96 | { 97 | // qDebug("[DeviceList] remove_device index:%d", i); 98 | 99 | remove_device(device_list[i], fixed_list); 100 | } 101 | 102 | // qDebug("[DeviceList] remove_device remaining:%d", count()); 103 | 104 | if (count() == 0) 105 | return false; 106 | else 107 | return true; 108 | } 109 | 110 | DeviceList DeviceList::filt(Devices::DeviceType device_type) 111 | { 112 | DeviceList result_list; 113 | result_list.clear(); 114 | 115 | for (int i = 0; i < count(); i++) 116 | { 117 | Devices *tmp_dev = this->at(i); 118 | 119 | if (tmp_dev->type() == device_type) 120 | { 121 | result_list.append(tmp_dev); 122 | } 123 | } 124 | 125 | return result_list; 126 | } 127 | 128 | bool DeviceList::contains(const Devices &value) const 129 | { 130 | for (int i = 0; i < count(); i++) 131 | { 132 | if (this->at(i)->equal(value)) 133 | { 134 | return true; 135 | } 136 | } 137 | 138 | return false; 139 | } 140 | 141 | void DeviceList::release_all() 142 | { 143 | 144 | // qDebug("[DeviceList] release_all count:%d", count()); 145 | 146 | for (int i = 0; i < count(); i++) 147 | { 148 | Devices *tmp_dev = this->at(i); 149 | 150 | if (tmp_dev == NULL) 151 | continue; 152 | 153 | delete tmp_dev; 154 | } 155 | 156 | this->clear(); 157 | 158 | // qDebug("[DeviceList] release_all done"); 159 | } 160 | -------------------------------------------------------------------------------- /src/devices/device_list.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICE_LIST_H 2 | #define DEVICE_LIST_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "devices.h" 8 | 9 | class Devices; 10 | class DeviceList; 11 | 12 | /******************************************************************************* 13 | * @brief 设备列表 14 | ******************************************************************************/ 15 | class DeviceList : public QList 16 | { 17 | public: 18 | DeviceList(); 19 | ~DeviceList(); 20 | 21 | // bool remove_device(Devices device, DeviceList *fixed_list = NULL); 22 | bool remove_device(Devices *p_device, DeviceList *fixed_list = NULL); 23 | bool remove_device(DeviceList device_list, DeviceList *fixed_list = NULL); 24 | 25 | DeviceList filt(Devices::DeviceType device_type); 26 | 27 | bool contains(const Devices &value) const; 28 | 29 | void release_all(); 30 | 31 | private: 32 | QStringList aaa; 33 | }; 34 | 35 | #endif // DEVICE_LIST_H 36 | -------------------------------------------------------------------------------- /src/devices/devices.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "devices.h" 3 | #include "dap_usb_hid.h" 4 | 5 | Devices::Devices() 6 | { 7 | } 8 | 9 | Devices::Devices(const Devices &src_device) 10 | { 11 | memcpy(this, &src_device, sizeof(Devices)); 12 | } 13 | 14 | Devices::~Devices() 15 | { 16 | } 17 | 18 | QString Devices::device_type_to_string(DeviceType t) 19 | { 20 | switch (t) 21 | { 22 | case DAP_USB_HID: 23 | return "DAP_USB_HID"; 24 | case DAP_USB_Bulk: 25 | return "DAP_USB_Bulk"; 26 | } 27 | 28 | return QString::asprintf("UnknownDeviceType:%d", t); 29 | } 30 | 31 | Devices::DeviceType Devices::string_to_device_type(QString str) 32 | { 33 | if (str == "DAP_USB_HID") 34 | return DAP_USB_HID; 35 | 36 | if (str == "DAP_USB_Bulk") 37 | return DAP_USB_Bulk; 38 | 39 | return UnknownDeviceType; 40 | } 41 | 42 | int Devices::parse_clock_str(QString str, uint64_t *clock, ClockUnit *unit) 43 | { 44 | str = str.toUpper(); 45 | QRegExp regexp = QRegExp("^(\\d+)([KMG]*)$"); 46 | int pos = regexp.indexIn(str); 47 | 48 | if (pos == -1) 49 | return -1; 50 | 51 | *clock = regexp.cap(1).toULongLong(); 52 | 53 | QString uint_str = regexp.cap(2); 54 | if (uint_str.isEmpty()) 55 | *unit = Hz; 56 | else if (uint_str == "K") 57 | *unit = KHz; 58 | else if (uint_str == "M") 59 | *unit = MHz; 60 | else if (uint_str == "G") 61 | *unit = GHz; 62 | else 63 | { 64 | return -1; 65 | } 66 | 67 | return 0; 68 | } 69 | 70 | QString Devices::get_clock_unit_str(ClockUnit unit) 71 | { 72 | switch (unit) 73 | { 74 | case Hz: 75 | return ""; 76 | case KHz: 77 | return "K"; 78 | case MHz: 79 | return "M"; 80 | case GHz: 81 | return "G"; 82 | } 83 | 84 | return ""; 85 | } 86 | 87 | bool Devices::equal(const Devices &device) 88 | { 89 | bool result = false; 90 | 91 | if (type() != device.type()) 92 | return false; 93 | 94 | switch (type()) 95 | { 96 | case DAP_USB_HID: 97 | { 98 | result = ((DAP_HID *)this)->equal(device); 99 | 100 | qDebug("[Devices] DAP_HID equal result: %d", result); 101 | 102 | return result; 103 | } 104 | break; 105 | case DAP_USB_Bulk: 106 | { 107 | result = ((CMSIS_DAP_V2 *)this)->equal(device); 108 | 109 | qDebug("[Devices] DAP_Bulk equal result: %d", result); 110 | 111 | return result; 112 | } 113 | break; 114 | } 115 | 116 | qDebug("[Devices] equal"); 117 | 118 | return result; 119 | } 120 | 121 | bool Devices::device_list_compare(DeviceList now_list, DeviceList prev_list, DeviceList *added_list, DeviceList *fixed_list, DeviceList *removed_list) 122 | { 123 | bool is_changed = false; 124 | 125 | DeviceList now_list_bak; 126 | DeviceList prev_list_bak; 127 | DeviceList fixed_list_bak; 128 | DeviceList tmp_list; 129 | 130 | fixed_list_bak.clear(); 131 | 132 | now_list_bak.clear(); 133 | now_list_bak.append(now_list); 134 | 135 | prev_list_bak.clear(); 136 | prev_list_bak.append(prev_list); 137 | 138 | // qDebug("[Devices] compare added_list"); 139 | now_list_bak.remove_device(prev_list, &fixed_list_bak); 140 | 141 | // qDebug("[Devices] compare removed_list"); 142 | prev_list_bak.remove_device(now_list, &fixed_list_bak); 143 | 144 | tmp_list.clear(); 145 | 146 | // qDebug("[Devices] fixed_list deduplication"); 147 | while (fixed_list_bak.count()) 148 | { 149 | Devices *tmp_dev = fixed_list_bak.takeFirst(); 150 | bool is_found = false; 151 | 152 | for (int i = 0; i < fixed_list_bak.count(); i++) 153 | { 154 | 155 | if (tmp_dev->equal(*fixed_list_bak[i])) 156 | { 157 | is_found = true; 158 | break; 159 | } 160 | } 161 | 162 | if (is_found == false) 163 | tmp_list.append(tmp_dev); 164 | } 165 | 166 | fixed_list_bak.clear(); 167 | fixed_list_bak.append(tmp_list); 168 | 169 | if (prev_list.count() != now_list.count()) 170 | is_changed = true; 171 | 172 | if (now_list_bak.count()) 173 | { 174 | is_changed = true; 175 | } 176 | 177 | if (prev_list_bak.count()) 178 | { 179 | is_changed = true; 180 | } 181 | 182 | if (is_changed) 183 | { 184 | qDebug("[Devices] added:%d fixed:%d removes:%d", now_list_bak.count(), fixed_list_bak.count(), prev_list_bak.count()); 185 | } 186 | 187 | // if (now_list_bak.count() || prev_list_bak.count()) 188 | // { 189 | // is_changed = true; 190 | // } 191 | 192 | if (added_list != NULL) 193 | { 194 | added_list->clear(); 195 | added_list->append(now_list_bak); 196 | } 197 | 198 | if (fixed_list != NULL) 199 | { 200 | fixed_list->clear(); 201 | fixed_list->append(fixed_list_bak); 202 | } 203 | 204 | if (removed_list != NULL) 205 | { 206 | removed_list->clear(); 207 | removed_list->append(prev_list_bak); 208 | } 209 | 210 | return is_changed; 211 | } 212 | -------------------------------------------------------------------------------- /src/devices/devices.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICES_H 2 | #define DEVICES_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "flash_algo.h" 8 | 9 | class Devices; 10 | class DeviceList; 11 | class DAP_HID; 12 | 13 | /******************************************************************************* 14 | * @brief 设备 15 | ******************************************************************************/ 16 | class Devices : public QObject 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | enum DeviceType 22 | { 23 | UnknownDeviceType = 0, 24 | DAP_USB_HID, 25 | DAP_USB_Bulk, 26 | DAP_USB_JLink, 27 | DAP_ETH_JLink, 28 | DAP_CH347, 29 | DAP_FT2232, 30 | }; 31 | Q_ENUM(DeviceType) 32 | 33 | enum Error 34 | { 35 | DEVICE_ERR_UNKNOW = -1, 36 | DEVICE_ERR_DAP_REQUEST_FAIL = -2, 37 | DEVICE_ERR_DAP_REQUEST_TIMEOUT = -3, 38 | DEVICE_ERR_DAP_TRANSFER_ERROR = -4, 39 | DEVICE_ERR_DAP_RESPONSE_ERROR = -5, 40 | }; 41 | Q_ENUM(Error) 42 | 43 | enum Clock 44 | { 45 | DEVICE_CLOCK_1HZ = 1, 46 | DEVICE_CLOCK_1KHZ = DEVICE_CLOCK_1HZ * 1000, 47 | DEVICE_CLOCK_1MHZ = DEVICE_CLOCK_1KHZ * 1000, 48 | }; 49 | Q_ENUM(Clock) 50 | 51 | enum ClockUnit 52 | { 53 | Hz, 54 | KHz, 55 | MHz, 56 | GHz, 57 | }; 58 | Q_ENUM(ClockUnit) 59 | 60 | Devices(); 61 | Devices(const Devices &src_device); 62 | ~Devices(); 63 | 64 | virtual int32_t connect() = 0; 65 | virtual int32_t run() = 0; 66 | virtual int chip_read_memory(uint32_t addr, uint8_t *data, uint32_t size) = 0; 67 | virtual int chip_write_memory(uint32_t addr, uint8_t *data, uint32_t size) = 0; 68 | virtual int32_t chip_syscall_exec(const program_syscall_t *sysCallParam, uint32_t entry, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4) = 0; 69 | 70 | uint32_t get_idcode() { return tmp_idcode; } 71 | 72 | static QString device_type_to_string(DeviceType t); 73 | static DeviceType string_to_device_type(QString str); 74 | static int parse_clock_str(QString str, uint64_t *clock, ClockUnit *unit); 75 | static QString get_clock_unit_str(ClockUnit unit); 76 | 77 | // typedef enum 78 | // { 79 | // JTAG, 80 | // SWD, 81 | // } transport_t; 82 | 83 | // virtual bool support_transports(transport_t t) = 0; 84 | // bool support_transport_jtag() { return support_transports(JTAG); } 85 | // bool support_transport_swd() { return support_transports(SWD); } 86 | 87 | virtual DeviceType type() const 88 | { 89 | return UnknownDeviceType; 90 | } 91 | QString type_str() 92 | { 93 | return device_type_to_string(type()); 94 | } 95 | 96 | virtual QString get_manufacturer_string() 97 | { 98 | return "Unknow"; 99 | } 100 | virtual QString get_product_string() 101 | { 102 | return "Unknow"; 103 | } 104 | 105 | virtual bool equal(const Devices &device); 106 | 107 | static bool device_list_compare(DeviceList now_list, 108 | DeviceList prev_list, 109 | DeviceList *added_list = NULL, 110 | DeviceList *fixed_list = NULL, 111 | DeviceList *removed_list = NULL); 112 | 113 | // virtual QString get_manufacturer_string() = 0; 114 | // virtual QString get_product_string() = 0; 115 | protected: 116 | uint32_t tmp_idcode; 117 | }; 118 | 119 | #include "device_list.h" 120 | #include "dap.h" 121 | 122 | #endif // DEVICES_H 123 | -------------------------------------------------------------------------------- /src/flash_algo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "utils.h" 3 | #include "flash_algo.h" 4 | 5 | flash_func_def_t func_symbol_list[FLASH_FUNC_COUNT] = { 6 | {"Init", 1}, 7 | {"UnInit", 1}, 8 | {"BlankCheck", 0}, 9 | {"EraseChip", 1}, 10 | {"EraseSector", 1}, 11 | {"ProgramPage", 1}, 12 | // "Verify", 13 | }; 14 | 15 | const uint32_t BLOB_HEADER = 0xE7FDBE00; 16 | 17 | FlashAlgo::FlashAlgo() 18 | { 19 | } 20 | 21 | FlashAlgo::~FlashAlgo(void) 22 | { 23 | } 24 | 25 | int32_t FlashAlgo::load(QString file_path, uint32_t ram_start) 26 | { 27 | qDebug("[FlashAlgo] Load ==================================================="); 28 | 29 | this->ram_start = ram_start; 30 | 31 | QFile elf_file(file_path); 32 | if (elf_file.open(QIODevice::ReadOnly) == false) 33 | { 34 | qDebug("[FlashAlgo] cannot open algo file"); 35 | return -1; 36 | } 37 | 38 | file_buf = elf_file.readAll(); 39 | elf_file.close(); 40 | 41 | memcpy(&elf_header, file_buf.data(), sizeof(elf_header)); 42 | 43 | if ((memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) && 44 | (elf_header.e_type == 0x7F)) 45 | { 46 | qDebug("[main] not ELF file"); 47 | return -1; 48 | } 49 | 50 | // qDebug("[main] read elf ok"); 51 | // qDebug("[main] e_shoff: 0x%08X", elf_header.e_shoff); // Section Header Table 在文件中的偏移 52 | // qDebug("[main] e_shentsize: 0x%08X", elf_header.e_shentsize); // 单个Section Header大小 53 | // qDebug("[main] e_shnum: 0x%08X", elf_header.e_shnum); // Section Header的数量 54 | // qDebug("[main] e_shstrndx: 0x%08X", elf_header.e_shstrndx); // Section Header字符串表在Section Header Table中的索引 55 | 56 | memcpy(&sh_str_section, file_buf.data() + elf_header.e_shoff + sizeof(Elf32_Shdr) * elf_header.e_shstrndx, sizeof(Elf32_Shdr)); 57 | // qDebug("[main] str_shdrs: 0x%08X", str_shdrs.sh_name); 58 | // qDebug("[main] str_sh_offset: 0x%08X", str_shdrs.sh_offset); 59 | 60 | QString str_section_name = section_get_name(sh_str_section); 61 | if (str_section_name != ".shstrtab") 62 | { 63 | qDebug("[FlashAlgo] not found str_tabel_section %s", qPrintable(str_section_name)); 64 | return -1; 65 | } 66 | 67 | bool is_find_sym_section = false; 68 | bool is_find_str_section = false; 69 | bool is_find_PrgCode_section = false; 70 | bool is_find_PrgData_section = false; 71 | 72 | // qDebug("[main] Section ====================================================="); 73 | 74 | for (int i = 0; i < elf_header.e_shnum; i++) 75 | { 76 | Elf32_Shdr shdrs; 77 | memcpy(&shdrs, file_buf.data() + elf_header.e_shoff + sizeof(Elf32_Shdr) * i, sizeof(Elf32_Shdr)); 78 | 79 | QString section_name = section_get_name(shdrs); 80 | 81 | if ((section_name == ".symtab") && (shdrs.sh_type == SHT_SYMTAB)) 82 | { 83 | symbol_section = shdrs; 84 | is_find_sym_section = true; 85 | } 86 | else if ((section_name == ".strtab") && (shdrs.sh_type == SHT_STRTAB)) 87 | { 88 | str_section = shdrs; 89 | is_find_str_section = true; 90 | } 91 | else if (section_name == "PrgCode") 92 | { 93 | PrgCode_section = shdrs; 94 | is_find_PrgCode_section = true; 95 | } 96 | else if (section_name == "PrgData") 97 | { 98 | PrgData_section = shdrs; 99 | is_find_PrgData_section = true; 100 | } 101 | 102 | // qDebug("[main] ==== %d Section =========================================", i); 103 | // qDebug(" sh_name: 0x%08X %s", shdrs.sh_name, file_buf.data() + str_shdrs.sh_offset + shdrs.sh_name); 104 | // qDebug(" sh_offset: 0x%08X", shdrs.sh_offset); 105 | // qDebug(" sh_type: 0x%08X %s", shdrs.sh_type, section_type_to_str(shdrs.sh_type)); 106 | 107 | // qDebug(" %2d %16s %16s addr:0x%08X size:0x%08X %s", 108 | // i, 109 | // qPrintable(section_name), 110 | // qPrintable(section_type_to_str(shdrs.sh_type)), 111 | // shdrs.sh_offset, 112 | // shdrs.sh_size, 113 | // qPrintable(section_flags_to_str(shdrs.sh_flags))); 114 | } 115 | 116 | if (is_find_sym_section == false) 117 | { 118 | qDebug("[FlashAlgo] not found symbol_tabel_section"); 119 | return -1; 120 | } 121 | 122 | if (is_find_str_section == false) 123 | { 124 | qDebug("[FlashAlgo] not found str_tabel_section"); 125 | return -1; 126 | } 127 | 128 | if (is_find_PrgCode_section == false) 129 | { 130 | qDebug("[FlashAlgo] not found PrgCode_section"); 131 | return -1; 132 | } 133 | 134 | if (is_find_PrgData_section == false) 135 | { 136 | qDebug("[FlashAlgo] not found PrgData_section"); 137 | return -1; 138 | } 139 | 140 | bool is_find_FlashDevice_symbol = false; 141 | bool is_find_flash_func_symbol[FLASH_FUNC_COUNT]; 142 | 143 | memset(is_find_flash_func_symbol, false, sizeof(is_find_flash_func_symbol)); 144 | 145 | // qDebug("[main] Symbol ======================================================"); 146 | 147 | for (uint32_t start_addr = 0; start_addr < symbol_section.sh_size; start_addr += sizeof(Elf32_Sym)) 148 | { 149 | Elf32_Sym symbol; 150 | memcpy(&symbol, file_buf.data() + symbol_section.sh_offset + start_addr, sizeof(Elf32_Sym)); 151 | 152 | QString symbol_name = symbol_get_name(symbol); 153 | 154 | if (symbol_name == "FlashDevice") 155 | { 156 | FlashDevice_symbol = symbol; 157 | is_find_FlashDevice_symbol = true; 158 | } 159 | 160 | for (uint32_t i = 0; i < FLASH_FUNC_COUNT; i++) 161 | { 162 | if (symbol_name == func_symbol_list[i].name) 163 | { 164 | flash_func_symbol_list[i] = symbol; 165 | is_find_flash_func_symbol[i] = true; 166 | } 167 | } 168 | 169 | // uint32_t str_name_len = strlen(pstr); 170 | // QByteArray symbol_name_buf(pstr, str_name_len); 171 | // QString symbol_name(symbol_name_buf); 172 | 173 | // qDebug(" st_name: 0x%08X %s", symbol.st_name, file_buf.data() + str_shdrs.sh_offset + symbol.st_name); 174 | 175 | // qDebug(" %dvsize:0x%08X %s ", 176 | // start_addr, 177 | // symbol.st_size, 178 | // qPrintable(symbol_name)); 179 | } 180 | 181 | if (is_find_FlashDevice_symbol == false) 182 | { 183 | qDebug("[FlashAlgo] not found FlashDevice_symbol"); 184 | } 185 | 186 | if (sizeof(FlashDevice) != FlashDevice_symbol.st_size) 187 | { 188 | qDebug("[FlashAlgo] FlashDevice_symbol size mismatch"); 189 | } 190 | 191 | // qDebug("[FlashAlgo] FlashDevice_symbol addr:0x%08X size:0x%X", 192 | // FlashDevice_symbol.st_value, 193 | // FlashDevice_symbol.st_size); 194 | 195 | memcpy(&flash_device_info, file_buf.data() + PrgCode_section.sh_offset + FlashDevice_symbol.st_value, sizeof(FlashDevice)); 196 | 197 | qDebug("[FlashAlgo] FlashDevice:"); 198 | qDebug("[FlashAlgo] Ver: 0x%04X", flash_device_info.Vers); 199 | qDebug("[FlashAlgo] DevName: %s", flash_device_info.DevName); 200 | qDebug("[FlashAlgo] DevType: %s", qPrintable(FlashDevice_type_to_str(flash_device_info.DevType))); 201 | qDebug("[FlashAlgo] DevAdr: 0x%08lX", static_cast(flash_device_info.DevAdr)); 202 | qDebug("[FlashAlgo] szDev: 0x%08lX", static_cast(flash_device_info.szDev)); 203 | qDebug("[FlashAlgo] szPage: 0x%08lX", static_cast(flash_device_info.szPage)); 204 | 205 | if (FLASH_DRV_VERS != flash_device_info.Vers) 206 | { 207 | qDebug("[FlashAlgo] Unsupport verison"); 208 | return -1; 209 | } 210 | 211 | // qDebug("[FlashAlgo] FuncSymbol:"); 212 | 213 | bool is_func_symbol_all_done = true; 214 | flash_code.clear(); 215 | flash_code.append((char *)&BLOB_HEADER, sizeof(BLOB_HEADER)); 216 | flash_code.append(file_buf.data() + PrgCode_section.sh_offset, PrgCode_section.sh_size); 217 | 218 | for (uint32_t i = 0; i < FLASH_FUNC_COUNT; i++) 219 | { 220 | if ((is_find_flash_func_symbol[i] == false) && (func_symbol_list[i].must == true)) 221 | { 222 | is_func_symbol_all_done = false; 223 | } 224 | 225 | // qDebug(" %d %16s 0x%08X 0x%08X %10s | %s", 226 | // i, 227 | // func_symbol_list[i].name, 228 | // flash_func_symbol_list[i].st_value, 229 | // flash_func_symbol_list[i].st_size, 230 | // (func_symbol_list[i].must) ? "must" : "optional", 231 | // (is_find_flash_func_symbol[i] == false) ? "fail" : "ok"); 232 | } 233 | 234 | if (is_func_symbol_all_done == false) 235 | { 236 | qDebug("[FlashAlgo] FuncSymbol check fail"); 237 | return -1; 238 | } 239 | 240 | qDebug("[FlashAlgo] falsh_code:"); 241 | for (uint32_t i = 0; i < FLASH_FUNC_COUNT; i++) 242 | { 243 | qDebug(" %d %12s : 0x%08X", i, func_symbol_list[i].name, flash_func_symbol_list[i].st_value); 244 | } 245 | 246 | qDebug("[FlashAlgo] FuncSymbol check all ok"); 247 | // qDebug("[FlashAlgo] flash_code size:%d", flash_code.length()); 248 | if ((flash_code.length() % 4) != 0) 249 | { 250 | qDebug("[FlashAlgo] flash_code size:%d wrong, should be 4-byte aligned", 251 | flash_code.length()); 252 | return -1; 253 | } 254 | 255 | sys_call_s.breakpoint = ram_start + 1; 256 | sys_call_s.static_base = ram_start + sizeof(BLOB_HEADER) + PrgCode_section.sh_size + PrgData_section.sh_size; 257 | sys_call_s.stack_pointer = sys_call_s.static_base + flash_device_info.szPage * 2; 258 | 259 | qDebug("[FlashAlgo] sys_call_s:"); 260 | qDebug(" breakpoint: %08X", sys_call_s.breakpoint); 261 | qDebug(" static_base: %08X", sys_call_s.static_base); 262 | qDebug(" stack_pointer: %08X", sys_call_s.stack_pointer); 263 | 264 | program_buffer = sys_call_s.static_base + PrgData_section.sh_size; 265 | 266 | qDebug("[FlashAlgo] program_buffer: %08X", program_buffer); 267 | // hexdump((uint8_t *)flash_code.data(), flash_code.length()); 268 | // dump_flash_code((uint32_t *)flash_code.data(), flash_code.length() / 4); 269 | 270 | return 0; 271 | } 272 | 273 | QString FlashAlgo::section_get_name(Elf32_Shdr section) 274 | { 275 | char *pstr = file_buf.data() + sh_str_section.sh_offset + section.sh_name; 276 | 277 | uint32_t str_name_len = strlen(pstr); 278 | QByteArray name_buf(pstr, str_name_len); 279 | QString name(name_buf); 280 | 281 | return name; 282 | } 283 | 284 | QString FlashAlgo::symbol_get_name(Elf32_Sym symbol) 285 | { 286 | char *pstr = file_buf.data() + str_section.sh_offset + symbol.st_name; 287 | 288 | uint32_t str_name_len = strlen(pstr); 289 | QByteArray name_buf(pstr, str_name_len); 290 | QString name(name_buf); 291 | 292 | return name; 293 | } 294 | 295 | QString FlashAlgo::section_type_to_str(uint32_t section_type) 296 | { 297 | switch (section_type) 298 | { 299 | case SHT_NULL: 300 | return "SHT_NULL"; 301 | case SHT_PROGBITS: 302 | return "SHT_PROGBITS"; 303 | case SHT_SYMTAB: 304 | return "SHT_SYMTAB"; 305 | case SHT_STRTAB: 306 | return "SHT_STRTAB"; 307 | case SHT_RELA: 308 | return "SHT_RELA"; 309 | case SHT_HASH: 310 | return "SHT_HASH"; 311 | case SHT_DYNAMIC: 312 | return "SHT_DYNAMIC"; 313 | case SHT_NOTE: 314 | return "SHT_NOTE"; 315 | case SHT_NOBITS: 316 | return "SHT_NOBITS"; 317 | case SHT_REL: 318 | return "SHT_REL"; 319 | case SHT_SHLIB: 320 | return "SHT_SHLIB"; 321 | case SHT_DYNSYM: 322 | return "SHT_DYNSYM"; 323 | case SHT_INIT_ARRAY: 324 | return "SHT_INIT_ARRAY"; 325 | case SHT_FINI_ARRAY: 326 | return "SHT_FINI_ARRAY"; 327 | case SHT_PREINIT_ARRAY: 328 | return "SHT_PREINIT_ARRAY"; 329 | case SHT_GROUP: 330 | return "SHT_GROUP"; 331 | case SHT_SYMTAB_SHNDX: 332 | return "SHT_SYMTAB_SHNDX"; 333 | case SHT_NUM: 334 | return "SHT_NUM"; 335 | case SHT_LOOS: 336 | return "SHT_LOOS"; 337 | case SHT_GNU_ATTRIBUTES: 338 | return "SHT_GNU_ATTRIBUTES"; 339 | case SHT_GNU_HASH: 340 | return "SHT_GNU_HASH"; 341 | case SHT_GNU_LIBLIST: 342 | return "SHT_GNU_LIBLIST"; 343 | case SHT_CHECKSUM: 344 | return "SHT_CHECKSUM"; 345 | case SHT_LOSUNW: 346 | return "SHT_LOSUNW / SHT_SUNW_move"; 347 | case SHT_SUNW_COMDAT: 348 | return "SHT_SUNW_COMDAT"; 349 | case SHT_SUNW_syminfo: 350 | return "SHT_SUNW_syminfo"; 351 | case SHT_GNU_verdef: 352 | return "SHT_GNU_verdef"; 353 | case SHT_GNU_verneed: 354 | return "SHT_GNU_verneed"; 355 | case SHT_GNU_versym: 356 | return "SHT_GNU_versym / SHT_HISUNW / SHT_HIOS"; 357 | case SHT_LOPROC: 358 | return "SHT_LOPROC"; 359 | case SHT_HIPROC: 360 | return "SHT_HIPROC"; 361 | case SHT_LOUSER: 362 | return "SHT_LOUSER"; 363 | case SHT_HIUSER: 364 | return "SHT_HIUSER"; 365 | } 366 | 367 | return ""; 368 | } 369 | 370 | QString FlashAlgo::section_flags_to_str(uint32_t section_flags) 371 | { 372 | QStringList str_list; 373 | 374 | if (section_flags & SHF_WRITE) 375 | str_list.append("SHF_WRITE"); 376 | 377 | if (section_flags & SHF_ALLOC) 378 | str_list.append("SHF_ALLOC"); 379 | 380 | if (section_flags & SHF_EXECINSTR) 381 | str_list.append("SHF_EXECINSTR"); 382 | 383 | if (section_flags & SHF_MERGE) 384 | str_list.append("SHF_MERGE"); 385 | 386 | if (section_flags & SHF_STRINGS) 387 | str_list.append("SHF_STRINGS"); 388 | 389 | if (section_flags & SHF_INFO_LINK) 390 | str_list.append("SHF_INFO_LINK"); 391 | 392 | if (section_flags & SHF_LINK_ORDER) 393 | str_list.append("SHF_LINK_ORDER"); 394 | 395 | if (section_flags & SHF_OS_NONCONFORMING) 396 | str_list.append("SHF_OS_NONCONFORMING"); 397 | 398 | if (section_flags & SHF_GROUP) 399 | str_list.append("SHF_GROUP"); 400 | 401 | if (section_flags & SHF_TLS) 402 | str_list.append("SHF_TLS"); 403 | 404 | if (section_flags & SHF_COMPRESSED) 405 | str_list.append("SHF_COMPRESSED"); 406 | 407 | if (section_flags & SHF_MASKOS) 408 | str_list.append("SHF_MASKOS"); 409 | 410 | if (section_flags & SHF_MASKPROC) 411 | str_list.append("SHF_MASKPROC"); 412 | 413 | if (section_flags & SHF_ORDERED) 414 | str_list.append("SHF_ORDERED"); 415 | 416 | if (section_flags & SHF_EXCLUDE) 417 | str_list.append("SHF_EXCLUDE"); 418 | 419 | QString ret_str = str_list.join(" "); 420 | 421 | if (ret_str.length() == 0) 422 | { 423 | ret_str.push_back("SHF_NULL"); 424 | } 425 | else 426 | { 427 | ret_str.push_front("["); 428 | ret_str.push_back("]"); 429 | } 430 | 431 | return ret_str; 432 | } 433 | 434 | QString FlashAlgo::FlashDevice_type_to_str(uint16_t type) 435 | { 436 | switch (type) 437 | { 438 | case UNKNOWN: 439 | return "UNKNOWN"; 440 | case ONCHIP: 441 | return "ONCHIP"; 442 | case EXT8BIT: 443 | return "EXT8BIT"; 444 | case EXT16BIT: 445 | return "EXT16BIT"; 446 | case EXT32BIT: 447 | return "EXT32BIT"; 448 | case EXTSPI: 449 | return "EXTSPI"; 450 | } 451 | 452 | return ""; 453 | } 454 | 455 | bool FlashAlgo::is_flash_func_impl(flash_func_t f) 456 | { 457 | if (f >= FLASH_FUNC_MAX) 458 | return false; 459 | 460 | if (flash_func_symbol_list[f].st_size == 0) 461 | return false; 462 | 463 | return true; 464 | } 465 | 466 | FlashDevice FlashAlgo::get_flash_device_info(void) 467 | { 468 | return flash_device_info; 469 | } 470 | 471 | QByteArray FlashAlgo::get_flash_code(void) 472 | { 473 | return flash_code; 474 | } 475 | 476 | uint32_t FlashAlgo::get_flash_func_offset(flash_func_t f) 477 | { 478 | if (f >= FLASH_FUNC_MAX) 479 | return UINT32_MAX; 480 | 481 | if (flash_func_symbol_list[f].st_size == 0) 482 | return UINT32_MAX; 483 | 484 | return ram_start + sizeof(BLOB_HEADER) + flash_func_symbol_list[f].st_value; 485 | } 486 | 487 | uint32_t FlashAlgo::get_flash_start(void) 488 | { 489 | return flash_device_info.DevAdr; 490 | } 491 | 492 | program_syscall_t FlashAlgo::get_sys_call_s(void) 493 | { 494 | return sys_call_s; 495 | } 496 | 497 | uint32_t FlashAlgo::program_mem_buffer(void) 498 | { 499 | return program_buffer; 500 | } 501 | -------------------------------------------------------------------------------- /src/flash_algo.h: -------------------------------------------------------------------------------- 1 | #ifndef FLASHALGO_H 2 | #define FLASHALGO_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "glibc_elf.h" 9 | #include "FlashOS.h" 10 | 11 | #define FLASH_FUNC_COUNT 6 12 | 13 | typedef struct 14 | { 15 | const char *name; 16 | uint8_t must; 17 | } flash_func_def_t; 18 | 19 | typedef enum 20 | { 21 | FLASH_FUNC_Init = 0, 22 | FLASH_FUNC_UnInit, 23 | FLASH_FUNC_BlankCheck, 24 | FLASH_FUNC_EraseChip, 25 | FLASH_FUNC_EraseSector, 26 | FLASH_FUNC_ProgramPage, 27 | FLASH_FUNC_Verify, 28 | FLASH_FUNC_MAX, 29 | } flash_func_t; 30 | 31 | typedef struct 32 | { 33 | uint32_t breakpoint; 34 | uint32_t static_base; 35 | uint32_t stack_pointer; 36 | } program_syscall_t; 37 | 38 | class FlashAlgo : public QObject 39 | { 40 | Q_OBJECT 41 | 42 | public: 43 | FlashAlgo(); 44 | ~FlashAlgo(); 45 | 46 | int32_t load(QString file_path, uint32_t ram_start = 0x20000000); 47 | bool is_flash_func_impl(flash_func_t f); 48 | FlashDevice get_flash_device_info(void); 49 | QByteArray get_flash_code(void); 50 | uint32_t get_flash_func_offset(flash_func_t f); 51 | uint32_t get_flash_start(void); 52 | program_syscall_t get_sys_call_s(void); 53 | uint32_t program_mem_buffer(void); 54 | 55 | private: 56 | QString section_get_name(Elf32_Shdr section); 57 | QString symbol_get_name(Elf32_Sym symbol); 58 | QString section_type_to_str(uint32_t section_type); 59 | QString section_flags_to_str(uint32_t section_flags); 60 | QString FlashDevice_type_to_str(uint16_t type); 61 | 62 | uint32_t ram_start; 63 | 64 | QByteArray file_buf; 65 | Elf32_Ehdr elf_header; 66 | Elf32_Shdr sh_str_section; 67 | Elf32_Shdr symbol_section; 68 | Elf32_Shdr str_section; 69 | Elf32_Shdr PrgCode_section; 70 | Elf32_Shdr PrgData_section; 71 | 72 | Elf32_Sym FlashDevice_symbol; 73 | Elf32_Sym flash_func_symbol_list[FLASH_FUNC_COUNT]; 74 | QByteArray flash_code; 75 | uint32_t program_buffer; 76 | 77 | program_syscall_t sys_call_s; 78 | 79 | // Elf32_Sym Init_symbol; 80 | // Elf32_Sym UnInit_symbol; 81 | // Elf32_Sym BlankCheck_symbol; 82 | // Elf32_Sym EraseChip_symbol; 83 | // Elf32_Sym EraseSector_symbol; 84 | // Elf32_Sym ProgramPage_symbol; 85 | // Elf32_Sym Verify_symbol; 86 | 87 | FlashDevice flash_device_info; 88 | }; 89 | 90 | #endif // FLASHALGO_H 91 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "devices.h" 3 | #include "device_list.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | libusb_context *g_libusb_context = NULL; 10 | 11 | #if !_WIN32 12 | libusb_hotplug_callback_handle g_libusb_hotplug_callback_handle; 13 | 14 | static int libusb_hotplug_callback(libusb_context *ctx, libusb_device *device, libusb_hotplug_event event, void *user_data) 15 | { 16 | if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) 17 | { 18 | qDebug("Device inserted"); 19 | } 20 | else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) 21 | { 22 | qDebug("Device removed"); 23 | } 24 | return 0; 25 | } 26 | #endif // !_WIN32 27 | 28 | int main(int argc, char *argv[]) 29 | { 30 | int rc = 0; 31 | 32 | rc = libusb_init(&g_libusb_context); 33 | if (rc != 0) 34 | { 35 | qDebug("[amin] libusb_init fail %d", rc); 36 | libusb_exit(g_libusb_context); 37 | return -1; 38 | } 39 | 40 | #if !_WIN32 41 | 42 | rc = libusb_hotplug_register_callback(g_libusb_context, 43 | LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 44 | LIBUSB_HOTPLUG_NO_FLAGS, 45 | LIBUSB_HOTPLUG_MATCH_ANY, 46 | LIBUSB_HOTPLUG_MATCH_ANY, 47 | LIBUSB_HOTPLUG_MATCH_ANY, 48 | libusb_hotplug_callback, 49 | NULL, 50 | &g_libusb_hotplug_callback_handle); 51 | 52 | if (rc != LIBUSB_SUCCESS) 53 | { 54 | fprintf(stderr, "Failed to register hotplug callback\n"); 55 | return 1; 56 | } 57 | 58 | #endif // !_WIN32 59 | 60 | qRegisterMetaType("uint32_t"); 61 | qRegisterMetaType("ProgramWorker::ChipOp"); 62 | // qRegisterMetaType("Devices"); 63 | qRegisterMetaType("Devices *"); 64 | qRegisterMetaType("DeviceList"); 65 | 66 | QApplication a(argc, argv); 67 | MainWindow w; 68 | w.show(); 69 | a.exec(); 70 | 71 | #if !_WIN32 72 | libusb_hotplug_deregister_callback(g_libusb_context, g_libusb_hotplug_callback_handle); 73 | #endif // !_WIN32 74 | libusb_exit(g_libusb_context); 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /src/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "config.h" 10 | #include "devices.h" 11 | #include "flash_algo.h" 12 | // #include "hex_viewer.h" 13 | #include "program_worker.h" 14 | #include "chip_selecter.h" 15 | 16 | #if _WIN32 17 | #include "win_hotplug_notify.h" 18 | #endif // _WIN32 19 | 20 | // views 21 | #include "chips_config_dialog.h" 22 | #include "enum_writer_list.h" 23 | 24 | QT_BEGIN_NAMESPACE 25 | namespace Ui 26 | { 27 | class MainWindow; 28 | } 29 | QT_END_NAMESPACE 30 | 31 | class MainWindow : public QMainWindow 32 | { 33 | Q_OBJECT 34 | 35 | public: 36 | MainWindow(QWidget *parent = nullptr); 37 | ~MainWindow(); 38 | 39 | QString now_time(void); 40 | void log_append(QString str); 41 | void log_debug(QString str); 42 | void log_info(QString str); 43 | void log_warn(QString str); 44 | void log_error(QString str); 45 | 46 | // void config_save(void); 47 | // int config_load(void); 48 | 49 | void set_dock_device_info(); 50 | void set_dock_chip_info(); 51 | 52 | bool detect_git(); 53 | 54 | void set_hexview_line_bytes(int bytes); 55 | void set_hexview_group_bytes(int bytes); 56 | int open_firmware_file(QString file_path); 57 | 58 | Devices *current_device(); 59 | 60 | 61 | private slots: 62 | void cb_action_open_firmware_file(void); 63 | void cb_action_save_firmware_file(void); 64 | 65 | void cb_action_view_info(void); 66 | void cb_action_log_clear(void); 67 | 68 | void cb_action_hexview_goto_addr(void); 69 | void cb_action_hexview_goto_start(void); 70 | void cb_action_hexview_goto_end(void); 71 | void cb_action_hexview_line_bytes(void); 72 | void cb_action_hexview_group_bytes(void); 73 | 74 | void cb_action_chips(void); 75 | void cb_action_chip_select(void); 76 | void cb_action_load_flm(void); 77 | 78 | void cb_action_connect(void); 79 | void cb_action_read_chip(void); 80 | void cb_action_erase_chip(void); 81 | void cb_action_check_blank(void); 82 | void cb_action_write(void); 83 | void cb_action_verify(void); 84 | void cb_action_reset_run(void); 85 | 86 | void cb_action_enum_device_list(void); 87 | void cb_tick_enum_device(void); 88 | void cb_action_manual_refresh_enum_devices(); 89 | void cb_action_auto_refresh_enum_devices(bool checked); 90 | 91 | void cb_erase_chip_finish(ProgramWorker::ChipOp op, bool ok); 92 | void cb_read_chip_finish(ProgramWorker::ChipOp op, bool ok); 93 | void cb_write_finish(ProgramWorker::ChipOp op, bool ok); 94 | void cb_verify_finish(ProgramWorker::ChipOp op, bool ok); 95 | 96 | void cb_read_chip_process(uint32_t val, uint32_t max); 97 | void cb_write_chip_process(uint32_t val, uint32_t max); 98 | void cb_verify_chip_process(uint32_t val, uint32_t max); 99 | 100 | void cb_usb_device_changed(); 101 | 102 | signals: 103 | void device_changed(DeviceList dev_list, bool changed); 104 | 105 | void program_worker_erase_chip(void); 106 | void program_worker_read_chip(QByteArray *data); 107 | void program_worker_write(uint32_t addr, QByteArray *data); 108 | void program_worker_verify(uint32_t addr, QByteArray *data); 109 | 110 | private: 111 | Ui::MainWindow *ui; 112 | QTimer *timer_enum_device; 113 | QTimer *device_change_delay_enum_timer; 114 | QElapsedTimer take_timer; 115 | Config *config; 116 | 117 | #if _WIN32 118 | WinHotplugNotify *win_hotplug_notify; 119 | #endif // _WIN32 120 | 121 | DeviceList dap_hid_device_list_prev; 122 | DeviceList dap_hid_device_list; 123 | 124 | DeviceList dap_v2_device_list_prev; 125 | DeviceList dap_v2_device_list; 126 | 127 | DeviceList device_list; 128 | 129 | QLabel *label_log_ending; 130 | 131 | int current_device_index; 132 | 133 | QByteArray firmware_buf; 134 | QByteArray read_back_buf; 135 | 136 | bool force_update_device_list; 137 | 138 | FlashAlgo flash_algo; 139 | uint32_t ram_start; 140 | 141 | // HexViewer *hex_viewer; 142 | QHexView *hexview; 143 | QHexDocument *hexview_doc; 144 | 145 | QHexView *file_hexview; 146 | QHexDocument *file_hexview_doc; 147 | 148 | ProgramWorker *program_worker; 149 | 150 | ChipSelecter *dialog_chip_selecter; 151 | enum_writer_list *dialog_enum_devices; 152 | 153 | // bool dap_hid_device_list_compare(QList *now_list, QList *prev_list); 154 | int32_t load_flash_algo(QString file_path); 155 | 156 | int device_connect(); 157 | }; 158 | #endif // MAINWINDOW_H 159 | -------------------------------------------------------------------------------- /src/program_worker.cpp: -------------------------------------------------------------------------------- 1 | #include "program_worker.h" 2 | 3 | ProgramWorker::ProgramWorker(Devices *device, FlashAlgo *algo) 4 | { 5 | this->dev = device; 6 | this->algo = algo; 7 | 8 | thread = new QThread(); 9 | thread->start(); 10 | 11 | // worker = new _ProgramWorker(dev, algo); 12 | // worker->moveToThread(thread); 13 | 14 | // connect(this, &ProgramWorker::_erase_chip, worker, &_ProgramWorker::erase_chip); 15 | // connect(worker, &_ProgramWorker::finished, this, &ProgramWorker::_finished); 16 | 17 | moveToThread(thread); 18 | } 19 | 20 | ProgramWorker::~ProgramWorker() 21 | { 22 | } 23 | 24 | void ProgramWorker::erase_chip(void) 25 | { 26 | int32_t err; 27 | program_syscall_t sys_call_s = algo->get_sys_call_s(); 28 | 29 | uint32_t entry = algo->get_flash_func_offset(FLASH_FUNC_EraseChip); 30 | if (entry == UINT32_MAX) 31 | { 32 | qDebug("[ProgramWorker] exec_flash_func unsuport func"); 33 | emit finished(ProgramWorker::EraseChip, false); 34 | return; 35 | } 36 | 37 | qDebug("[ProgramWorker] entry: 0x%08X", entry); 38 | 39 | err = dev->chip_syscall_exec(&sys_call_s, entry, 0, 0, 0, 0); 40 | if (err < 0) 41 | { 42 | qDebug("[ProgramWorker] exec_flash_func EraseChip fail"); 43 | emit finished(ProgramWorker::EraseChip, false); 44 | return; 45 | } 46 | 47 | emit finished(ProgramWorker::EraseChip, true); 48 | } 49 | 50 | void ProgramWorker::read_chip(QByteArray *data) 51 | { 52 | if (data == NULL) 53 | { 54 | qDebug("[ProgramWorker] read_chip fail data buf is nullptr"); 55 | emit finished(ProgramWorker::ReadChip, false); 56 | return; 57 | } 58 | 59 | int32_t err; 60 | FlashDevice flash_info = algo->get_flash_device_info(); 61 | uint32_t flash_size = flash_info.szDev; 62 | uint32_t flash_addr = flash_info.DevAdr; 63 | uint32_t page_size = flash_info.szPage; 64 | 65 | qDebug("[ProgramWorker] read_chip"); 66 | 67 | // flash_size = 256 + 128; 68 | 69 | data->clear(); 70 | data->fill(0x00, flash_size); 71 | 72 | err = read(flash_addr, flash_size, data); 73 | // err = dev->chip_read_memory(flash_addr, (uint8_t *)data->data(), flash_size); 74 | if (err < 0) 75 | { 76 | qDebug("[ProgramWorker] exec_flash_func ReadChip fail"); 77 | emit finished(ProgramWorker::ReadChip, false); 78 | return; 79 | } 80 | 81 | // data.fill(0x00, flash_size); 82 | // for (uint32_t i = 0; i < flash_size; i += page_size) 83 | // { 84 | // err = dev->dap_read_memory(flash_addr + i, (uint8_t *)(data.data()) + i, page_size); 85 | // if (err < 0) 86 | // { 87 | // qDebug("[ProgramWorker] exec_flash_func ReadChip fail"); 88 | // emit finished(ProgramWorker::ReadChip, false); 89 | // return; 90 | // } 91 | 92 | // emit process(i, flash_size); 93 | // } 94 | 95 | emit finished(ProgramWorker::ReadChip, true); 96 | } 97 | 98 | int32_t ProgramWorker::read(uint32_t addr, uint32_t size, QByteArray *data, uint32_t page_size) 99 | { 100 | int32_t err; 101 | uint32_t pr_size; 102 | 103 | data->clear(); 104 | data->fill(0x00, size); 105 | 106 | for (uint32_t i = 0; i < size; i += page_size) 107 | { 108 | 109 | if ((i + page_size) > size) 110 | { 111 | pr_size = size % page_size; 112 | } 113 | else 114 | { 115 | pr_size = page_size; 116 | } 117 | 118 | // err = dev->dap_read_memory(addr + i, (uint8_t *)(data->data()) + i, page_size); 119 | err = dev->chip_read_memory(addr + i, (uint8_t *)(data->data()) + i, pr_size); 120 | if (err < 0) 121 | { 122 | qDebug("[ProgramWorker] Read fail"); 123 | // emit finished(ProgramWorker::ReadChip, false); 124 | return -1; 125 | } 126 | 127 | emit process(i, size); 128 | } 129 | 130 | return 0; 131 | } 132 | 133 | void ProgramWorker::write(uint32_t addr, QByteArray *data) 134 | { 135 | int32_t err; 136 | program_syscall_t sys_call_s = algo->get_sys_call_s(); 137 | FlashDevice flash_info = algo->get_flash_device_info(); 138 | uint32_t flash_size = flash_info.szDev; 139 | uint32_t flash_addr = flash_info.DevAdr; 140 | // uint32_t page_size = flash_info.szPage; 141 | // uint32_t flash_size = 1024 * 16; 142 | uint32_t page_size = 512; 143 | uint32_t program_buff = algo->program_mem_buffer(); 144 | 145 | qDebug("[ProgramWorker] write page_size: %d", page_size); 146 | 147 | uint32_t entry = algo->get_flash_func_offset(FLASH_FUNC_ProgramPage); 148 | if (entry == UINT32_MAX) 149 | { 150 | qDebug("[ProgramWorker] exec_flash_func unsuport func"); 151 | emit finished(ProgramWorker::Program, false); 152 | return; 153 | } 154 | 155 | // uint32_t fw_size = data->length(); 156 | uint32_t fw_size = (flash_size > data->length()) ? data->length() : flash_size; 157 | uint32_t pw_size; 158 | 159 | for (uint32_t i = 0; i < fw_size; i += page_size) 160 | { 161 | if ((i + page_size) > fw_size) 162 | { 163 | pw_size = fw_size % page_size; 164 | } 165 | else 166 | { 167 | pw_size = page_size; 168 | } 169 | 170 | qDebug("[ProgramWorker] exec_flash_func ProgramPage page %d %d", i, pw_size); 171 | 172 | err = dev->chip_write_memory(program_buff, (uint8_t *)(data->data()) + i, pw_size); 173 | if (err < 0) 174 | { 175 | qDebug("[ProgramWorker] exec_flash_func ReadChip fail"); 176 | emit finished(ProgramWorker::Program, false); 177 | return; 178 | } 179 | 180 | err = dev->chip_syscall_exec(&sys_call_s, entry, addr + i, pw_size, program_buff, 0); 181 | if (err < 0) 182 | { 183 | qDebug("[ProgramWorker] exec_flash_func ProgramPage fail"); 184 | emit finished(ProgramWorker::Program, false); 185 | return; 186 | } 187 | 188 | emit process(i, fw_size); 189 | } 190 | 191 | emit finished(ProgramWorker::Program, true); 192 | } 193 | 194 | void ProgramWorker::verify(uint32_t addr, QByteArray *data) 195 | { 196 | int32_t err; 197 | uint32_t pr_size; 198 | uint32_t page_size = 1024; 199 | QByteArray tmp_buf; 200 | 201 | tmp_buf.fill(0x00, page_size); 202 | 203 | for (uint32_t i = 0; i < data->length(); i += page_size) 204 | { 205 | if ((i + page_size) > data->length()) 206 | { 207 | pr_size = data->length() % page_size; 208 | } 209 | else 210 | { 211 | pr_size = page_size; 212 | } 213 | 214 | err = dev->chip_read_memory(addr + i, (uint8_t *)(tmp_buf.data()), pr_size); 215 | if (err < 0) 216 | { 217 | qDebug("[ProgramWorker] Read fail"); 218 | emit finished(ProgramWorker::Verify, false); 219 | return; 220 | } 221 | 222 | if (memcmp(tmp_buf.data(), data->data() + i, pr_size) != 0) 223 | { 224 | qDebug("[ProgramWorker] Verify fail addr:%d", i); 225 | emit finished(ProgramWorker::Verify, false); 226 | return; 227 | } 228 | 229 | emit process(i, data->length()); 230 | } 231 | 232 | qDebug("[ProgramWorker] Verify ok"); 233 | emit finished(ProgramWorker::Verify, true); 234 | } 235 | -------------------------------------------------------------------------------- /src/program_worker.h: -------------------------------------------------------------------------------- 1 | #ifndef PROGRAM_WORKER_H 2 | #define PROGRAM_WORKER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "devices.h" 8 | #include "flash_algo.h" 9 | #include "utils.h" 10 | 11 | class _ProgramWorker; 12 | 13 | /******************************************************************************* 14 | * 封装一层 15 | ******************************************************************************/ 16 | class ProgramWorker : public QObject 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | ProgramWorker(Devices *device, FlashAlgo *algo); 22 | ~ProgramWorker(); 23 | 24 | typedef enum 25 | { 26 | EraseChip, 27 | ReadChip, 28 | EraseBlock, 29 | Program, 30 | Verify, 31 | } ChipOp; 32 | 33 | private: 34 | Devices *dev; 35 | FlashAlgo *algo; 36 | QThread *thread; 37 | 38 | signals: 39 | void finished(ProgramWorker::ChipOp op, bool ok); 40 | void process(uint32_t val, uint32_t max); 41 | 42 | public slots: 43 | void erase_chip(void); 44 | int32_t read(uint32_t addr, uint32_t size, QByteArray *data, uint32_t page_size = 1024); 45 | void read_chip(QByteArray *data); 46 | void write(uint32_t addr, QByteArray *data); 47 | void verify(uint32_t addr, QByteArray *data); 48 | }; 49 | 50 | #endif // PROGRAM_WORK_H 51 | -------------------------------------------------------------------------------- /src/ui_components/chip_selecter.h: -------------------------------------------------------------------------------- 1 | #ifndef CHIP_SELECTER_H 2 | #define CHIP_SELECTER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace Ui 10 | { 11 | class ChipSelecter; 12 | } 13 | 14 | class ChipInfo 15 | { 16 | public: 17 | ChipInfo() 18 | { 19 | } 20 | ~ChipInfo() 21 | { 22 | } 23 | int from_node(YAML::Node node); 24 | 25 | QString name; 26 | QString log_text; 27 | QString core; 28 | QString algo; 29 | QString ram_size_str; 30 | QString flash_size_str; 31 | 32 | private: 33 | }; 34 | 35 | class Series 36 | { 37 | public: 38 | Series() 39 | { 40 | } 41 | 42 | ~Series() 43 | { 44 | } 45 | 46 | int from_node(YAML::Node node); 47 | inline int chip_count() const { return chip_info_list.count(); } 48 | 49 | QList chips_name_list() const 50 | { 51 | QList ret; 52 | for (int i = 0; i < chip_info_list.count(); i++) 53 | { 54 | if (chip_info_list[i]) 55 | ret.push_back(QString("%1 | %2").arg(i).arg(chip_info_list[i]->name)); 56 | else 57 | ret.push_back(QString("%1 | %2 ").arg(i).arg("NULL")); 58 | } 59 | 60 | return ret; 61 | } 62 | 63 | QString name; 64 | QString homepage; 65 | QString log_text; 66 | QList chip_info_list; 67 | QString core; 68 | QString algo; 69 | QString ram_size_str; 70 | QString flash_size_str; 71 | 72 | private: 73 | }; 74 | 75 | class Vendor 76 | { 77 | public: 78 | Vendor() 79 | { 80 | } 81 | 82 | ~Vendor() 83 | { 84 | } 85 | 86 | int from_node(YAML::Node node); 87 | int from_vendor_file(QString vendor_file_path); 88 | 89 | inline int series_count() const { return series_list.count(); } 90 | QList series_name_list() const 91 | { 92 | QList ret; 93 | for (int i = 0; i < series_list.count(); i++) 94 | { 95 | if (series_list[i]->chip_count()) 96 | ret.push_back(QString("%1 | %2").arg(i).arg(series_list[i]->name)); 97 | else 98 | ret.push_back(QString("%1 | [❌无效] %2 ").arg(i).arg(series_list[i]->name)); 99 | } 100 | 101 | return ret; 102 | } 103 | 104 | // static int from_node(Vendor *vendor, YAML::Node node); 105 | // static int from_vendor_file(Vendor *vendor, QString vendor_file_path); 106 | 107 | QString name; 108 | QString log_text; 109 | QString homepage; 110 | QList series_list; 111 | 112 | private: 113 | }; 114 | 115 | class ChipSelecter : public QDialog 116 | { 117 | Q_OBJECT 118 | 119 | public: 120 | explicit ChipSelecter(QWidget *parent = nullptr); 121 | ~ChipSelecter(); 122 | int load_chips(QString chips_dir_path = ""); 123 | int load_chip_vendor(QString vendor_file_path, Vendor *vendor); 124 | 125 | int error() { return _load_chip_err; } 126 | 127 | void log_clear(); 128 | void log_output(); 129 | void switch_vendor(uint32_t index); 130 | void switch_series(uint32_t index); 131 | void switch_chip(uint32_t index); 132 | 133 | bool switch_vendor(QString vendor_name); 134 | bool switch_series(QString series_name); 135 | bool switch_chip(QString chip_name); 136 | bool switch_chip(QString vendor_name, QString series_name, QString chip_name); 137 | 138 | QString vendor_name(); 139 | QString vendor_homepage(); 140 | QString series_name(); 141 | QString series_homepage(); 142 | QString chip_name(); 143 | 144 | QString core_homepage(QString core); 145 | 146 | Vendor *current_vendor() 147 | { 148 | return vendor_list[current_vendor_index]; 149 | } 150 | 151 | Series *current_series() 152 | { 153 | return current_vendor()->series_list[current_series_index]; 154 | } 155 | 156 | ChipInfo *current_chip_info() 157 | { 158 | return current_series()->chip_info_list[current_chip_index]; 159 | } 160 | 161 | bool is_chip_info_available() 162 | { 163 | if (current_series()->chip_info_list.count() == 0) 164 | return false; 165 | 166 | if (current_chip_info() == NULL) 167 | return false; 168 | 169 | return true; 170 | } 171 | 172 | QString chip_core() 173 | { 174 | QString ret = current_series()->core; 175 | 176 | if (is_chip_info_available() == false) 177 | return ret; 178 | 179 | if (current_chip_info()->core.isEmpty()) 180 | return ret; 181 | 182 | return current_chip_info()->core; 183 | } 184 | 185 | QString chip_algo() 186 | { 187 | QString ret = current_series()->algo; 188 | 189 | if (is_chip_info_available() == false) 190 | return ret; 191 | 192 | if (current_chip_info()->algo.isEmpty()) 193 | return ret; 194 | 195 | return current_chip_info()->algo; 196 | } 197 | 198 | QString chip_ram_size() 199 | { 200 | QString ret = current_series()->ram_size_str; 201 | 202 | if (is_chip_info_available() == false) 203 | return ret; 204 | 205 | if (current_chip_info()->ram_size_str.isEmpty()) 206 | return ret; 207 | 208 | return current_chip_info()->ram_size_str; 209 | } 210 | 211 | QString chip_flash_size() 212 | { 213 | QString ret = current_series()->flash_size_str; 214 | 215 | if (is_chip_info_available() == false) 216 | return ret; 217 | 218 | if (current_chip_info()->flash_size_str.isEmpty()) 219 | return ret; 220 | 221 | return current_chip_info()->flash_size_str; 222 | } 223 | 224 | void set_dd_vendor_connect(); 225 | void set_dd_vendor_disconnect(); 226 | void set_dd_series_connect(); 227 | void set_dd_series_disconnect(); 228 | void set_dd_chip_connect(); 229 | void set_dd_chip_disconnect(); 230 | 231 | ChipInfo chip_info(); 232 | 233 | public slots: 234 | void cb_combobox_vendor(int index); 235 | void cb_combobox_series(int index); 236 | void cb_combobox_chip(int index); 237 | 238 | void cb_btn_ok(); 239 | 240 | private: 241 | Ui::ChipSelecter *ui; 242 | 243 | // QList> series_name_list; 244 | // QList>> chip_name_list; 245 | QList vendor_list; 246 | int current_vendor_index; 247 | int current_series_index; 248 | int current_chip_index; 249 | 250 | int _load_chip_err; 251 | 252 | QString log_vendor; 253 | QString log_series; 254 | QString log_chip; 255 | 256 | QStringList error_info; 257 | 258 | QMetaObject::Connection conn_dd_vendor; 259 | QMetaObject::Connection conn_dd_series; 260 | QMetaObject::Connection conn_dd_chip; 261 | 262 | QMap chip_core_homepage_map; 263 | }; 264 | 265 | #endif // CHIP_SELECTER_H 266 | -------------------------------------------------------------------------------- /src/ui_components/chip_selecter.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ChipSelecter 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 500 11 | 12 | 13 | 14 | 芯片型号选择 15 | 16 | 17 | 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 25 | 0 26 | 0 27 | 780 28 | 391 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 思源黑体 CN Bold 37 | 12 38 | 39 | 40 | 41 | TextLabel 42 | 43 | 44 | Qt::TextFormat::MarkdownText 45 | 46 | 47 | true 48 | 49 | 50 | Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse 51 | 52 | 53 | 54 | 55 | 56 | 57 | Qt::Orientation::Vertical 58 | 59 | 60 | 61 | 20 62 | 40 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 厂商 80 | 81 | 82 | 83 | 84 | 85 | 86 | 系列/家族 87 | 88 | 89 | 90 | 91 | 92 | 93 | false 94 | 95 | 96 | 97 | 98 | 99 | 100 | 型号 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 5 113 | 114 | 115 | 5 116 | 117 | 118 | 119 | 120 | Qt::Orientation::Horizontal 121 | 122 | 123 | 124 | 40 125 | 20 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 思源黑体 CN Bold 135 | 12 136 | 137 | 138 | 139 | color: rgb(255, 0,0); 140 | 141 | 142 | TextLabel 143 | 144 | 145 | Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse 146 | 147 | 148 | 149 | 150 | 151 | 152 | 确定 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /src/ui_components/hex_viewer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "hex_viewer.h" 4 | #include "ui_hex_viewer.h" 5 | #include "utils.h" 6 | 7 | bool is_visible_char(char a) 8 | { 9 | // if ((a >= '0') && (a <= '9')) 10 | // return true; 11 | // else if ((a >= 'a') && (a <= 'z')) 12 | // return true; 13 | // else if ((a >= 'A') && (a <= 'Z')) 14 | // return true; 15 | 16 | if ((a >= 0x20) && (a <= 0x7E)) 17 | return true; 18 | 19 | return false; 20 | } 21 | 22 | HexViewer::HexViewer(QWidget *parent) : QWidget(parent), 23 | ui(new Ui::hex_viewer) 24 | { 25 | ui->setupUi(this); 26 | 27 | parent_layout = (QGridLayout *)(ui->scrollAreaWidgetContents->layout()); 28 | 29 | // thread_loader = new QThread(); 30 | // loader = new HexViewerLoader(parent_layout); 31 | // connect(this, &HexViewer::loader_load, loader, &HexViewerLoader::load); 32 | // connect(loader, &HexViewerLoader::finished, this, &HexViewer::loader_finished); 33 | // loader->moveToThread(thread_loader); 34 | // thread_loader->start(); 35 | 36 | add_title(); 37 | // clear_layout(); 38 | 39 | QByteArray init_data; 40 | init_data.fill(0x00, 42); 41 | // init_data.fill(0x00, 1024); 42 | 43 | QRandomGenerator *generator = QRandomGenerator::global(); 44 | 45 | for (uint32_t i = 0; i < init_data.length(); i++) 46 | { 47 | init_data[i] = static_cast(QRandomGenerator::global()->bounded(256)); 48 | } 49 | 50 | load(init_data); 51 | } 52 | 53 | HexViewer::~HexViewer() 54 | { 55 | delete ui; 56 | } 57 | 58 | void HexViewer::clear_layout(void) 59 | { 60 | uint32_t remove_count = 0; 61 | QLayoutItem *tmp_item; 62 | 63 | while ((tmp_item = parent_layout->takeAt(0)) != NULL) 64 | { 65 | if (tmp_item->widget() != NULL) 66 | delete tmp_item->widget(); 67 | 68 | delete tmp_item; 69 | 70 | remove_count++; 71 | } 72 | 73 | // ui->scrollAreaWidgetContents->resize(0,0); 74 | 75 | qDebug("[HexViewer] clear_layout remove_count: %d", remove_count); 76 | } 77 | 78 | void HexViewer::add_title(void) 79 | { 80 | uint32_t line_i = 0; 81 | QFont newFont_title("Courier New", 10, QFont::Bold, false); 82 | QLabel *tmp_label; 83 | 84 | tmp_label = new QLabel(); 85 | tmp_label->setTextFormat(Qt::PlainText); 86 | tmp_label->setFont(newFont_title); 87 | tmp_label->setText(QString("Offset(h)")); 88 | tmp_label->setStyleSheet("QLabel{ color: blue;}"); 89 | ui->gridLayout_title->addWidget(tmp_label, 0, 0); 90 | 91 | for (line_i = 0; line_i < 0x10; line_i++) 92 | { 93 | 94 | tmp_label = new QLabel(); 95 | tmp_label->setTextFormat(Qt::PlainText); 96 | tmp_label->setFont(newFont_title); 97 | tmp_label->setText(QString(" ")); 98 | tmp_label->setStyleSheet("QLabel{ color: blue;}"); 99 | ui->gridLayout_title->addWidget(tmp_label, 0, 1UL + line_i * 2); 100 | 101 | tmp_label = new QLabel(); 102 | tmp_label->setTextFormat(Qt::PlainText); 103 | tmp_label->setFont(newFont_title); 104 | tmp_label->setText(QString("%1").arg(line_i, 2, 16, QChar('0')).toUpper()); 105 | tmp_label->setStyleSheet("QLabel{ color: blue;}"); 106 | ui->gridLayout_title->addWidget(tmp_label, 0, 1UL + line_i * 2 + 1); 107 | } 108 | 109 | tmp_label = new QLabel(); 110 | tmp_label->setTextFormat(Qt::PlainText); 111 | tmp_label->setFont(newFont_title); 112 | tmp_label->setText(QString(" ")); 113 | tmp_label->setStyleSheet("QLabel{ color: blue;}"); 114 | ui->gridLayout_title->addWidget(tmp_label, 0, 1UL + line_i * 2); 115 | 116 | tmp_label = new QLabel(); 117 | tmp_label->setTextFormat(Qt::PlainText); 118 | tmp_label->setFont(newFont_title); 119 | tmp_label->setText(QString("对应文本")); 120 | tmp_label->setStyleSheet("QLabel{ color: blue;}"); 121 | ui->gridLayout_title->addWidget(tmp_label, 0, 1ULL + 0x10 * 2 + 1); 122 | ui->gridLayout_title->setColumnStretch(1ULL + 0x10 * 2 + 1, 1); 123 | } 124 | 125 | // void HexViewer::load(uint8_t *data, uint32_t size) 126 | // { 127 | // delete ui->scrollAreaWidgetContents->layout(); 128 | 129 | // emit loader_load(data, size); 130 | // } 131 | 132 | void HexViewer::loader_finished(QGridLayout *parent_layout) 133 | { 134 | qDebug("[HexViewer] loader_finished"); 135 | 136 | ui->scrollAreaWidgetContents->setLayout(parent_layout); 137 | } 138 | 139 | void HexViewer::load(uint8_t *data, uint32_t size) 140 | { 141 | uint32_t i = 0; 142 | uint32_t line_i = 0; 143 | QLabel *tmp_label; 144 | 145 | qDebug("[HexViewer] load: %d", size); 146 | hexdump(data, size); 147 | 148 | clear_layout(); 149 | if (size == 0) 150 | return; 151 | 152 | uint32_t line_count = size / 0x10; 153 | if (size % 0x10) 154 | line_count++; 155 | 156 | qDebug("[HexViewer] rowCount:%d", parent_layout->rowCount()); 157 | QFont newFont("Courier New", 10, QFont::Normal, false); 158 | QFont newFont_title("Courier New", 10, QFont::Bold, false); 159 | 160 | for (i = 0; i < size; i += 0x10) 161 | { 162 | uint32_t rowIndex = i / 0x10; 163 | 164 | QLabel *tmp_addr_label = new QLabel(); 165 | tmp_addr_label->setTextFormat(Qt::PlainText); 166 | tmp_addr_label->setFont(newFont_title); 167 | tmp_addr_label->setText(QString("%1_%2").arg(i >> 16, 4, 16, QChar('0')).arg(i & 0xFFFF, 4, 16, QChar('0')).toUpper()); 168 | tmp_addr_label->setStyleSheet("QLabel{ color: blue;}"); 169 | parent_layout->addWidget(tmp_addr_label, rowIndex, 0); 170 | 171 | for (line_i = 0; line_i < 0x10; line_i++) 172 | { 173 | 174 | tmp_label = new QLabel(); 175 | tmp_label->setTextFormat(Qt::PlainText); 176 | tmp_label->setFont(newFont); 177 | tmp_label->setText(QString(" ")); 178 | parent_layout->addWidget(tmp_label, rowIndex, 1UL + line_i * 2); 179 | 180 | QLabel *tmp_byte_label = new QLabel(); 181 | tmp_byte_label->setTextFormat(Qt::PlainText); 182 | tmp_byte_label->setFont(newFont); 183 | // tmp_byte_label->setAlignment(Qt::AlignCenter); 184 | // tmp_byte_label->setMouseTracking(true); 185 | 186 | parent_layout->addWidget(tmp_byte_label, rowIndex, 1UL + line_i * 2 + 1); 187 | 188 | if (line_i % 2) 189 | { 190 | // tmp_byte_label->setPa 191 | QPalette tmp_palette = tmp_byte_label->palette(); 192 | tmp_palette.setColor(QPalette::WindowText, QColor(128, 96, 96)); 193 | tmp_byte_label->setPalette(tmp_palette); 194 | } 195 | 196 | if ((i + line_i) >= size) 197 | { 198 | tmp_byte_label->setText(" "); 199 | } 200 | else 201 | { 202 | tmp_byte_label->setText(QString("%1").arg(data[i + line_i] & 0xFF, 2, 16, QChar('0')).toUpper()); 203 | } 204 | 205 | // tmp_byte_label->setText(QString(" %1").arg(*(data + i + line_i) & 0xFF, 2, 16, QChar('0')).toUpper()); 206 | // tmp_ascii_label->setText(QString(".")); 207 | // res.append(QString(" %1").arg(*(data + i + line_i) & 0xFF, 2, 16, QChar('0')).toUpper()); 208 | } 209 | 210 | tmp_label = new QLabel(); 211 | tmp_label->setTextFormat(Qt::PlainText); 212 | tmp_label->setFont(newFont); 213 | tmp_label->setText(QString(" ")); 214 | parent_layout->addWidget(tmp_label, rowIndex, 1UL + 0x10 * 2); 215 | 216 | uint8_t lineIndexBase = 1UL + 0x10 * 2 + 1; 217 | 218 | for (line_i = 0; line_i < 0x10; line_i++) 219 | { 220 | QLabel *tmp_ascii_label = new QLabel(); 221 | tmp_ascii_label->setTextFormat(Qt::PlainText); 222 | tmp_ascii_label->setFont(newFont); 223 | tmp_ascii_label->setAlignment(Qt::AlignCenter); 224 | 225 | if (is_visible_char(data[i + line_i])) 226 | tmp_ascii_label->setText(QChar(data[i + line_i])); 227 | else 228 | tmp_ascii_label->setText(QString(".")); 229 | 230 | parent_layout->addWidget(tmp_ascii_label, rowIndex, lineIndexBase + line_i); 231 | } 232 | 233 | tmp_label = new QLabel(); 234 | tmp_label->setTextFormat(Qt::PlainText); 235 | tmp_label->setFont(newFont); 236 | tmp_label->setText(QString(" ")); 237 | tmp_label->setStyleSheet("QLabel{ color: blue;}"); 238 | parent_layout->addWidget(tmp_label, rowIndex, 1UL + 0x10 * 3 + 1); 239 | parent_layout->setColumnStretch(1ULL + 0x10 * 3 + 1, 1); 240 | 241 | parent_layout->setRowStretch(rowIndex, 0); 242 | } 243 | 244 | tmp_label = new QLabel(); 245 | tmp_label->setTextFormat(Qt::PlainText); 246 | tmp_label->setFont(newFont); 247 | tmp_label->setText(QString("--- 到底啦 --- ")); 248 | tmp_label->setAlignment(Qt::AlignTop | Qt::AlignHCenter); 249 | tmp_label->setStyleSheet("QLabel{ color: blue;}"); 250 | parent_layout->addWidget(tmp_label, line_count, 0, 1, 1 + 0x10 * 3 + 1); 251 | parent_layout->setRowStretch(line_count, 1); 252 | 253 | // uint32_t title_width = ui->gridLayout_title->itemAtPosition(0, 0)->widget()->width(); 254 | // uint32_t data_width = parent_layout->itemAtPosition(0, 0)->widget()->width(); 255 | 256 | // qDebug("[HexViewer] load title_width:%d data_width:%d", title_width, data_width); 257 | 258 | // if (title_width > data_width) 259 | // { 260 | // parent_layout->setColumnMinimumWidth(0, title_width); 261 | // } 262 | // else 263 | // { 264 | // ui->gridLayout_title->setColumnMinimumWidth(0, data_width); 265 | // } 266 | } 267 | 268 | HexViewerLoader::HexViewerLoader(QGridLayout *parent_layout) 269 | { 270 | this->parent_layout = parent_layout; 271 | } 272 | 273 | HexViewerLoader::~HexViewerLoader() 274 | { 275 | } 276 | 277 | void HexViewerLoader::clear_layout(void) 278 | { 279 | uint32_t remove_count = 0; 280 | QLayoutItem *tmp_item; 281 | 282 | while ((tmp_item = parent_layout->takeAt(0)) != NULL) 283 | { 284 | if (tmp_item->widget() != NULL) 285 | delete tmp_item->widget(); 286 | 287 | delete tmp_item; 288 | 289 | remove_count++; 290 | } 291 | 292 | // ui->scrollAreaWidgetContents->resize(0,0); 293 | 294 | qDebug("[HexViewerLoader] clear_layout remove_count: %d", remove_count); 295 | } 296 | 297 | void HexViewerLoader::load(uint8_t *data, uint32_t len) 298 | { 299 | uint32_t i = 0; 300 | uint32_t line_i = 0; 301 | QLabel *tmp_label; 302 | 303 | QGridLayout *parent_layout = new QGridLayout(); 304 | 305 | qDebug("[HexViewerLoader] load: %d", len); 306 | // hexdump((uint8_t *)data, len); 307 | 308 | clear_layout(); 309 | if (len == 0) 310 | return; 311 | 312 | uint32_t line_count = len / 0x10; 313 | if (len % 0x10) 314 | line_count++; 315 | 316 | qDebug("[HexViewerLoader] rowCount:%d", parent_layout->rowCount()); 317 | QFont newFont("Courier New", 10, QFont::Normal, false); 318 | 319 | for (i = 0; i < len; i += 0x10) 320 | { 321 | uint32_t rowIndex = i / 0x10; 322 | 323 | QLabel *tmp_addr_label = new QLabel(); 324 | tmp_addr_label->setTextFormat(Qt::PlainText); 325 | tmp_addr_label->setFont(newFont); 326 | tmp_addr_label->setText(QString("%1_%2").arg(i >> 16, 4, 16, QChar('0')).arg(i & 0xFFFF, 4, 16, QChar('0')).toUpper()); 327 | tmp_addr_label->setStyleSheet("QLabel{ color: blue;}"); 328 | parent_layout->addWidget(tmp_addr_label, rowIndex, 0); 329 | 330 | for (line_i = 0; line_i < 0x10; line_i++) 331 | { 332 | 333 | tmp_label = new QLabel(); 334 | tmp_label->setTextFormat(Qt::PlainText); 335 | tmp_label->setFont(newFont); 336 | tmp_label->setText(QString(" ")); 337 | parent_layout->addWidget(tmp_label, rowIndex, 1UL + line_i * 2); 338 | 339 | QLabel *tmp_byte_label = new QLabel(); 340 | tmp_byte_label->setTextFormat(Qt::PlainText); 341 | tmp_byte_label->setFont(newFont); 342 | // tmp_byte_label->setAlignment(Qt::AlignCenter); 343 | // tmp_byte_label->setMouseTracking(true); 344 | 345 | parent_layout->addWidget(tmp_byte_label, rowIndex, 1UL + line_i * 2 + 1); 346 | 347 | if (line_i % 2) 348 | { 349 | // tmp_byte_label->setPa 350 | QPalette tmp_palette = tmp_byte_label->palette(); 351 | tmp_palette.setColor(QPalette::WindowText, QColor(128, 96, 96)); 352 | tmp_byte_label->setPalette(tmp_palette); 353 | } 354 | 355 | if ((i + line_i) >= len) 356 | { 357 | tmp_byte_label->setText(" "); 358 | } 359 | else 360 | { 361 | tmp_byte_label->setText(QString("%1").arg(data[i + line_i] & 0xFF, 2, 16, QChar('0')).toUpper()); 362 | } 363 | 364 | // tmp_byte_label->setText(QString(" %1").arg(*(data + i + line_i) & 0xFF, 2, 16, QChar('0')).toUpper()); 365 | // tmp_ascii_label->setText(QString(".")); 366 | // res.append(QString(" %1").arg(*(data + i + line_i) & 0xFF, 2, 16, QChar('0')).toUpper()); 367 | } 368 | 369 | tmp_label = new QLabel(); 370 | tmp_label->setTextFormat(Qt::PlainText); 371 | tmp_label->setFont(newFont); 372 | tmp_label->setText(QString(" ")); 373 | parent_layout->addWidget(tmp_label, rowIndex, 1UL + 0x10 * 2); 374 | 375 | uint8_t lineIndexBase = 1UL + 0x10 * 2 + 1; 376 | 377 | for (line_i = 0; line_i < 0x10; line_i++) 378 | { 379 | QLabel *tmp_ascii_label = new QLabel(); 380 | tmp_ascii_label->setTextFormat(Qt::PlainText); 381 | tmp_ascii_label->setFont(newFont); 382 | tmp_ascii_label->setAlignment(Qt::AlignCenter); 383 | 384 | if (is_visible_char(data[i + line_i])) 385 | tmp_ascii_label->setText(QString("%1").arg(data[i + line_i])); 386 | else 387 | tmp_ascii_label->setText(QString(".")); 388 | 389 | parent_layout->addWidget(tmp_ascii_label, rowIndex, lineIndexBase + line_i); 390 | } 391 | 392 | tmp_label = new QLabel(); 393 | tmp_label->setTextFormat(Qt::PlainText); 394 | tmp_label->setFont(newFont); 395 | tmp_label->setText(QString(" ")); 396 | tmp_label->setStyleSheet("QLabel{ color: blue;}"); 397 | parent_layout->addWidget(tmp_label, rowIndex, 1UL + 0x10 * 3 + 1); 398 | parent_layout->setColumnStretch(1ULL + 0x10 * 3 + 1, 1); 399 | 400 | parent_layout->setRowStretch(rowIndex, 0); 401 | } 402 | 403 | tmp_label = new QLabel(); 404 | tmp_label->setTextFormat(Qt::PlainText); 405 | tmp_label->setFont(newFont); 406 | tmp_label->setText(QString("--- 到底啦 --- ")); 407 | tmp_label->setAlignment(Qt::AlignTop | Qt::AlignHCenter); 408 | tmp_label->setStyleSheet("QLabel{ color: blue;}"); 409 | parent_layout->addWidget(tmp_label, line_count, 0, 1, 1 + 0x10 * 3 + 1); 410 | parent_layout->setRowStretch(line_count, 1); 411 | 412 | emit finished(parent_layout); 413 | } 414 | -------------------------------------------------------------------------------- /src/ui_components/hex_viewer.h: -------------------------------------------------------------------------------- 1 | #ifndef HEX_VIEWER_H 2 | #define HEX_VIEWER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace Ui 10 | { 11 | class hex_viewer; 12 | } 13 | 14 | class HexViewerLoader : public QObject 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | HexViewerLoader(QGridLayout *parent_layout); 20 | ~HexViewerLoader(); 21 | 22 | public slots: 23 | void load(uint8_t *data, uint32_t len); 24 | 25 | signals: 26 | void update_progress(uint32_t progress); 27 | void finished(QGridLayout *parent_layout); 28 | 29 | private: 30 | QGridLayout *parent_layout; 31 | 32 | void clear_layout(void); 33 | }; 34 | 35 | class HexViewer : public QWidget 36 | { 37 | Q_OBJECT 38 | 39 | public: 40 | explicit HexViewer(QWidget *parent = nullptr); 41 | ~HexViewer(); 42 | 43 | void load(uint8_t *data, uint32_t size); 44 | void load(QByteArray data) { load((uint8_t *)(data.data()), data.size()); } 45 | void load(void) { load(NULL, 0); } 46 | 47 | public slots: 48 | void loader_finished(QGridLayout *parent_layout); 49 | 50 | signals: 51 | void loader_load(uint8_t *data, uint32_t len); 52 | 53 | private: 54 | Ui::hex_viewer *ui; 55 | QGridLayout *parent_layout; 56 | QThread *thread_loader; 57 | HexViewerLoader *loader; 58 | 59 | void clear_layout(void); 60 | void add_title(void); 61 | }; 62 | 63 | #endif // HEX_VIEWER_H 64 | -------------------------------------------------------------------------------- /src/ui_components/hex_viewer.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | hex_viewer 4 | 5 | 6 | 7 | 0 8 | 0 9 | 725 10 | 462 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | #QLabel{background-color: yellow;} 18 | 19 | 20 | 21 | 0 22 | 23 | 24 | 0 25 | 26 | 27 | 0 28 | 29 | 30 | 0 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | Source Code Pro 40 | false 41 | 42 | 43 | 44 | Qt::ScrollBarAlwaysOn 45 | 46 | 47 | Qt::ScrollBarAsNeeded 48 | 49 | 50 | true 51 | 52 | 53 | 54 | 55 | 0 56 | 0 57 | 702 58 | 447 59 | 60 | 61 | 62 | #QLabel{background-color: yellow;} 63 | 64 | 65 | 66 | 0 67 | 68 | 69 | 0 70 | 71 | 72 | 0 73 | 74 | 75 | 0 76 | 77 | 78 | 0 79 | 80 | 81 | 5 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | void dump_flash_code(const uint32_t *buf, uint32_t len) 4 | { 5 | uint8_t i; 6 | 7 | QString res(""); 8 | 9 | for (i = 0; i < len; i++) 10 | { 11 | 12 | res.append(QString("0x%1, ").arg(*(buf + i), 8, 16)); 13 | 14 | if (((i + 1) % 8) == 0) 15 | { 16 | res.append("\r\n"); 17 | } 18 | } 19 | 20 | qDebug("%s", qPrintable(res)); 21 | } 22 | 23 | void hexdump(const uint8_t *buf, uint32_t len) 24 | { 25 | uint32_t i = 0; 26 | uint32_t line_i = 0; 27 | 28 | QString res(""); 29 | 30 | res.append("[hexdump] ====================================================\r\n"); 31 | res.append("[hexdump] 0 1 2 3 4 5 6 7 8 9 A B C D E F\r\n"); 32 | 33 | for (i = 0; i < len; i += 0x10) 34 | { 35 | res.append(QString("[hexdump]")); 36 | res.append(QString(" %1").arg((int)(i / 16 * 16), 4, 16, QChar('0')).toUpper()); 37 | 38 | for (line_i = 0; line_i < 0x10; line_i++) 39 | { 40 | if ((i + line_i) >= len) 41 | { 42 | res.append(" "); 43 | continue; 44 | } 45 | 46 | res.append(QString(" %1").arg(*(buf + i + line_i), 2, 16, QChar('0')).toUpper()); 47 | } 48 | 49 | res.append("\r\n"); 50 | } 51 | 52 | res.append("[hexdump] ====================================================\r\n"); 53 | 54 | qDebug("%s", qPrintable(res)); 55 | } 56 | 57 | QString convert_bytes_speed_unit(uint64_t bytes) 58 | { 59 | if (bytes < 1024) 60 | { 61 | return QString("%1 B/s").arg(bytes); 62 | } 63 | 64 | if (bytes < 1024 * 1024) 65 | { 66 | return QString("%1 KB/s").arg((float)bytes / 1024, 0, 'f', 2); 67 | } 68 | 69 | if (bytes < 1024 * 1024) 70 | { 71 | return QString("%1 KB/s").arg((float)bytes / 1024, 0, 'f', 2); 72 | } 73 | 74 | if (bytes < 1024 * 1024 * 1024) 75 | { 76 | return QString("%1 MB/s").arg((float)bytes / 1024 / 1024, 0, 'f', 2); 77 | } 78 | 79 | return QString("%1 GB/s").arg((float)bytes / 1024 / 1024 / 1024, 0, 'f', 2); 80 | } -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #include "stdint.h" 5 | #include 6 | 7 | void hexdump(const uint8_t *buf, uint32_t len); 8 | void dump_flash_code(const uint32_t *buf, uint32_t len); 9 | 10 | QString convert_bytes_speed_unit(uint64_t bytes); 11 | 12 | #endif // UTILS_H 13 | -------------------------------------------------------------------------------- /src/views/chips_config_dialog/chips_config_dialog.cpp: -------------------------------------------------------------------------------- 1 | #include "chips_config_dialog.h" 2 | #include "ui_chips_config_dialog.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static const QString default_chips_url = "https://github.com/ma6254/qdap_chips/archive/refs/heads/main.zip"; 10 | static const QString tmp_chips_compress_file = ".tmp/qdap_chips-main.zip"; 11 | static const QString tmp_chips_directory = ".tmp/chips"; 12 | static const QString chips_directory = "chips"; 13 | 14 | /******************************************************************************* 15 | * @brief 器件库配置对话窗口,构造函数 16 | * @param parent 父组件 17 | * @return None 18 | ******************************************************************************/ 19 | ChipsConfigDialog::ChipsConfigDialog(QWidget *parent) 20 | : QDialog(parent), ui(new Ui::chips_config_dialog) 21 | { 22 | ui->setupUi(this); 23 | 24 | reply = NULL; 25 | 26 | qDebug("[SSL] supports: %d", QSslSocket::supportsSsl()); 27 | qDebug("[SSL] sslLibraryBuildVersion: %s", qPrintable(QSslSocket::sslLibraryBuildVersionString())); 28 | qDebug("[SSL] sslLibraryVersion: %s", qPrintable(QSslSocket::sslLibraryVersionString())); 29 | 30 | connect(ui->btn_ok, SIGNAL(clicked()), this, SLOT(cb_btn_ok())); 31 | connect(ui->btn_refresh, SIGNAL(clicked()), this, SLOT(cb_btn_refresh())); 32 | connect(ui->btn_abort, SIGNAL(clicked()), this, SLOT(cb_btn_abort())); 33 | connect(ui->lineEdit_chips_url, SIGNAL(textEdited(QString)), this, SLOT(lineEdit_url_textEdited(QString))); 34 | 35 | // 可以识别到系统代理,可以不需要手动设置 36 | // QNetworkProxy proxy; 37 | // proxy.setType(QNetworkProxy::HttpProxy); 38 | // proxy.setHostName("127.0.0.1"); 39 | // proxy.setPort(10809); 40 | // networkManager.setProxy(proxy); 41 | 42 | // cb_btn_refresh(); 43 | 44 | ui->label_msg->setText("未验证"); 45 | ui->progressBar->setVisible(false); 46 | } 47 | 48 | /******************************************************************************* 49 | * @brief 器件库配置对话窗口,析构函数 50 | * @param None 51 | * @return None 52 | ******************************************************************************/ 53 | ChipsConfigDialog::~ChipsConfigDialog() 54 | { 55 | delete ui; 56 | 57 | if (reply) 58 | { 59 | disconnect(reply, nullptr, nullptr, nullptr); 60 | reply->abort(); 61 | reply->deleteLater(); 62 | delete reply; 63 | } 64 | } 65 | 66 | /******************************************************************************* 67 | * @brief 回调函数,确认按钮按下 68 | * @param None 69 | * @return None 70 | ******************************************************************************/ 71 | void ChipsConfigDialog::cb_btn_ok() 72 | { 73 | qDebug("[ChipsConfigDialog] cb_btn_ok"); 74 | 75 | QDir tempDir(chips_directory); 76 | if (tempDir.exists()) 77 | { 78 | tempDir.removeRecursively(); 79 | } 80 | QDir().rename(tmp_chips_directory, chips_directory); 81 | 82 | emit accept(); 83 | } 84 | 85 | /******************************************************************************* 86 | * @brief 回调函数,中止按钮按下 87 | * @param None 88 | * @return None 89 | ******************************************************************************/ 90 | void ChipsConfigDialog::cb_btn_abort() 91 | { 92 | qDebug("[ChipsConfigDialog] cb_btn_abort"); 93 | 94 | if (reply) 95 | { 96 | 97 | disconnect(reply, nullptr, nullptr, nullptr); 98 | reply->abort(); 99 | reply->deleteLater(); 100 | delete reply; 101 | reply = NULL; 102 | } 103 | } 104 | 105 | void ChipsConfigDialog::lineEdit_url_textEdited(QString text) 106 | { 107 | qDebug("[ChipsConfigDialog] url_textEdited %s", qPrintable(text)); 108 | 109 | ui->label_msg->setText("未验证"); 110 | ui->btn_ok->setEnabled(false); 111 | } 112 | 113 | /******************************************************************************* 114 | * @brief 回调函数,刷新按钮按下 115 | * @param None 116 | * @return None 117 | ******************************************************************************/ 118 | void ChipsConfigDialog::cb_btn_refresh() 119 | { 120 | qDebug("[ChipsConfigDialog] cb_btn_refresh"); 121 | ui->btn_refresh->setEnabled(false); 122 | ui->lineEdit_chips_url->setEnabled(false); 123 | 124 | QUrl newUrl = QUrl::fromUserInput(get_chips_url()); 125 | qDebug("[ChipsConfigDialog] url: %s", qPrintable(newUrl.toString())); 126 | 127 | // networkManager.setNetworkAccessible(QNetworkAccessManager::Accessible); 128 | 129 | ui->progressBar->setMinimum(0); 130 | ui->progressBar->setMaximum(0); 131 | ui->progressBar->setValue(0); 132 | ui->progressBar->setVisible(true); 133 | 134 | // reply->ignoreSslErrors(); 135 | 136 | ui->label_msg->setText("发送了消息,等待服务器回复"); 137 | http_get_request(newUrl); 138 | ui->btn_ok->setEnabled(false); 139 | } 140 | 141 | /******************************************************************************* 142 | * @brief 回调函数,HTTP完成函数 143 | * @param None 144 | * @return None 145 | ******************************************************************************/ 146 | void ChipsConfigDialog::cb_reply_finished() 147 | { 148 | int err; 149 | 150 | ui->progressBar->setVisible(false); 151 | ui->btn_refresh->setEnabled(true); 152 | ui->lineEdit_chips_url->setEnabled(true); 153 | qDebug("[ChipsConfigDialog] finished"); 154 | 155 | QDir(".tmp").mkdir("."); 156 | QFile *downloadedFile = new QFile(tmp_chips_compress_file); 157 | if (downloadedFile->open(QIODevice::WriteOnly) == false) 158 | { 159 | QMessageBox::information(this, tr("错误"), "临时文件打开错误"); 160 | return; 161 | } 162 | 163 | file_buf.append(reply->readAll()); 164 | downloadedFile->write(file_buf); 165 | downloadedFile->close(); 166 | delete downloadedFile; 167 | downloadedFile = Q_NULLPTR; 168 | 169 | int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); 170 | qDebug("[ChipsConfigDialog] finished statusCode %d", statusCode); 171 | 172 | if (reply->error() != QNetworkReply::NoError) 173 | { 174 | qDebug("[ChipsConfigDialog] finished err: %d %s", reply->error(), qPrintable(reply->errorString())); 175 | 176 | ui->label_msg->setText(QString("通讯失败:%1").arg(qPrintable(reply->errorString()))); 177 | 178 | reply->deleteLater(); // 179 | reply = Q_NULLPTR; 180 | return; 181 | } 182 | 183 | if (file_buf.count() == 0) 184 | { 185 | qDebug("[ChipsConfigDialog] finished get empty"); 186 | 187 | reply->deleteLater(); 188 | reply = Q_NULLPTR; 189 | return; 190 | } 191 | 192 | err = extract(); 193 | if (err < 0) 194 | { 195 | ui->label_msg->setText("解压失败"); 196 | return; 197 | } 198 | 199 | ui->label_msg->setText("成功"); 200 | ui->progressBar->setVisible(true); 201 | ui->btn_ok->setEnabled(true); 202 | } 203 | 204 | void ChipsConfigDialog::cb_reply_redirected(QUrl url) 205 | { 206 | qDebug("[ChipsConfigDialog] cb_reply_redirected %s", qPrintable(url.toString())); 207 | } 208 | 209 | void ChipsConfigDialog::cb_reply_sslErrors(QList errors) 210 | { 211 | qDebug("[ChipsConfigDialog] cb_reply_sslErrors count:%d", errors.count()); 212 | } 213 | 214 | void ChipsConfigDialog::cb_reply_errorOccurred(QNetworkReply::NetworkError code) 215 | { 216 | qDebug("[ChipsConfigDialog] cb_reply_errorOccurred %d %s", code, qPrintable(QVariant::fromValue(code).toString())); 217 | } 218 | 219 | void ChipsConfigDialog::cb_reply_readyRead() 220 | { 221 | // qDebug("[ChipsConfigDialog] reply_readyRead"); 222 | file_buf.append(reply->readAll()); 223 | } 224 | 225 | void ChipsConfigDialog::cb_reply_downloadProgress(qint64 bytesRead, qint64 totalBytes) 226 | { 227 | // qDebug("[ChipsConfigDialog] download_progress"); 228 | qDebug("[ChipsConfigDialog] download_progress %d/%d", bytesRead, totalBytes); 229 | // qDebug("[ChipsConfigDialog] download_progress ContentLengthHeader: %s", qPrintable(reply->header(QNetworkRequest::ContentLengthHeader).toString())); 230 | 231 | if (totalBytes <= 0) 232 | { 233 | ui->progressBar->setMinimum(0); 234 | ui->progressBar->setMaximum(0); 235 | ui->progressBar->setValue(bytesRead); 236 | } 237 | else 238 | { 239 | ui->progressBar->setMinimum(0); 240 | ui->progressBar->setMaximum(totalBytes); 241 | ui->progressBar->setValue(bytesRead); 242 | } 243 | } 244 | 245 | QString ChipsConfigDialog::get_chips_url() 246 | { 247 | QString tmp_str = ui->lineEdit_chips_url->text(); 248 | 249 | if (tmp_str.isEmpty()) 250 | { 251 | ui->lineEdit_chips_url->setText(default_chips_url); 252 | } 253 | 254 | return ui->lineEdit_chips_url->text(); 255 | } 256 | 257 | void ChipsConfigDialog::set_chips_url(QString url) 258 | { 259 | if (url.isEmpty()) 260 | { 261 | url = default_chips_url; 262 | } 263 | 264 | ui->lineEdit_chips_url->setText(url); 265 | } 266 | 267 | int ChipsConfigDialog::http_get_request(QUrl url) 268 | { 269 | request.setUrl(url); 270 | // request.setRawHeader("User-Agent", "QDAP/1.0"); 271 | request.setRawHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"); 272 | request.setRawHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"); 273 | request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); 274 | 275 | file_buf.clear(); 276 | reply = networkManager.get(request); 277 | 278 | file_buf.clear(); 279 | reply = networkManager.get(request); 280 | 281 | connect(reply, SIGNAL(finished()), this, SLOT(cb_reply_finished())); 282 | connect(reply, SIGNAL(readyRead()), this, SLOT(cb_reply_readyRead())); 283 | 284 | connect(reply, SIGNAL(sslErrors(QList)), 285 | this, SLOT(cb_reply_sslErrors(QList))); 286 | 287 | connect(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), 288 | this, SLOT(cb_reply_errorOccurred(QNetworkReply::NetworkError))); 289 | 290 | connect(reply, SIGNAL(redirected(QUrl)), 291 | this, SLOT(cb_reply_redirected(QUrl))); 292 | 293 | connect(reply, SIGNAL(downloadProgress(qint64, qint64)), 294 | this, SLOT(cb_reply_downloadProgress(qint64, qint64))); 295 | 296 | return 0; 297 | } 298 | 299 | int ChipsConfigDialog::extract() 300 | { 301 | 302 | QDir tempDir(tmp_chips_directory); 303 | if (tempDir.exists()) 304 | { 305 | tempDir.removeRecursively(); 306 | } 307 | tempDir.mkdir("."); 308 | QZipReader reader(tmp_chips_compress_file); 309 | bool ok = reader.extractAll(tmp_chips_directory); 310 | if (ok == false) 311 | { 312 | return -1; 313 | } 314 | qDebug("[ChipsConfigDialog] extract"); 315 | 316 | QStringList dir_list; 317 | QStringList file_list; 318 | 319 | QDir dir(tmp_chips_directory); 320 | // QString chips_directory = dir.fromNativeSeparators(chips_directory); 321 | dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); 322 | dir.setSorting(QDir::Name); 323 | dir_list = dir.entryList(); 324 | 325 | dir.setFilter(QDir::Files | QDir::NoDotAndDotDot); 326 | dir.setSorting(QDir::Name); 327 | file_list = dir.entryList(); 328 | 329 | qDebug("[ChipsConfigDialog] extract dir_list len:%d", dir_list.length()); 330 | qDebug("[ChipsConfigDialog] extract file_list len:%d", file_list.length()); 331 | 332 | for (int i = 0; i < dir_list.length(); i++) 333 | { 334 | qDebug("[ChipsConfigDialog] extract ls %d %s", i, qPrintable(dir_list[i])); 335 | } 336 | 337 | if ((dir_list.length() == 1) && (file_list.length() == 0)) 338 | { 339 | 340 | QDir(tmp_chips_directory + "1").removeRecursively(); 341 | QDir(".").rename(tmp_chips_directory + QDir::separator() + dir_list[0], tmp_chips_directory + "1"); 342 | QDir(tmp_chips_directory).removeRecursively(); 343 | QDir().rename(tmp_chips_directory + "1", tmp_chips_directory); 344 | } 345 | 346 | qDebug("[ChipsConfigDialog] extract finished"); 347 | 348 | // 网络响应结束 349 | // QFileInfo fileInfo; 350 | // fileInfo.setFile(downloadedFile->fileName()); 351 | 352 | return 0; 353 | } 354 | 355 | int ChipsConfigDialog::apply() 356 | { 357 | return 0; 358 | } 359 | -------------------------------------------------------------------------------- /src/views/chips_config_dialog/chips_config_dialog.h: -------------------------------------------------------------------------------- 1 | #ifndef CHIPS_CONFIG_DIALOG_H 2 | #define CHIPS_CONFIG_DIALOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace Ui 13 | { 14 | class chips_config_dialog; 15 | } 16 | 17 | class ChipsConfigDialog : public QDialog 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | explicit ChipsConfigDialog(QWidget *parent = nullptr); 23 | ~ChipsConfigDialog(); 24 | 25 | QString get_chips_url(); 26 | void set_chips_url(QString url); 27 | 28 | public slots: 29 | void cb_btn_ok(); 30 | void lineEdit_url_textEdited(QString text); 31 | void cb_btn_refresh(); 32 | void cb_btn_abort(); 33 | 34 | void cb_reply_finished(); 35 | void cb_reply_redirected(QUrl url); 36 | void cb_reply_sslErrors(QList errors); 37 | void cb_reply_errorOccurred(QNetworkReply::NetworkError code); 38 | void cb_reply_readyRead(); 39 | void cb_reply_downloadProgress(qint64 bytesRead, qint64 totalBytes); 40 | 41 | private: 42 | int http_get_request(QUrl url); 43 | int http_get_request(QString url) { return http_get_request(QUrl(url)); }; 44 | int extract(); 45 | int apply(); 46 | 47 | private: 48 | Ui::chips_config_dialog *ui; 49 | 50 | QByteArray file_buf; 51 | 52 | QNetworkAccessManager networkManager; 53 | QNetworkRequest request; 54 | QNetworkReply *reply; 55 | }; 56 | 57 | #endif // DIALOG_CHIPS_CONFIG_H 58 | -------------------------------------------------------------------------------- /src/views/chips_config_dialog/chips_config_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | chips_config_dialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 842 10 | 435 11 | 12 | 13 | 14 | QDAP 芯片器件库管理 15 | 16 | 17 | 18 | 19 | 20 | 器件库地址: 21 | 22 | 23 | 24 | 25 | 26 | 27 | Qt::Vertical 28 | 29 | 30 | 31 | 20 32 | 40 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | Github 44 | 45 | 46 | 47 | :/assets/github_favicon.png:/assets/github_favicon.png 48 | 49 | 50 | 51 | 52 | Gitee 53 | 54 | 55 | 56 | :/assets/gitee_favicon.ico:/assets/gitee_favicon.ico 57 | 58 | 59 | 60 | 61 | Gitea 62 | 63 | 64 | 65 | :/assets/gitea_favicon.png:/assets/gitea_favicon.png 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 刷新 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 24 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 消息 95 | 96 | 97 | 98 | 99 | 100 | 101 | Qt::Horizontal 102 | 103 | 104 | 105 | 40 106 | 20 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 中止 115 | 116 | 117 | 118 | 119 | 120 | 121 | 应用 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /src/views/device_selector/cmsis-dap/enum_dap.cpp: -------------------------------------------------------------------------------- 1 | #include "enum_dap.h" 2 | #include "ui_enum_dap.h" 3 | 4 | EnumDAP::EnumDAP(QWidget *parent) 5 | : QWidget(parent), ui(new Ui::EnumDAP) 6 | { 7 | ui->setupUi(this); 8 | 9 | ui->dd_dev->addItem("Any CMSIS-DAP"); 10 | ui->dd_dev->setCurrentText(0); 11 | 12 | connect(ui->dd_dev, SIGNAL(currentIndexChanged(int)), this, SLOT(cb_dd_dev_currentIndexChanged(int))); 13 | 14 | QRegExp regexp("\\d+"); 15 | QRegExpValidator *validator = new QRegExpValidator(regexp, this); 16 | ui->lineEdit_clock->setValidator(validator); 17 | } 18 | 19 | EnumDAP::~EnumDAP() 20 | { 21 | delete ui; 22 | } 23 | 24 | // QComboBox *EnumDAP::dd_dev() 25 | // { 26 | // return ui->dd_dev; 27 | // } 28 | 29 | void EnumDAP::dd_dev_clear() 30 | { 31 | ui->dd_dev->blockSignals(true); 32 | while (ui->dd_dev->count() > 1) 33 | { 34 | ui->dd_dev->removeItem(1); 35 | } 36 | ui->dd_dev->blockSignals(false); 37 | 38 | device_list.clear(); 39 | 40 | ui->label_manufacturer->setText("N/A"); 41 | ui->label_product->setText("N/A"); 42 | ui->label_serial->setText("N/A"); 43 | ui->label_version->setText("N/A"); 44 | } 45 | 46 | void EnumDAP::dd_dev_append(CMSIS_DAP_Base *dap) 47 | { 48 | device_list.append(dap); 49 | 50 | QString tmp_str; 51 | 52 | switch (dap->type()) 53 | { 54 | case Devices::DAP_USB_HID: 55 | { 56 | 57 | // tmp_str = QString::asprintf( 58 | // "%d | HID [%s] [%s]", 59 | // ui->dd_dev->count(), 60 | // qPrintable(dap->get_manufacturer_string()), 61 | // qPrintable(dap->get_product_string())); 62 | tmp_str = QString::asprintf( 63 | "%d | V1 | %s", 64 | ui->dd_dev->count(), 65 | qPrintable(dap->get_product_string())); 66 | } 67 | break; 68 | case Devices::DAP_USB_Bulk: 69 | { 70 | CMSIS_DAP_V2 *tmp_dap_v2 = (CMSIS_DAP_V2 *)dap; 71 | 72 | tmp_str = QString::asprintf( 73 | "%d | V2 | %s", 74 | ui->dd_dev->count(), 75 | qPrintable(tmp_dap_v2->get_interface_string())); 76 | } 77 | break; 78 | default: 79 | tmp_str = "Unknown " + dap->type_str(); 80 | break; 81 | } 82 | 83 | ui->dd_dev->blockSignals(true); 84 | ui->dd_dev->addItem(tmp_str); 85 | ui->dd_dev->blockSignals(false); 86 | 87 | // if (ui->dd_dev->currentIndex() == 0) 88 | // { 89 | // set_info(0); 90 | // } 91 | // else 92 | // { 93 | // set_info(ui->dd_dev->currentIndex() - 1); 94 | // } 95 | } 96 | 97 | void EnumDAP::set_info_empty() 98 | { 99 | ui->label_manufacturer->setText("N/A"); 100 | ui->label_product->setText("N/A"); 101 | ui->label_serial->setText("N/A"); 102 | ui->label_version->setText("N/A"); 103 | } 104 | 105 | void EnumDAP::set_config_port(CMSIS_DAP_Base::Port port, bool swj) 106 | { 107 | switch (port) 108 | { 109 | case CMSIS_DAP_Base::SWD: 110 | ui->comboBox_port->setCurrentIndex(0); 111 | break; 112 | case CMSIS_DAP_Base::JTAG: 113 | ui->comboBox_port->setCurrentIndex(1); 114 | break; 115 | default: 116 | ui->comboBox_port->setCurrentIndex(-1); 117 | break; 118 | } 119 | 120 | ui->checkBox_swj->setChecked(swj); 121 | } 122 | 123 | void EnumDAP::set_config_clock(uint64_t clock, Devices::ClockUnit unit) 124 | { 125 | ui->lineEdit_clock->setText(QString::number(clock)); 126 | ui->comboBox_clock_unit->setCurrentIndex(unit); 127 | } 128 | 129 | CMSIS_DAP_Base::Port EnumDAP::get_config_port() 130 | { 131 | switch (ui->comboBox_port->currentIndex()) 132 | { 133 | case 0: 134 | return CMSIS_DAP_Base::SWD; 135 | default: 136 | return CMSIS_DAP_Base::JTAG; 137 | } 138 | } 139 | 140 | bool EnumDAP::get_config_swj() 141 | { 142 | return ui->checkBox_swj->isChecked(); 143 | } 144 | 145 | QString EnumDAP::get_config_clock_str() 146 | { 147 | return ui->lineEdit_clock->text() + 148 | Devices::get_clock_unit_str(static_cast(ui->comboBox_clock_unit->currentIndex())); 149 | } 150 | 151 | uint64_t EnumDAP::get_config_clock() 152 | { 153 | return ui->lineEdit_clock->text().toULongLong(); 154 | } 155 | 156 | Devices::ClockUnit EnumDAP::get_config_clock_unit() 157 | { 158 | return static_cast(ui->comboBox_clock_unit->currentIndex()); 159 | } 160 | 161 | void EnumDAP::set_info(CMSIS_DAP_Base *dap) 162 | { 163 | qDebug("[EnumDAP] set_info device"); 164 | 165 | if (dap == NULL) 166 | { 167 | set_info_empty(); 168 | return; 169 | } 170 | 171 | ui->label_manufacturer->setText(dap->get_manufacturer_string()); 172 | 173 | switch (dap->type()) 174 | { 175 | case Devices::DAP_USB_HID: 176 | { 177 | ui->label_product->setText(dap->get_product_string()); 178 | } 179 | break; 180 | case Devices::DAP_USB_Bulk: 181 | { 182 | CMSIS_DAP_V2 *tmp_dap_v2 = (CMSIS_DAP_V2 *)dap; 183 | 184 | ui->label_product->setText(tmp_dap_v2->get_interface_string()); 185 | } 186 | break; 187 | } 188 | 189 | ui->label_serial->setText(dap->get_serial_string()); 190 | ui->label_version->setText(dap->get_version_string()); 191 | } 192 | 193 | void EnumDAP::set_info(int index) 194 | { 195 | if (index >= device_list.count()) 196 | { 197 | set_info_empty(); 198 | return; 199 | } 200 | 201 | set_info(device_list[index]); 202 | } 203 | 204 | int EnumDAP::count() 205 | { 206 | return device_list.count(); 207 | } 208 | 209 | int EnumDAP::current_index() 210 | { 211 | int curent_index = ui->dd_dev->currentIndex(); 212 | 213 | if (curent_index == 0) 214 | return -1; 215 | 216 | if (device_list.count() == 0) 217 | return -1; 218 | 219 | if ((curent_index - 1) >= device_list.count()) 220 | { 221 | return device_list.count() - 1; 222 | } 223 | 224 | return curent_index - 1; 225 | } 226 | 227 | void EnumDAP::set_current_index(int index) 228 | { 229 | if (index == -1) 230 | { 231 | ui->dd_dev->setCurrentIndex(0); 232 | return; 233 | } 234 | 235 | ui->dd_dev->setCurrentIndex(index + 1); 236 | } 237 | 238 | Devices *EnumDAP::current_device() 239 | { 240 | if (count() == 0) 241 | return NULL; 242 | 243 | if (current_index() < 0) 244 | return NULL; 245 | 246 | if (current_index() == 0) 247 | return device_list[0]; 248 | 249 | return device_list[current_index() - 1]; 250 | } 251 | 252 | int EnumDAP::set_current_device(Devices *device) 253 | { 254 | return -1; 255 | } 256 | 257 | // void EnumDAP::cb_devices_changed(QList dev_list) 258 | // { 259 | // } 260 | 261 | void EnumDAP::cb_dd_dev_currentIndexChanged(int index) 262 | { 263 | if (index == 0) 264 | { 265 | set_info(0); 266 | } 267 | else 268 | { 269 | set_info(index - 1); 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /src/views/device_selector/cmsis-dap/enum_dap.h: -------------------------------------------------------------------------------- 1 | #ifndef ENUM_DAP_H 2 | #define ENUM_DAP_H 3 | 4 | #include 5 | #include 6 | #include "dap.h" 7 | 8 | namespace Ui 9 | { 10 | class EnumDAP; 11 | } 12 | 13 | class EnumDAP : public QWidget 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit EnumDAP(QWidget *parent = nullptr); 19 | ~EnumDAP(); 20 | 21 | // QComboBox *dd_dev(); 22 | 23 | void dd_dev_clear(); 24 | void dd_dev_append(CMSIS_DAP_Base *dap); 25 | void set_info(CMSIS_DAP_Base *dap); 26 | void set_info(int index); 27 | void set_info_empty(); 28 | void set_config_port(CMSIS_DAP_Base::Port port, bool swj); 29 | void set_config_clock(uint64_t clock, Devices::ClockUnit unit); 30 | 31 | CMSIS_DAP_Base::Port get_config_port(); 32 | bool get_config_swj(); 33 | QString get_config_clock_str(); 34 | uint64_t get_config_clock(); 35 | Devices::ClockUnit get_config_clock_unit(); 36 | 37 | int current_index(); 38 | void set_current_index(int index); 39 | Devices *current_device(); 40 | int set_current_device(Devices *device); 41 | 42 | int count(); 43 | 44 | public slots: 45 | // void cb_devices_changed(QList dev_list); 46 | void cb_dd_dev_currentIndexChanged(int index); 47 | 48 | private: 49 | Ui::EnumDAP *ui; 50 | 51 | QList device_list; 52 | }; 53 | 54 | #endif // ENUM_DAP_H 55 | -------------------------------------------------------------------------------- /src/views/device_selector/enum_writer_list.cpp: -------------------------------------------------------------------------------- 1 | #include "enum_writer_list.h" 2 | #include "ui_enum_writer_list.h" 3 | 4 | enum_writer_list::enum_writer_list(QWidget *parent) : QDialog(parent), 5 | ui(new Ui::enum_writer_list) 6 | { 7 | ui->setupUi(this); 8 | 9 | connect(ui->collapse, SIGNAL(currentChanged(int)), this, SLOT(cb_collapse_currentChanged(int))); 10 | connect(ui->btn_ok, SIGNAL(clicked()), this, SLOT(cb_btn_ok())); 11 | 12 | tmp_current_device = NULL; 13 | 14 | icon_arrow_right = QIcon(":/assets/chevron_right_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.png"); 15 | icon_arrow_down = QIcon(":/assets/keyboard_arrow_down_24dp_FFFFFF_FILL0_wght400_GRAD0_opsz24.png"); 16 | 17 | // widget_dap = new QWidget(this); 18 | // vbox_dap = new QVBoxLayout(widget_dap); 19 | // widget_dap->setLayout(vbox_dap); 20 | // widget_dap->setContentsMargins(0, 0, 0, 0); 21 | // vbox_dap->setMargin(0); 22 | 23 | enum_dap = new EnumDAP(this); 24 | 25 | // dd_dap = new QComboBox(this); 26 | // vbox_dap->addWidget(dd_dap); 27 | // dd_dap->addItem("Any CMSIS-DAP"); 28 | // vbox_dap->addWidget(new QLabel("")); 29 | // vbox_dap->setStretch(0, 0); 30 | // vbox_dap->setStretch(1, 1); 31 | 32 | while (ui->collapse->count()) 33 | ui->collapse->removeItem(0); 34 | 35 | ui->collapse->addItem(enum_dap, "CMSIS-DAP"); 36 | ui->collapse->addItem(new QWidget(), "Segger J-Link"); 37 | ui->collapse->addItem(new QWidget(), "WCH CH347"); 38 | ui->collapse->addItem(new QWidget(), "FTDI FT2232"); 39 | 40 | for (uint32_t i = 0; i < ui->collapse->count(); i++) 41 | { 42 | collapse_title_bak_list.append(ui->collapse->itemText(i)); 43 | } 44 | 45 | ui->collapse->setCurrentIndex(0); 46 | set_collapse_icon(0); 47 | 48 | ui->collapse->setStyleSheet(R""( 49 | QToolBox::tab { 50 | background-color: rgba(50, 50, 50, 1); 51 | color: rgba(255, 255, 255, 1); 52 | border-radius: 5px; 53 | } 54 | )""); 55 | 56 | connect(ui->btn_refresh_enum_devices, SIGNAL(clicked()), this, SLOT(cb_refresh_enum_devices())); 57 | } 58 | 59 | enum_writer_list::~enum_writer_list() 60 | { 61 | delete ui; 62 | } 63 | 64 | void enum_writer_list::set_auto_refresh(bool auto_refresh) 65 | { 66 | is_auto_refresh_enum_devices = auto_refresh; 67 | ui->btn_refresh_enum_devices->setEnabled(!auto_refresh); 68 | } 69 | 70 | void enum_writer_list::cb_device_changed(DeviceList dev_list, bool changed) 71 | { 72 | if (is_auto_refresh_enum_devices == false) 73 | { 74 | ui->btn_refresh_enum_devices->setEnabled(true); 75 | } 76 | 77 | if (changed) 78 | { 79 | qDebug("[enum_writer_list] dev_changed count:%d", dev_list.count()); 80 | } 81 | 82 | device_list.clear(); 83 | device_list.append(dev_list); 84 | 85 | // dap_hid_list_clear(); 86 | enum_dap->dd_dev_clear(); 87 | 88 | for (int i = 0; i < dev_list.count(); i++) 89 | { 90 | Devices *tmp_dev = dev_list.at(i); 91 | 92 | switch (tmp_dev->type()) 93 | { 94 | case Devices::DAP_USB_HID: 95 | { 96 | // qDebug(" %d [%s] [%s] [%s]", 97 | // i, 98 | // qPrintable(tmp_dev->type_str()), 99 | // qPrintable(tmp_dev->get_manufacturer_string()), 100 | // qPrintable(tmp_dev->get_product_string())); 101 | 102 | enum_dap->dd_dev_append((CMSIS_DAP_Base *)tmp_dev); 103 | } 104 | break; 105 | case Devices::DAP_USB_Bulk: 106 | { 107 | // qDebug(" %d [%s] [%s] [%s]", 108 | // i, 109 | // qPrintable(tmp_dev->type_str()), 110 | // qPrintable(tmp_dev->get_manufacturer_string()), 111 | // qPrintable(tmp_dev->get_product_string())); 112 | 113 | enum_dap->dd_dev_append((CMSIS_DAP_Base *)tmp_dev); 114 | } 115 | break; 116 | case Devices::DAP_USB_JLink: 117 | { 118 | } 119 | break; 120 | case Devices::DAP_ETH_JLink: 121 | { 122 | } 123 | break; 124 | case Devices::DAP_CH347: 125 | { 126 | } 127 | break; 128 | case Devices::DAP_FT2232: 129 | { 130 | } 131 | break; 132 | } 133 | 134 | // QPushButton *tmp_btn = new QPushButton(this); 135 | // tmp_btn->setText(str); 136 | // ui->gbox_cmsis_dap->layout()->addWidget(tmp_btn); 137 | } 138 | 139 | // ui->gbox_cmsis_dap->setTitle(QString::asprintf("CMSIS-DAP [%d]", ui->comboBox_daplink->count() - 1)); 140 | ui->collapse->setItemText(0, QString::asprintf( 141 | "%s [%d]", 142 | qPrintable(collapse_title_bak_list[0]), 143 | enum_dap->count())); 144 | // enum_dap->dd_dev()->setCurrentIndex(current_device_index); 145 | } 146 | 147 | void enum_writer_list::cb_collapse_currentChanged(int index) 148 | { 149 | set_collapse_icon(index); 150 | } 151 | 152 | void enum_writer_list::cb_btn_ok(void) 153 | { 154 | // emit finished(ui->comboBox_daplink->currentIndex()); 155 | 156 | accept(); 157 | } 158 | 159 | void enum_writer_list::cb_refresh_enum_devices() 160 | { 161 | if (is_auto_refresh_enum_devices) 162 | return; 163 | 164 | // ui->btn_refresh_enum_devices->setEnabled(false); 165 | 166 | emit refresh_enum_devides(); 167 | } 168 | 169 | void enum_writer_list::dap_hid_list_clear(void) 170 | { 171 | // while (ui->comboBox_daplink->count() > 1) 172 | // { 173 | // ui->comboBox_daplink->removeItem(1); 174 | // } 175 | 176 | // while (enum_dap->dd_dev()->count() > 1) 177 | // { 178 | // enum_dap->dd_dev()->removeItem(1); 179 | // } 180 | } 181 | 182 | int enum_writer_list::currentIndex(void) 183 | { 184 | // return ui->comboBox_daplink->currentIndex(); 185 | 186 | if (device_list.count() == 0) 187 | return -1; 188 | 189 | switch (ui->collapse->currentIndex()) 190 | { 191 | case 0: 192 | { 193 | return enum_dap->current_index(); 194 | } 195 | break; 196 | } 197 | 198 | return -1; 199 | } 200 | 201 | void enum_writer_list::setCurrentIndex(int index) 202 | { 203 | 204 | // current_device_index = n; 205 | // ui->comboBox_daplink->setCurrentIndex(n); 206 | } 207 | 208 | Devices *enum_writer_list::current_device() 209 | { 210 | // return tmp_current_device; 211 | 212 | if (device_list.count() == 0) 213 | return NULL; 214 | 215 | switch (ui->collapse->currentIndex()) 216 | { 217 | case 0: 218 | { 219 | return enum_dap->current_device(); 220 | } 221 | break; 222 | } 223 | 224 | return NULL; 225 | } 226 | 227 | void enum_writer_list::set_collapse_icon(uint32_t index) 228 | { 229 | ui->collapse->setItemIcon(0, icon_arrow_right); 230 | ui->collapse->setItemIcon(1, icon_arrow_right); 231 | ui->collapse->setItemIcon(2, icon_arrow_right); 232 | ui->collapse->setItemIcon(3, icon_arrow_right); 233 | 234 | ui->collapse->setItemIcon(index, icon_arrow_down); 235 | } 236 | 237 | void enum_writer_list::set_btn_manual_refresh_enabled(bool enabled) 238 | { 239 | ui->btn_refresh_enum_devices->setEnabled(enabled); 240 | } 241 | -------------------------------------------------------------------------------- /src/views/device_selector/enum_writer_list.h: -------------------------------------------------------------------------------- 1 | #ifndef ENUM_WRITER_LIST_H 2 | #define ENUM_WRITER_LIST_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "devices.h" 10 | #include "enum_writer_list.h" 11 | #include "enum_dap.h" 12 | 13 | namespace Ui 14 | { 15 | class enum_writer_list; 16 | } 17 | 18 | class enum_writer_list : public QDialog 19 | { 20 | Q_OBJECT 21 | 22 | public: 23 | explicit enum_writer_list(QWidget *parent = nullptr); 24 | ~enum_writer_list(); 25 | 26 | void set_auto_refresh(bool auto_refresh); 27 | 28 | void dap_hid_list_clear(void); 29 | int currentIndex(void); 30 | void setCurrentIndex(int index); 31 | 32 | Devices *current_device(); 33 | 34 | void set_collapse_icon(uint32_t index); 35 | void set_btn_manual_refresh_enabled(bool enabled); 36 | 37 | EnumDAP *get_enum_dap() { return enum_dap; } 38 | 39 | signals: 40 | void refresh_enum_devides(); 41 | 42 | public slots: 43 | void cb_device_changed(DeviceList dev_list, bool changed); 44 | void cb_collapse_currentChanged(int index); 45 | void cb_btn_ok(void); 46 | void cb_refresh_enum_devices(); 47 | 48 | private: 49 | Ui::enum_writer_list *ui; 50 | 51 | DeviceList device_list; 52 | int current_device_index; 53 | Devices *tmp_current_device; 54 | 55 | // QWidget *widget_dap; 56 | // QVBoxLayout *vbox_dap; 57 | // QComboBox *dd_dap; 58 | 59 | EnumDAP *enum_dap; 60 | 61 | QIcon icon_arrow_right; 62 | QIcon icon_arrow_down; 63 | 64 | bool is_auto_refresh_enum_devices; 65 | 66 | QStringList collapse_title_bak_list; 67 | }; 68 | 69 | #endif // ENUM_WRITER_LIST_H 70 | -------------------------------------------------------------------------------- /src/views/device_selector/enum_writer_list.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | enum_writer_list 4 | 5 | 6 | 7 | 0 8 | 0 9 | 450 10 | 700 11 | 12 | 13 | 14 | 请选择一个烧录器 15 | 16 | 17 | 18 | 19 | 20 | 确定(Enter) 21 | 22 | 23 | Return 24 | 25 | 26 | 27 | 28 | 29 | 30 | 刷新枚举(F5) 31 | 32 | 33 | F5 34 | 35 | 36 | 37 | 38 | 39 | 40 | 1 41 | 42 | 43 | 5 44 | 45 | 46 | 47 | 48 | 0 49 | 0 50 | 382 51 | 597 52 | 53 | 54 | 55 | Page 1 56 | 57 | 58 | 59 | 60 | 61 | 0 62 | 0 63 | 432 64 | 597 65 | 66 | 67 | 68 | Page 2 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/views/input_box_dialog/input_box_dialog.cpp: -------------------------------------------------------------------------------- 1 | #include "input_box_dialog.h" 2 | 3 | InputBoxDialog::InputBoxDialog(QDialog *parent) : QDialog(parent), 4 | ui(new Ui::input_box_dialog) 5 | { 6 | ui->setupUi(this); 7 | setWindowTitle("QDAP 参数输入窗口"); 8 | validator = NULL; 9 | ui->label_status->setVisible(false); 10 | } 11 | 12 | InputBoxDialog::~InputBoxDialog() 13 | { 14 | delete ui; 15 | } 16 | 17 | void InputBoxDialog::lineEdit_input_textEdited(QString text) 18 | { 19 | // qDebug("[InputBoxDialog] textEdited %s", qPrintable(text)); 20 | } 21 | 22 | void InputBoxDialog::set_validate_status(bool valid) 23 | { 24 | ui->btn_ok->setEnabled(valid); 25 | 26 | if (valid) 27 | { 28 | ui->label_status->setText("✅"); 29 | } 30 | else 31 | { 32 | ui->label_status->setText("❌"); 33 | } 34 | } 35 | 36 | void InputBoxDialog::set_validator(QValidator *v) 37 | { 38 | if (v == NULL) 39 | { 40 | ui->label_status->setVisible(false); 41 | validator = NULL; 42 | disconnect(ui->lineEdit_input, SIGNAL(textEdited(QString)), this, SLOT(lineEdit_input_textEdited(QString))); 43 | return; 44 | } 45 | 46 | ui->label_status->setVisible(true); 47 | 48 | int pos = 0; 49 | QString str = get_value(); 50 | QValidator::State state = validator->validate(str, pos); 51 | set_validate_status(state == QValidator::Acceptable); 52 | connect(ui->lineEdit_input, SIGNAL(textEdited(QString)), this, SLOT(lineEdit_input_textEdited(QString))); 53 | } 54 | -------------------------------------------------------------------------------- /src/views/input_box_dialog/input_box_dialog.h: -------------------------------------------------------------------------------- 1 | #ifndef INPUT_BOX_DIALOG_H 2 | #define INPUT_BOX_DIALOG_H 3 | 4 | #include 5 | #include 6 | #include "ui_input_box_dialog.h" 7 | 8 | namespace Ui 9 | { 10 | class input_box_dialog; 11 | } 12 | 13 | class InputBoxDialog : public QDialog 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit InputBoxDialog(QDialog *parent = nullptr); 19 | ~InputBoxDialog(); 20 | 21 | void set_description_text(const QString str) 22 | { 23 | ui->label_description->setText(str); 24 | } 25 | 26 | void set_default_value(const QString str) { ui->lineEdit_input->setText(str); } 27 | QString get_value() { return ui->lineEdit_input->text(); } 28 | 29 | void set_validator(QValidator *v); 30 | 31 | public slots: 32 | void lineEdit_input_textEdited(QString text); 33 | 34 | private: 35 | Ui::input_box_dialog *ui; 36 | 37 | QValidator *validator; 38 | 39 | void set_validate_status(bool valid); 40 | }; 41 | 42 | #endif // INPUT_BOX_DIALOG_H 43 | -------------------------------------------------------------------------------- /src/views/input_box_dialog/input_box_dialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | input_box_dialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 600 10 | 110 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | #QLabel{background-color: yellow;} 18 | 19 | 20 | 21 | 10 22 | 23 | 24 | 10 25 | 26 | 27 | 10 28 | 29 | 30 | 10 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 提示词: 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | Qt::Horizontal 50 | 51 | 52 | 53 | 40 54 | 20 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 确定 63 | 64 | 65 | 66 | 67 | 68 | 69 | Qt::Horizontal 70 | 71 | 72 | 73 | 40 74 | 20 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 36 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | btn_ok 101 | clicked() 102 | input_box_dialog 103 | accept() 104 | 105 | 106 | 255 107 | 83 108 | 109 | 110 | 299 111 | 54 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /src/win_hotplug_notify/win_hotplug_notify.cpp: -------------------------------------------------------------------------------- 1 | #include "win_hotplug_notify.h" 2 | 3 | WinHotplugNotify::WinHotplugNotify(QObject *parent) : QObject{parent} 4 | { 5 | HINSTANCE hi = ::GetModuleHandleW(nullptr); 6 | 7 | // 创建隐藏窗口以接收设备通知 8 | WNDCLASS wc; 9 | memset(&wc, 0, sizeof(WNDCLASSW)); 10 | wc.lpfnWndProc = windowMessageProcess; 11 | wc.cbClsExtra = 0; 12 | wc.cbWndExtra = 0; 13 | wc.hInstance = hi; 14 | wc.lpszClassName = get_window_class_name().toStdString().c_str(); 15 | RegisterClass(&wc); 16 | 17 | hwnd = CreateWindowW(get_window_class_name().toStdWString().c_str(), // classname 18 | get_window_class_name().toStdWString().c_str(), // window name 19 | 0, // style 20 | 0, // x 21 | 0, // y 22 | 0, // width 23 | 0, // height 24 | 0, // parent 25 | 0, // menu handle 26 | hi, // application 27 | 0); // windows creation data. 28 | 29 | if (hwnd == NULL) 30 | { 31 | qDebug("createMessageWindow error %d", (int)GetLastError()); 32 | return; 33 | } 34 | 35 | // 初始化 DEV_BROADCAST_DEVICEINTERFACE 数据结构 36 | DEV_BROADCAST_DEVICEINTERFACE_W filter_data; 37 | memset(&filter_data, 0, sizeof(DEV_BROADCAST_DEVICEINTERFACE_W)); 38 | filter_data.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE_W); 39 | filter_data.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; 40 | 41 | QUuid uuid = GUID_DEVINTERFACE_USB_DEVICE; 42 | 43 | filter_data.dbcc_classguid = uuid; 44 | usb_device_notification_handle = RegisterDeviceNotificationW(hwnd, &filter_data, DEVICE_NOTIFY_WINDOW_HANDLE); 45 | if (usb_device_notification_handle == NULL) 46 | { 47 | qDebug("[win_hotplug_notify] RegisterDeviceNotification error"); 48 | } 49 | 50 | SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)this); 51 | } 52 | 53 | WinHotplugNotify::~WinHotplugNotify() 54 | { 55 | if (hwnd) 56 | { 57 | DestroyWindow(hwnd); 58 | hwnd = NULL; 59 | 60 | if (usb_device_notification_handle) 61 | { 62 | UnregisterDeviceNotification(usb_device_notification_handle); 63 | usb_device_notification_handle = NULL; 64 | } 65 | } 66 | 67 | UnregisterClassW( 68 | reinterpret_cast(get_window_class_name().toStdString().c_str()), 69 | GetModuleHandleW(nullptr)); 70 | } 71 | 72 | LRESULT CALLBACK WinHotplugNotify::windowMessageProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 73 | { 74 | // qDebug("[WinHotplugNotify] windowMessageProcess"); 75 | 76 | static int i = 0; 77 | 78 | if (message == WM_DEVICECHANGE) 79 | { 80 | do 81 | { 82 | // 设备可用事件 83 | const bool is_add = wParam == DBT_DEVICEARRIVAL; 84 | // 设备移除事件 85 | const bool is_remove = wParam == DBT_DEVICEREMOVECOMPLETE; 86 | if (!is_add && !is_remove) 87 | break; 88 | 89 | // 过滤 device interface class 以外类型的消息 90 | DEV_BROADCAST_HDR *broadcast = reinterpret_cast(lParam); 91 | if (!broadcast || broadcast->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE) 92 | break; 93 | 94 | // 获取 SetWindowLongPtrW 设置的对象 95 | WinHotplugNotify *data = reinterpret_cast(GetWindowLongPtrW(hwnd, GWLP_USERDATA)); 96 | if (!data) 97 | break; 98 | 99 | // 过滤不监听的设备类型 100 | DEV_BROADCAST_DEVICEINTERFACE *device_interface = reinterpret_cast(broadcast); 101 | QUuid uid(device_interface->dbcc_classguid); 102 | if (uid != GUID_DEVINTERFACE_USB_DEVICE) 103 | break; 104 | 105 | QString device_name; 106 | if (device_interface->dbcc_name) 107 | { 108 | #ifdef UNICODE 109 | device_name = QString::fromWCharArray(device_interface->dbcc_name); 110 | #else 111 | device_name = QString(device_interface->dbcc_name); 112 | #endif 113 | } 114 | 115 | i++; 116 | // qDebug("[WinHotplugNotify] windowMessageProcess WM_DEVICECHANGE %s %d", qPrintable(device_name), i); 117 | 118 | Event e; 119 | 120 | if (is_add) 121 | { 122 | e = EVENT_DEVICE_ARRIVED; 123 | } 124 | else if (is_remove) 125 | { 126 | e = EVENT_DEVICE_REMOVED; 127 | } 128 | 129 | emit data->device_change(); 130 | } while (false); 131 | } 132 | 133 | return DefWindowProcW(hwnd, message, wParam, lParam); 134 | } 135 | -------------------------------------------------------------------------------- /src/win_hotplug_notify/win_hotplug_notify.h: -------------------------------------------------------------------------------- 1 | #ifndef WIN_HOTPLUG_NOTIFY_H 2 | #define WIN_HOTPLUG_NOTIFY_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | class WinHotplugNotify : public QObject 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | WinHotplugNotify(QObject *parent = nullptr); 21 | ~WinHotplugNotify(); 22 | 23 | enum Event 24 | { 25 | EVENT_DEVICE_ARRIVED = 1, 26 | EVENT_DEVICE_REMOVED = 2, 27 | }; 28 | Q_ENUM(Event) 29 | 30 | QString get_window_class_name() const 31 | { 32 | return QString("QDAP_win_win_hotplug_notify_window %1").arg(QString::number((uint64_t)hwnd, 16)); 33 | } 34 | 35 | signals: 36 | void device_change(); 37 | 38 | private: 39 | static LRESULT CALLBACK windowMessageProcess(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); 40 | 41 | HWND hwnd; 42 | 43 | HDEVNOTIFY usb_device_notification_handle; 44 | }; 45 | 46 | #endif // WIN_HOTPLUG_NOTIFY_H 47 | -------------------------------------------------------------------------------- /vendor.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import os 3 | from tqdm import tqdm 4 | from pathlib import Path 5 | import py7zr 6 | import zipfile 7 | import argparse 8 | import shutil 9 | 10 | 11 | def make_directory(path): 12 | if not os.path.exists(path): 13 | os.makedirs(path) 14 | 15 | 16 | def extract_7z(input_file, output_folder): 17 | with py7zr.SevenZipFile(input_file, mode='r') as z: 18 | z.extractall(path=output_folder) 19 | print(f'Extraction complete. Files extracted to {output_folder}') 20 | 21 | 22 | def extract_zip(input_file, output_folder): 23 | with zipfile.ZipFile(input_file, 'r') as zip_ref: 24 | zip_ref.extractall(output_folder) 25 | 26 | 27 | def extract_any(input_file, output_folder): 28 | 29 | print("[extract] {0} => {1}".format(input_file, output_folder)) 30 | 31 | if input_file.endswith(".7z"): 32 | extract_7z(input_file, output_folder) 33 | elif input_file.endswith(".zip"): 34 | extract_zip(input_file, output_folder) 35 | else: 36 | raise ValueError("Unsupported file format") 37 | 38 | 39 | def download_file(url, output_path): 40 | response = requests.get(url, stream=True) 41 | 42 | with open(output_path, "wb") as handle: 43 | for data in tqdm(response.iter_content()): 44 | handle.write(data) 45 | 46 | 47 | def pull_library_files(url, output_folder): 48 | 49 | if os.path.exists(output_folder): 50 | print( 51 | "[pull_library_files] output_folder [{0}] is already exists, skip download".format(output_folder)) 52 | return 53 | 54 | compress_file_path = "build/.tmp/vendor/" + os.path.basename(url) 55 | make_directory(output_folder) 56 | 57 | print("[pull_library_files] {0}".format(compress_file_path)) 58 | 59 | if os.path.exists(compress_file_path): 60 | print( 61 | "[pull_library_files] compress_file [{0}] is already exists, skip download".format(compress_file_path)) 62 | else: 63 | download_file(url, compress_file_path) 64 | 65 | extract_any(compress_file_path, output_folder) 66 | 67 | 68 | def clear_all_vendor_files(): 69 | shutil.rmtree("vendor/libusb") 70 | shutil.rmtree("vendor/libusb_hid_api") 71 | shutil.rmtree("vendor/openssl") 72 | shutil.rmtree("build/.tmp/vendor") 73 | 74 | 75 | def download_all_vendor_files(): 76 | make_directory("build/.tmp/vendor/") 77 | 78 | pull_library_files( 79 | "https://github.com/libusb/libusb/releases/download/v1.0.27/libusb-1.0.27.7z", 80 | "vendor/libusb") 81 | 82 | pull_library_files( 83 | "https://github.com/libusb/hidapi/releases/download/hidapi-0.14.0/hidapi-win.zip", 84 | "vendor/libusb_hid_api") 85 | 86 | pull_library_files( 87 | "https://wiki.overbyte.eu/arch/openssl-1.1.1w-win64.zip", 88 | "vendor/openssl") 89 | 90 | 91 | if __name__ == "__main__": 92 | 93 | parser = argparse.ArgumentParser(description='QDAP vendor manage script') 94 | subparsers = parser.add_subparsers(dest='command', help='sub command') 95 | parser_greet = subparsers.add_parser( 96 | name='clean', help="clean all vendor files") 97 | parser_greet = subparsers.add_parser( 98 | name='download', help="download all vendor files") 99 | args = parser.parse_args() 100 | 101 | if args.command == 'clean': 102 | clear_all_vendor_files() 103 | elif args.command == 'download': 104 | download_all_vendor_files() 105 | else: 106 | parser.print_help() 107 | 108 | # make_directory("build/vendor/") 109 | 110 | # url = "https://github.com/libusb/libusb/releases/download/v1.0.27/libusb-1.0.27.7z" 111 | # compress_file_path = "build/vendor/" + os.path.basename(url) 112 | # make_directory("vendor/libusb") 113 | # print("[vendor] libusb: {0}".format(compress_file_path)) 114 | # download_file(url, compress_file_path) 115 | # extract_7z(compress_file_path, "vendor/libusb") 116 | 117 | # make_directory("vendor/libusb_hid_api") 118 | # url = "https://github.com/libusb/hidapi/releases/download/hidapi-0.14.0/hidapi-win.zip" 119 | # compress_file_path = "build/vendor/" + os.path.basename(url) 120 | # print("[vendor] libusb-hid-api: {0}".format(compress_file_path)) 121 | # download_file(url, compress_file_path) 122 | # extract_zip(compress_file_path, "vendor/libusb_hid_api") 123 | --------------------------------------------------------------------------------