├── .github ├── FUNDING.yml └── workflows │ ├── build_osx.yml │ └── build_ubuntu.yml ├── .gitignore ├── CMakeLists.txt ├── Doxyfile ├── LICENSE ├── README.md ├── appveyor.yml ├── cmake ├── FindLibUSB.cmake ├── GetGitRevisionDescription.cmake └── GetGitRevisionDescription.cmake.in ├── include ├── cxxopts.hpp ├── fymodem.h └── radio_tool │ ├── codeplug │ ├── codeplug.hpp │ ├── codeplug_factory.hpp │ ├── rdt.hpp │ ├── rdt_general.hpp │ └── rdt_header.hpp │ ├── device │ └── ymodem_device.hpp │ ├── dfu │ ├── dfu.hpp │ ├── dfu_exception.hpp │ └── tyt_dfu.hpp │ ├── fw │ ├── ailunce_fw.hpp │ ├── cipher │ │ ├── cs800.hpp │ │ ├── dm1701.hpp │ │ ├── dr5xx0.hpp │ │ ├── md380.hpp │ │ ├── md9600.hpp │ │ ├── sgl.hpp │ │ └── uv3x0.hpp │ ├── cs_fw.hpp │ ├── fw.hpp │ ├── fw_factory.hpp │ ├── tyt_fw.hpp │ ├── tyt_fw_sgl.hpp │ └── yaesu_fw.hpp │ ├── h8sx │ ├── h8sx.hpp │ └── h8sx_exception.hpp │ ├── hid │ ├── hid.hpp │ └── tyt_hid.hpp │ ├── radio │ ├── ailunce_radio.hpp │ ├── radio.hpp │ ├── radio_factory.hpp │ ├── serial_radio_factory.hpp │ ├── tyt_radio.hpp │ ├── tyt_sgl_radio.hpp │ ├── usb_radio_factory.hpp │ └── yaesu_radio.hpp │ ├── util.hpp │ ├── util │ ├── flash.hpp │ └── log.hpp │ └── version.hpp ├── src ├── ailunce_fw.cpp ├── ailunce_radio.cpp ├── cs_fw.cpp ├── dfu.cpp ├── fymodem.c ├── h8sx.cpp ├── hid.cpp ├── radio_factory.cpp ├── radio_tool.cpp ├── rdt.cpp ├── serial_radio_factory.cpp ├── tyt_dfu.cpp ├── tyt_fw.cpp ├── tyt_fw_sgl.cpp ├── tyt_hid.cpp ├── tyt_radio.cpp ├── tyt_sgl_radio.cpp ├── usb_radio_factory.cpp ├── version.cpp.in ├── yaesu_fw.cpp ├── yaesu_radio.cpp └── ymodem_device.cpp └── test ├── CMakeLists.txt ├── dummy_device.hpp ├── dump_sgl_info.cpp ├── firmware ├── BF-5R_V2.1.0.sgl.sha256 ├── BF-5R_V2.1.6.sgl.sha256 ├── CS800D_Host_MS.30.14_Use_Flashburn3.0_Upgrade.bin.sha256 ├── CS800D_RCDB_Upgradde.bin.sha256 ├── D013.034.bin.sha256 ├── GD-77S_V1.2.0.sgl.sha256 ├── GD-77S_V1.3.0.sgl.sha256 ├── GD-77_V3.2.1.sgl.sha256 ├── GD-77_V3.2.2.sgl.sha256 ├── GD-77_V4.2.6.sgl.sha256 ├── GD-77_V4.2.8.sgl.sha256 ├── MD280.002.018.bin.sha256 ├── RD-5R_V2.0.9.sgl.sha256 ├── RT3S_CSV_GPS__P16.06.bin.sha256 ├── RT3S_CSV__V16.06.bin.sha256 ├── RT3S_GPS_REC__S16.06.bin.sha256 ├── RT3S_REC__D16.06.bin.sha256 ├── TEST_CS800_4000__Mobile_M100000_Host_S3.02.07_Auth_Test_Ver_1_.bin.sha256 ├── TYT2017_UVCSV_GPS_P3.35.bin.sha256 ├── TYT2017_UVCSV_V3.35.bin.sha256 ├── TYT2017_UVGPS_REC_S3.31.bin.sha256 ├── TYT2017_UVGPS_REC_S3.38.bin.sha256 ├── TYT2017_UVREC_D3.31.bin.sha256 ├── TYT2017_UVREC_D3.36.bin.sha256 ├── TYT2017_UV_CSV_GPS__P3.33.bin.sha256 ├── TYT2017_UV_CSV_GPS__P3.35.bin.sha256 ├── TYT2017_UV_CSV_GPS__P3.38.bin.sha256 ├── TYT2017_UV_CSV__V3.33.bin.sha256 ├── TYT2017_UV_CSV__V3.35.bin.sha256 ├── TYT2017_UV_CSV__V3.36.bin.sha256 ├── TYT2017_UV_GPS_REC__S3.31.bin.sha256 ├── TYT2017_UV_GPS_REC__S3.38.bin.sha256 ├── TYT2017_UV_REC__D3.31.bin.sha256 ├── TYT2017_UV_REC__D3.36.bin.sha256 ├── TYT_GPS_MD390_MD380_S003.012.bin.sha256 ├── TYT_TFT_MD380_D3.20.bin.sha256 ├── TYT_TFT_MD446_D3.20.bin.sha256 ├── TYT_Vocoder_MD380_D13.14.bin.sha256 ├── TYT_Vocoder_MD380_D13.20.bin.sha256 ├── TYT_Vocoder_MD380_D14.07.bin.sha256 ├── TYT_Vocoder_MD390_S13.12.bin.sha256 ├── TYT_Vocoder_MD390_S13.20.bin.sha256 ├── TYT_Vocoder_MD390_S15.02.bin.sha256 ├── TYT_Vocoder_MD390_S15.04.bin.sha256 ├── TYT_Vocoder_MD446_D13.20.bin.sha256 ├── dm1701_2.03.bin.sha256 ├── md2017_csv_gps_p4.17.bin.sha256 ├── md2017_csv_v4.15.bin.sha256 ├── md2017_rec_d4.15.bin.sha256 ├── md2017_rec_gps_s4.17.bin.sha256 ├── md9600_csv_gps_p6.13.bin.sha256 ├── md9600_csv_v6.09.bin.sha256 ├── md9600_rec_d6.09.bin.sha256 ├── md9600_rec_gps_s6.13.bin.sha256 ├── mk_links.py ├── uv380_csv_v18.11.bin.sha256 ├── uv380_rec_d18.11.bin.sha256 ├── uv390_csv_gps_p18.11.bin.sha256 └── uv390_rec_gps_s18.11.bin.sha256 ├── test_bin2sgl.sh ├── test_firmware_download.cpp ├── test_fw.cpp ├── test_util.cpp └── test_xor_tool.cpp /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | liberapay: v0l 4 | patreon: v0l 5 | custom: ['https://pay.v0l.io/api/v1/invoices?storeId=CxjchLEkirhBWU17KeJrAe71g5TzrxsvsfLuFwrnyp5Q&price=1¤cy=USD'] 6 | -------------------------------------------------------------------------------- /.github/workflows/build_osx.yml: -------------------------------------------------------------------------------- 1 | name: OSXRelease 2 | on: 3 | push: 4 | branches: ["main"] 5 | pull_request: 6 | jobs: 7 | build: 8 | runs-on: macos-12 9 | steps: 10 | - uses: actions/checkout@v2 11 | - name: run-cmake 12 | working-directory: ${{ github.workspace }} 13 | run: | 14 | mkdir build && cd build 15 | cmake -DBUILD_TESTING=1 -DCMAKE_BUILD_TYPE=Release .. 16 | - name: make 17 | working-directory: ${{ github.workspace }}/build 18 | run: make -j4 19 | - name: test 20 | working-directory: ${{ github.workspace }}/build 21 | run: ctest -C Release --timeout 600 --output-on-failure 22 | - name: pack 23 | working-directory: ${{ github.workspace }}/build 24 | run: cpack -C Release 25 | - uses: actions/upload-artifact@v2 26 | with: 27 | name: release-dmg 28 | path: | 29 | ${{github.workspace}}/build/*.dmg 30 | ${{github.workspace}}/build/*.dmg.sha256 31 | -------------------------------------------------------------------------------- /.github/workflows/build_ubuntu.yml: -------------------------------------------------------------------------------- 1 | name: UbuntuRelease 2 | on: 3 | push: 4 | branches: ["main"] 5 | pull_request: 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - name: apt-install 12 | run: | 13 | sudo apt update 14 | sudo apt install libusb-1.0-0-dev cmake gcc-9 15 | - name: run-cmake 16 | run: | 17 | cd ${{github.workspace}} 18 | mkdir build && cd build 19 | cmake -DBUILD_TESTING=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/bin/gcc-9 -DCMAKE_CXX_COMPILER=/usr/bin/g++-9 .. 20 | - name: make 21 | run: | 22 | cd ${{github.workspace}}/build 23 | make -j4 24 | - name: test 25 | run: | 26 | cd ${{github.workspace}}/build 27 | ctest -C Release --timeout 600 --output-on-failure 28 | - name: pack 29 | run: | 30 | cd ${{github.workspace}}/build 31 | cpack -C Release 32 | - uses: actions/upload-artifact@v2 33 | with: 34 | name: release-deb 35 | path: | 36 | ${{github.workspace}}/build/*.deb 37 | ${{github.workspace}}/build/*.deb.sha256 38 | - uses: actions/upload-artifact@v2 39 | with: 40 | name: release-tar 41 | path: | 42 | ${{github.workspace}}/build/*.tar.xz.sha256 43 | ${{github.workspace}}/build/*.tar.xz 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .vscode/ 3 | *.bin 4 | .DS_Store 5 | .vs/ 6 | CMakeSettings.json 7 | test/bin2sgl 8 | test/random* 9 | Testing/Temporary 10 | 11 | html/ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2.0) 2 | project(radio_tool VERSION 0.2.2) 3 | 4 | option(BUILD_TESTING "Enable tests" OFF) 5 | 6 | if(NOT CMAKE_BUILD_TYPE) 7 | set(CMAKE_BUILD_TYPE Release) 8 | endif() 9 | string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER) 10 | 11 | if(NOT CMAKE_GENERATOR_PLATFORM) 12 | set(CMAKE_GENERATOR_PLATFORM x64) 13 | endif() 14 | 15 | set(CMAKE_CXX_STANDARD 20) 16 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 17 | 18 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 19 | 20 | #Git version 21 | include(GetGitRevisionDescription) 22 | get_git_head_revision(GIT_REFSPEC GIT_SHA1) 23 | git_describe(GIT_SHA1_SHORT "--always") 24 | configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/version.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp" @ONLY) 25 | 26 | #FindLIBUSB 27 | if (${CMAKE_CXX_COMPILER_ID} STREQUAL GNU OR ${CMAKE_CXX_COMPILER_ID} STREQUAL AppleClang) 28 | find_package(LibUSB REQUIRED) 29 | set(CMAKE_CXX_FLAGS "-Wall -Wextra") 30 | set(CMAKE_CXX_FLAGS_DEBUG "-g") 31 | set(CMAKE_CXX_FLAGS_RELEASE "-O3") 32 | elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) 33 | set(VCPKG_INCLUDE_DIR $ENV{VCPKG_ROOT}\\installed\\${CMAKE_GENERATOR_PLATFORM}-windows\\include) 34 | if(${CMAKE_BUILD_TYPE_LOWER} STREQUAL release) 35 | set(VCPKG_LIB_DIR $ENV{VCPKG_ROOT}\\installed\\${CMAKE_GENERATOR_PLATFORM}-windows\\lib) 36 | elseif (${CMAKE_BUILD_TYPE_LOWER} STREQUAL debug) 37 | set(VCPKG_LIB_DIR $ENV{VCPKG_ROOT}\\installed\\${CMAKE_GENERATOR_PLATFORM}-windows\\debug\\lib) 38 | endif() 39 | message("-- VCPKG include dir: ${VCPKG_INCLUDE_DIR}") 40 | message("-- VCPKG lib dir: ${VCPKG_LIB_DIR}") 41 | add_definitions(-DNOMINMAX -DVC_EXTRALEAN -DWIN32_LEAN_AND_MEAN) 42 | endif() 43 | 44 | if(BUILD_TESTING) 45 | include(CTest) 46 | enable_testing() 47 | add_subdirectory(test) 48 | endif() 49 | 50 | set(ALL_SRC 51 | src/radio_tool.cpp 52 | src/dfu.cpp 53 | src/h8sx.cpp 54 | src/radio_factory.cpp 55 | src/usb_radio_factory.cpp 56 | src/serial_radio_factory.cpp 57 | src/tyt_radio.cpp 58 | src/ymodem_device.cpp 59 | src/tyt_dfu.cpp 60 | src/tyt_fw.cpp 61 | src/tyt_fw_sgl.cpp 62 | src/cs_fw.cpp 63 | src/ailunce_radio.cpp 64 | src/ailunce_fw.cpp 65 | src/yaesu_radio.cpp 66 | src/yaesu_fw.cpp 67 | src/fymodem.c 68 | src/rdt.cpp 69 | src/hid.cpp 70 | src/tyt_hid.cpp 71 | src/tyt_sgl_radio.cpp 72 | "${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp" 73 | ) 74 | 75 | file(GLOB_RECURSE ALL_HEADERS include false "*.h*") 76 | 77 | add_library(radiotool ${ALL_SRC} ${ALL_HEADERS}) 78 | target_include_directories(radiotool PUBLIC include) 79 | 80 | add_executable(radio_tool src/radio_tool.cpp) 81 | target_include_directories(radio_tool PUBLIC include) 82 | target_link_libraries(radio_tool radiotool) 83 | 84 | if (${CMAKE_CXX_COMPILER_ID} STREQUAL GNU OR ${CMAKE_CXX_COMPILER_ID} STREQUAL AppleClang) 85 | target_link_libraries(radiotool pthread) 86 | target_link_libraries(radiotool PkgConfig::LibUSB) 87 | target_link_libraries(radio_tool PkgConfig::LibUSB) 88 | target_include_directories(radiotool PUBLIC ${LibUSB_INCLUDEDIR}) 89 | target_include_directories(radio_tool PUBLIC ${LibUSB_INCLUDEDIR}) 90 | elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) 91 | target_include_directories(radiotool PUBLIC ${VCPKG_INCLUDE_DIR}) 92 | target_link_directories(radiotool PRIVATE ${VCPKG_LIB_DIR}) 93 | target_include_directories(radio_tool PUBLIC ${VCPKG_INCLUDE_DIR}) 94 | target_link_directories(radio_tool PRIVATE ${VCPKG_LIB_DIR}) 95 | 96 | target_link_libraries(radiotool libusb-1.0) 97 | target_link_libraries(radio_tool libusb-1.0) 98 | endif() 99 | 100 | if(XOR_TOOL_INC) 101 | if (EXISTS "${XOR_TOOL_INC}/xor_tool.hpp") 102 | message("-- XOR Tool found") 103 | add_definitions(-DXOR_TOOL) 104 | include_directories(${XOR_TOOL_INC}) 105 | else() 106 | message(SEND_ERROR "xor_tool.hpp not found (Make sure to specifiy an absolute path)") 107 | endif() 108 | endif() 109 | 110 | install(TARGETS radio_tool RUNTIME DESTINATION bin) 111 | 112 | set(CPACK_PROJECT_NAME ${PROJECT_NAME}) 113 | set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) 114 | set(CPACK_PACKAGE_DESCRIPTION "Universal radio firmware tool") 115 | set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/v0l/radio_tool") 116 | set(CPACK_PACKAGE_CONTACT "v0l ") 117 | set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") 118 | if(${CMAKE_CXX_COMPILER_ID} STREQUAL AppleClang) 119 | set(CPACK_GENERATOR "DragNDrop") 120 | else() 121 | set(CPACK_GENERATOR "DEB" "TGZ" "TXZ") 122 | endif() 123 | set(CPACK_PACKAGE_CHECKSUM SHA256) 124 | set(CPACK_STRIP_FILES true) 125 | 126 | set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64") 127 | set(CPACK_DEBIAN_PACKAGE_DEPENDS "libusb-1.0-0") 128 | set(CPACK_DEBIAN_PACKAGE_SECTION "hamradio") 129 | set(CPACK_DEBIAN_COMPRESSION_TYPE "xz") 130 | include(CPack) 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # radio_tool 2 | 3 | Radio Firmware tool 4 | 5 | ## Radio Support 6 | 7 | | Manufacturer | Radio Model | Fw Read | Fw Write | Fw Wrap | Db Read | Db Write | 8 | | - | - | - | - | - | - | - | 9 | | TYT | [MD-2017](https://www.tyt888.com/?mod=product_show&id=110)| ✖️ | ✔️ | ✔️ | ✖️ | ✖️ | 10 | | TYT | [MD-9600](https://www.tyt888.com/?mod=product_show&id=108) | ✖️ | ✔️ | ✔️ | ✖️ | ✖️ | 11 | | TYT | [MD-UV380](https://www.tyt888.com/?mod=product_show&id=127) | ✖️ | ✔️ | ✔️ | ✖️ | ✖️ | 12 | | TYT | [MD-UV390](https://www.tyt888.com/?mod=product_show&id=129) | ✖️ | ✔️ | ✔️ | ✖️ | ✖️ | 13 | | TYT | [MD-390](https://www.tyt888.com/?mod=product_show&id=77) | ✖️ | ✔️ | ✔️ | ✖️ | ✖️ | 14 | | TYT | [MD-380](https://www.tyt888.com/?mod=product_show&id=78) | ✖️ | ✔️ | ✔️ | ✖️ | ✖️ | 15 | | TYT | [MD-446](https://www.tyt888.com/?mod=product_show&id=75) | ✖️ | ✔️ | ✔️ | ✖️ | ✖️ | 16 | | TYT | [MD-280](https://www.tyt888.com/?mod=product_show&id=80) | ✖️ | ✔️ | ✔️ | ✖️ | ✖️ | 17 | | Baofeng | [DM-1701](https://www.baofengradio.com/products/dm-1701) | ✖️ | ✔️ | ✔️ | ✖️ | ✖️ | 18 | | Baofeng | [DM-1801](https://www.baofengradio.com/products/dm-1801) | ✖️ | ✔️ | ✔️ | ✖️ | ✖️ | 19 | | Baofeng | [RD-5R](https://www.baofengradio.com/products/rd-5r) | ✖️ | ✔️ | ✔️ | ✖️ | ✖️ | 20 | | Connect Systems | [CS800D](https://www.connectsystems.com/products/top/radios/CS800D.htm) | ✖️ | ✖️ | ✔️ | ✖️ | ✖️ | 21 | | Ailunce | [HD1](https://www.ailunce.com/Product/HD1/Overview) | ✖️ | ✔️ | ✔️ | ✖️ | ✖️ | 22 | | Yaesu | [FT-70DR](https://www.yaesu.com/indexVS.cfm?cmd=DisplayProducts&ProdCatID=249&encProdID=7CDB93B02164B1FB036530FBD7D37F1A&DivisionID=65&isArchived=0) | ✖️ | ✔️ | ✖️ | ✖️ | ✖️ | 23 | | Radioddity | [GD-77](https://www.radioddity.com/products/radioddity-gd-77-dmr-two-way-radio) | ✖️ | ✔️ | ✔️ | ✖️ | ✖️ | 24 | 25 | ``` 26 | Fw = Firmware 27 | Db = Codeplug database 28 | ``` 29 | # Download 30 | 31 | Windows: [AppVeyor](https://ci.appveyor.com/project/v0l/radio-tool) 32 | 33 | Linux: [Github Actions](https://github.com/v0l/radio_tool/actions) 34 | 35 | ![AppVeyor](https://ci.appveyor.com/api/projects/status/github/v0l/radio_tool?svg=true) 36 | 37 | ![Release](https://github.com/v0l/radio_tool/workflows/UbuntuRelease/badge.svg) 38 | 39 | Otherwise you can use the instructions below to build 40 | 41 | # Building 42 | Dependencies Linux (Ubuntu/Debian): 43 | 44 | ```bash 45 | sudo apt install libusb-1.0-0-dev cmake gcc g++ pkg-config 46 | ``` 47 | 48 | Dependencies Mac: 49 | ```bash 50 | brew install libusb cmake pkg-config 51 | ``` 52 | 53 | Build: 54 | ```bash 55 | git clone https://github.com/v0l/radio_tool 56 | cd radio_tool 57 | mkdir build && cd build 58 | cmake .. 59 | make -j4 60 | ./radio_tool --help 61 | ``` 62 | 63 | # Docs 64 | Code documentation: https://data.v0l.io/radio_tool/docs 65 | 66 | # Usage 67 | ``` 68 | Usage: 69 | ./radio_tool [OPTION...] 70 | 71 | General options: 72 | -h, --help Show this message 73 | -l, --list List devices 74 | -d, --device Device to use 75 | -i, --in Input file 76 | -o, --out Output file 77 | -L, --list-radios List supported radios 78 | 79 | Programming options: 80 | -f, --flash Flash firmware 81 | -p, --program Upload codeplug 82 | 83 | Firmware options: 84 | --fw-info Print info about a firmware file 85 | --wrap Wrap a firmware bin (use --help wrap, for more info) 86 | --unwrap Unwrap a fimrware file 87 | 88 | All radio options: 89 | --info Print some info about the radio 90 | --write-custom Send custom command to radio 91 | --get-status Print the current DFU Status 92 | 93 | TYT Radio options: 94 | --get-time Gets the radio time 95 | --set-time Sets the radio time 96 | --dump-reg Dump a register from the radio 97 | --reboot Reboot the radio 98 | --dump-bootloader Dump bootloader (Mac only) 99 | 100 | Codeplug options: 101 | --codeplug-info Print info about a codeplug file 102 | ``` 103 | 104 | ## Flash Firmware 105 | ```bash 106 | ./radio_tool -d 0 -f -i new_firmware.bin 107 | ``` 108 | 109 | ## Wrap Firmware 110 | ```bash 111 | ./radio_tool --wrap -o wrapped.bin -r DM1701 -s 0x0800C000:main.bin 112 | ``` 113 | 114 | ## Unwrap Firmware 115 | Output file in this case is a file prefix, the filename will be `unwrapped_0x0800C000` and others if you have 116 | firmware will more than one segment 117 | ```bash 118 | ./radio_tool --unwrap -i wrapped.bin -o unwrapped 119 | ``` 120 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | 3 | image: 4 | - Visual Studio 2022 5 | 6 | configuration: 7 | - Debug 8 | - Release 9 | 10 | environment: 11 | matrix: 12 | - DBUILD_TESTING: 1 13 | VCPKG_ROOT: C:\Tools\vcpkg 14 | 15 | install: 16 | - cd %VCPKG_ROOT% 17 | - git pull 18 | - .\bootstrap-vcpkg.bat 19 | - .\vcpkg install libusb:x86-windows libusb:x64-windows 20 | - cd %APPVEYOR_BUILD_FOLDER% 21 | 22 | cache: 23 | - '%VCPKG_ROOT%\installed' 24 | - '%APPVEYOR_BUILD_FOLDER%\build\ExternalData\Objects' 25 | 26 | before_build: 27 | - cmd: cmake -H. -B./build -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%/scripts/buildsystems/vcpkg.cmake -DBUILD_TESTING=%DBUILD_TESTING% 28 | 29 | after_build: 30 | - cmd: cd %APPVEYOR_BUILD_FOLDER% && 7z a radio_tool_%CONFIGURATION%_%APPVEYOR_BUILD_VERSION%.zip %APPVEYOR_BUILD_FOLDER%\build\%CONFIGURATION%\* 31 | 32 | test_script: 33 | - cmd: cd %APPVEYOR_BUILD_FOLDER%\build && ctest -C %CONFIGURATION% --timeout 600 --output-on-failure 34 | 35 | artifacts: 36 | - path: radio_tool_%CONFIGURATION%_%APPVEYOR_BUILD_VERSION%.zip 37 | name: '%CONFIGURATION%_bin' 38 | 39 | build: 40 | verbosity: normal 41 | project: build/radio_tool.sln 42 | -------------------------------------------------------------------------------- /cmake/FindLibUSB.cmake: -------------------------------------------------------------------------------- 1 | if(NOT WIN32) 2 | set(MODULE "libusb-1.0") 3 | include(FindPkgConfig) 4 | if(PKG_CONFIG_FOUND) 5 | SET(MODULE "libusb-1.0") 6 | IF(CMAKE_SYSTEM_NAME MATCHES "Linux") 7 | SET(MODULE "libusb-1.0>=1.0.20") 8 | ENDIF() 9 | IF(LibUSB_FIND_REQUIRED) 10 | SET(LibUSB_REQUIRED "REQUIRED") 11 | ENDIF() 12 | PKG_CHECK_MODULES(LibUSB ${LibUSB_REQUIRED} ${MODULE} IMPORTED_TARGET) 13 | RETURN() 14 | endif() 15 | endif() 16 | message(SEND_ERROR "Platform not supported") -------------------------------------------------------------------------------- /cmake/GetGitRevisionDescription.cmake: -------------------------------------------------------------------------------- 1 | # - Returns a version string from Git 2 | # 3 | # These functions force a re-configure on each git commit so that you can 4 | # trust the values of the variables in your build system. 5 | # 6 | # get_git_head_revision( [ ...]) 7 | # 8 | # Returns the refspec and sha hash of the current head revision 9 | # 10 | # git_describe( [ ...]) 11 | # 12 | # Returns the results of git describe on the source tree, and adjusting 13 | # the output so that it tests false if an error occurs. 14 | # 15 | # git_get_exact_tag( [ ...]) 16 | # 17 | # Returns the results of git describe --exact-match on the source tree, 18 | # and adjusting the output so that it tests false if there was no exact 19 | # matching tag. 20 | # 21 | # git_local_changes() 22 | # 23 | # Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes. 24 | # Uses the return code of "git diff-index --quiet HEAD --". 25 | # Does not regard untracked files. 26 | # 27 | # Requires CMake 2.6 or newer (uses the 'function' command) 28 | # 29 | # Original Author: 30 | # 2009-2010 Ryan Pavlik 31 | # http://academic.cleardefinition.com 32 | # Iowa State University HCI Graduate Program/VRAC 33 | # 34 | # Copyright Iowa State University 2009-2010. 35 | # Distributed under the Boost Software License, Version 1.0. 36 | # (See accompanying file LICENSE_1_0.txt or copy at 37 | # http://www.boost.org/LICENSE_1_0.txt) 38 | 39 | if(__get_git_revision_description) 40 | return() 41 | endif() 42 | set(__get_git_revision_description YES) 43 | 44 | # We must run the following at "include" time, not at function call time, 45 | # to find the path to this module rather than the path to a calling list file 46 | get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) 47 | 48 | function(get_git_head_revision _refspecvar _hashvar) 49 | set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") 50 | set(GIT_DIR "${GIT_PARENT_DIR}/.git") 51 | while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories 52 | set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") 53 | get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) 54 | if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) 55 | # We have reached the root directory, we are not in git 56 | set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) 57 | set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) 58 | return() 59 | endif() 60 | set(GIT_DIR "${GIT_PARENT_DIR}/.git") 61 | endwhile() 62 | # check if this is a submodule 63 | if(NOT IS_DIRECTORY ${GIT_DIR}) 64 | file(READ ${GIT_DIR} submodule) 65 | string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) 66 | get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) 67 | get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) 68 | endif() 69 | if(NOT IS_DIRECTORY "${GIT_DIR}") 70 | file(READ ${GIT_DIR} worktree) 71 | string(REGEX REPLACE "gitdir: (.*)worktrees(.*)\n$" "\\1" GIT_DIR ${worktree}) 72 | endif() 73 | set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") 74 | if(NOT EXISTS "${GIT_DATA}") 75 | file(MAKE_DIRECTORY "${GIT_DATA}") 76 | endif() 77 | 78 | if(NOT EXISTS "${GIT_DIR}/HEAD") 79 | return() 80 | endif() 81 | set(HEAD_FILE "${GIT_DATA}/HEAD") 82 | configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) 83 | 84 | configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" 85 | "${GIT_DATA}/grabRef.cmake" 86 | @ONLY) 87 | include("${GIT_DATA}/grabRef.cmake") 88 | 89 | set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) 90 | set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) 91 | endfunction() 92 | 93 | function(git_describe _var) 94 | if(NOT GIT_FOUND) 95 | find_package(Git QUIET) 96 | endif() 97 | get_git_head_revision(refspec hash) 98 | if(NOT GIT_FOUND) 99 | set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) 100 | return() 101 | endif() 102 | if(NOT hash) 103 | set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) 104 | return() 105 | endif() 106 | 107 | # TODO sanitize 108 | #if((${ARGN}" MATCHES "&&") OR 109 | # (ARGN MATCHES "||") OR 110 | # (ARGN MATCHES "\\;")) 111 | # message("Please report the following error to the project!") 112 | # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") 113 | #endif() 114 | 115 | #message(STATUS "Arguments to execute_process: ${ARGN}") 116 | 117 | execute_process(COMMAND 118 | "${GIT_EXECUTABLE}" 119 | describe 120 | ${hash} 121 | ${ARGN} 122 | WORKING_DIRECTORY 123 | "${CMAKE_CURRENT_SOURCE_DIR}" 124 | RESULT_VARIABLE 125 | res 126 | OUTPUT_VARIABLE 127 | out 128 | ERROR_QUIET 129 | OUTPUT_STRIP_TRAILING_WHITESPACE) 130 | if(NOT res EQUAL 0) 131 | set(out "${out}-${res}-NOTFOUND") 132 | endif() 133 | 134 | set(${_var} "${out}" PARENT_SCOPE) 135 | endfunction() 136 | 137 | function(git_get_exact_tag _var) 138 | git_describe(out --exact-match ${ARGN}) 139 | set(${_var} "${out}" PARENT_SCOPE) 140 | endfunction() 141 | 142 | function(git_local_changes _var) 143 | if(NOT GIT_FOUND) 144 | find_package(Git QUIET) 145 | endif() 146 | get_git_head_revision(refspec hash) 147 | if(NOT GIT_FOUND) 148 | set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) 149 | return() 150 | endif() 151 | if(NOT hash) 152 | set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) 153 | return() 154 | endif() 155 | 156 | execute_process(COMMAND 157 | "${GIT_EXECUTABLE}" 158 | diff-index --quiet HEAD -- 159 | WORKING_DIRECTORY 160 | "${CMAKE_CURRENT_SOURCE_DIR}" 161 | RESULT_VARIABLE 162 | res 163 | OUTPUT_VARIABLE 164 | out 165 | ERROR_QUIET 166 | OUTPUT_STRIP_TRAILING_WHITESPACE) 167 | if(res EQUAL 0) 168 | set(${_var} "CLEAN" PARENT_SCOPE) 169 | else() 170 | set(${_var} "DIRTY" PARENT_SCOPE) 171 | endif() 172 | endfunction() 173 | -------------------------------------------------------------------------------- /cmake/GetGitRevisionDescription.cmake.in: -------------------------------------------------------------------------------- 1 | # 2 | # Internal file for GetGitRevisionDescription.cmake 3 | # 4 | # Requires CMake 2.6 or newer (uses the 'function' command) 5 | # 6 | # Original Author: 7 | # 2009-2010 Ryan Pavlik 8 | # http://academic.cleardefinition.com 9 | # Iowa State University HCI Graduate Program/VRAC 10 | # 11 | # Copyright Iowa State University 2009-2010. 12 | # Distributed under the Boost Software License, Version 1.0. 13 | # (See accompanying file LICENSE_1_0.txt or copy at 14 | # http://www.boost.org/LICENSE_1_0.txt) 15 | 16 | set(HEAD_HASH) 17 | 18 | file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) 19 | 20 | string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) 21 | if(HEAD_CONTENTS MATCHES "ref") 22 | # named branch 23 | string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") 24 | if(EXISTS "@GIT_DIR@/${HEAD_REF}") 25 | configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) 26 | else() 27 | configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) 28 | file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) 29 | if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") 30 | set(HEAD_HASH "${CMAKE_MATCH_1}") 31 | endif() 32 | endif() 33 | else() 34 | # detached HEAD 35 | configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) 36 | endif() 37 | 38 | if(NOT HEAD_HASH) 39 | file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) 40 | string(STRIP "${HEAD_HASH}" HEAD_HASH) 41 | endif() 42 | -------------------------------------------------------------------------------- /include/fymodem.h: -------------------------------------------------------------------------------- 1 | #ifndef _FYMODEM_H_ 2 | #define _FYMODEM_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | /** 10 | * Free YModem implementation. 11 | * 12 | * Fredrik Hederstierna 2014 13 | * 14 | * This file is in the public domain. 15 | * You can do whatever you want with it. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | /* max length of filename */ 30 | #define FYMODEM_FILE_NAME_MAX_LENGTH (64) 31 | 32 | /* receive file over ymodem */ 33 | int32_t fymodem_receive(uint8_t *rxdata, 34 | size_t rxsize, 35 | char filename[FYMODEM_FILE_NAME_MAX_LENGTH]); 36 | 37 | /* send file over ymodem */ 38 | int32_t fymodem_send(int fd, 39 | uint8_t *txdata, 40 | size_t txsize, 41 | const char *filename); 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /include/radio_tool/codeplug/codeplug.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | namespace radio_tool::codeplug 26 | { 27 | class CodeplugSupport 28 | { 29 | public: 30 | /** 31 | * Read a codeplug from disk 32 | */ 33 | virtual auto Read(const std::string&) -> void = 0; 34 | 35 | /** 36 | * Write a codeplug to disk 37 | */ 38 | virtual auto Write(const std::string&) const -> void = 0; 39 | 40 | /** 41 | * Get the codeplug data to write to a device 42 | */ 43 | virtual auto GetData() const -> const std::vector = 0; 44 | 45 | /** 46 | * Get some general info about the loaded codeplug 47 | */ 48 | virtual auto ToString() const -> const std::string = 0; 49 | }; 50 | } -------------------------------------------------------------------------------- /include/radio_tool/codeplug/codeplug_factory.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | namespace radio_tool::codeplug 28 | { 29 | /** 30 | * All codeplug handlers 31 | */ 32 | const std::vector, std::function()>>> AllCodeplugs = { 33 | {RDT::SupportsCodeplug, RDT::Create} 34 | }; 35 | 36 | class CodeplugFactory 37 | { 38 | public: 39 | static auto GetCodeplugHandler(const std::string &file) -> std::unique_ptr 40 | { 41 | for (const auto &try_this : AllCodeplugs) 42 | { 43 | if (try_this.first(file)) 44 | { 45 | return try_this.second(); 46 | } 47 | } 48 | 49 | return nullptr; 50 | } 51 | }; 52 | } // namespace radio_tool::codeplug -------------------------------------------------------------------------------- /include/radio_tool/codeplug/rdt.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace radio_tool::codeplug 29 | { 30 | class RDT : public CodeplugSupport { 31 | public: 32 | static auto SupportsCodeplug(const std::string &file) -> bool 33 | { 34 | std::ifstream file_test(file, std::ios_base::in | std::ios_base::binary); 35 | if(file_test.is_open()) 36 | { 37 | auto hdr = RDTHeader(); 38 | hdr.Read(file_test); 39 | file_test.close(); 40 | 41 | return hdr.Validate(); 42 | } 43 | return false; 44 | } 45 | 46 | static auto Create() -> std::unique_ptr 47 | { 48 | auto nInst = new RDT(); 49 | return std::unique_ptr(nInst); 50 | } 51 | 52 | auto Read(const std::string&) -> void override; 53 | auto Write(const std::string&) const -> void override; 54 | auto GetData() const -> const std::vector override; 55 | auto ToString() const -> const std::string override; 56 | private: 57 | RDTHeader header; 58 | time_t timestamp; 59 | RDTGeneral general; 60 | }; 61 | } -------------------------------------------------------------------------------- /include/radio_tool/codeplug/rdt_general.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | namespace radio_tool::codeplug 27 | { 28 | class RDTGeneral 29 | { 30 | public: 31 | std::u16string intro_line1; //10 32 | std::u16string intro_line2; //10 33 | //skip 24 34 | uint8_t flags_1; 35 | uint8_t flags_2; 36 | uint8_t flags_3; 37 | //skip 1 38 | uint8_t radio_id[3]; 39 | //skip 1 40 | uint8_t tx_preamble; 41 | uint8_t group_call_hang; 42 | uint8_t private_call_hang; 43 | uint8_t vox_level; 44 | //skip 2 45 | uint8_t rx_low_bat_interval; 46 | uint8_t call_alert_tone_duration; 47 | uint8_t lone_worker_response_time; 48 | uint8_t lone_worker_reminder_time; 49 | //skip 1 50 | uint8_t scan_digital_hang_time; 51 | uint8_t scan_analog_hang_time; 52 | uint8_t flags_4; 53 | uint8_t set_keypad_lock_time; 54 | uint8_t mode; 55 | uint32_t power_on_password; 56 | uint32_t radio_prog_password; 57 | uint8_t pc_prog_password[8]; 58 | //skip 8 59 | std::u16string radio_name; //16 60 | 61 | auto Read(std::ifstream &i) -> void 62 | { 63 | intro_line1.reserve(10); 64 | intro_line2.reserve(10); 65 | i.read((char*)intro_line1.data(), sizeof(char16_t) * 10); 66 | i.read((char*)intro_line2.data(), sizeof(char16_t) * 10); 67 | intro_line1.shrink_to_fit(); 68 | intro_line2.shrink_to_fit(); 69 | } 70 | 71 | auto ToString() const -> const std::wstring 72 | { 73 | std::basic_stringstream out; 74 | 75 | out 76 | << "Intro 1: " << std::wstring(intro_line1.begin(), intro_line1.end()) << std::endl 77 | << "Intro 2: " << std::wstring(intro_line2.begin(), intro_line2.end()); //<< std::endl; 78 | 79 | return out.str(); 80 | } 81 | }; 82 | } -------------------------------------------------------------------------------- /include/radio_tool/codeplug/rdt_header.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | using namespace std::literals::string_literals; 29 | 30 | namespace radio_tool::codeplug 31 | { 32 | const std::vector> RadioConfigs = { 33 | /* Radio, Timestamp, General */ 34 | { "DM-1701"s, 0x2001u, 0x2040u }, 35 | { "2017"s, 0x2001u, 0x2040u }, 36 | { "DR780"s, 0x2001u, 0x2040u } 37 | }; 38 | 39 | enum class RDTType : uint8_t 40 | { 41 | Unknown = 0, 42 | TYT = 1, 43 | Anytone = 2 44 | }; 45 | 46 | class RDTHeader 47 | { 48 | public: 49 | auto Read(std::ifstream& i) -> void 50 | { 51 | magic.resize(0x05); 52 | i.read((char*)magic.data(), 0x05); 53 | i.read((char*)&n0, sizeof(uint8_t)); 54 | i.read((char*)&channel_offset, sizeof(uint32_t)); 55 | i.read((char*)&n1, sizeof(uint8_t)); 56 | target.resize(0x06); 57 | i.read((char*)target.data(), 0x06); 58 | i.read((char*)&n2, sizeof(uint8_t)); 59 | i.read((char*)&n3, sizeof(uint32_t)); 60 | 61 | target_name.resize(0xff); 62 | i.read((char*)target_name.data(), 0xff); 63 | target_name.resize(strlen(target_name.c_str())); 64 | 65 | i.read((char*)&n4, sizeof(uint32_t)); 66 | i.read((char*)&n5, sizeof(uint32_t)); 67 | i.read((char*)&n6, sizeof(uint32_t)); 68 | i.read((char*)&n7, sizeof(uint32_t)); 69 | 70 | radio.resize(0x10); 71 | i.read((char*)radio.data(), 0x10); 72 | radio.resize(strlen(radio.c_str())); 73 | 74 | i.read((char*)nz, sizeof(uint32_t) * 0x3c); 75 | type = RDTType::TYT; 76 | } 77 | 78 | auto Validate() const -> bool 79 | { 80 | if("DfuSe"s != magic) 81 | { 82 | return false; 83 | } 84 | else if("Target"s != target) 85 | { 86 | return false; 87 | } 88 | return true; 89 | } 90 | 91 | auto GetTimestampOffset() const -> uint32_t 92 | { 93 | for(const auto& rx : RadioConfigs) 94 | { 95 | auto r = std::get<0>(rx); 96 | auto o = std::get<1>(rx); 97 | 98 | if(r == radio) 99 | { 100 | return o; 101 | } 102 | } 103 | return 0x2001u; //default 104 | } 105 | 106 | auto GetGeneralOffset() const -> uint32_t 107 | { 108 | for(const auto& rx : RadioConfigs) 109 | { 110 | auto r = std::get<0>(rx); 111 | auto o = std::get<2>(rx); 112 | 113 | if(r == radio) 114 | { 115 | return o; 116 | } 117 | } 118 | return 0x2040u; //default 119 | } 120 | 121 | RDTType type; 122 | std::string magic; //0x05 123 | uint8_t n0; 124 | uint32_t channel_offset; // +0x100 125 | uint8_t n1; 126 | std::string target; //0x06 127 | uint8_t n2; 128 | uint32_t n3; 129 | std::string target_name; // 0xff 130 | uint32_t n4; 131 | uint32_t n5; 132 | uint32_t n6; 133 | uint32_t n7; 134 | std::string radio; //0x10 135 | uint32_t nz[0x3c]; 136 | }; 137 | } -------------------------------------------------------------------------------- /include/radio_tool/device/ymodem_device.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace radio_tool::device 25 | { 26 | class YModemDevice 27 | { 28 | public: 29 | YModemDevice(const std::string& port, const std::string& filename); 30 | 31 | auto SetAddress(const uint32_t&) const -> void; 32 | auto Erase(const uint32_t& amount) const -> void; 33 | auto Write(const std::vector& data) const -> void; 34 | auto Read(const uint16_t& size) const->std::vector; 35 | auto Status() const -> const std::string; 36 | 37 | auto SetInterfaceAttribs(const uint32_t& speed, const int& parity) const -> int; 38 | auto GetFD() const -> const int& 39 | { 40 | return fd; 41 | } 42 | 43 | private: 44 | const std::string port, filename; 45 | int fd; 46 | }; 47 | } // namespace radio_tool::device -------------------------------------------------------------------------------- /include/radio_tool/dfu/dfu_exception.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | 23 | namespace radio_tool::dfu { 24 | class DFUException : public std::exception { 25 | public: 26 | DFUException(const std::string& str) 27 | : msg(str) { } 28 | 29 | auto what() const noexcept -> const char* { 30 | return msg.c_str(); 31 | } 32 | private: 33 | const std::string msg; 34 | }; 35 | } -------------------------------------------------------------------------------- /include/radio_tool/dfu/tyt_dfu.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | 22 | namespace radio_tool::dfu 23 | { 24 | /** 25 | * Custom radio commands starting with 0x91 26 | */ 27 | enum class TYTCommand : uint8_t 28 | { 29 | ProgrammingMode = 0x01, 30 | SetRTC = 0x02, 31 | Reboot = 0x05, 32 | FirmwareUpgrade = 0x31 33 | }; 34 | 35 | enum class TYTRegister : uint8_t 36 | { 37 | RadioInfo = 0x01, //Radio Model(16 bytes) + 16 bytes of something else 38 | R_02 = 0x02, //unknown (4 bytes) 39 | R_03 = 0x03, //unknown (24 bytes) 40 | R_04 = 0x04, //unknown (8 bytes) 41 | R_07 = 0x07, //unknown (16 bytes) 42 | RTC = 0x08, //Real time clock (7 bytes) 43 | }; 44 | 45 | class TYTDFU : public DFU 46 | { 47 | public: 48 | static const auto VID = 0x0483; 49 | static const auto PID = 0xdf11; 50 | 51 | static const auto CustomCommand = 0x91; 52 | static const auto RegisterCommand = 0xa2; 53 | static const auto RegisterSize = 1024; 54 | 55 | TYTDFU(libusb_device_handle* h) : DFU(h) {} 56 | 57 | /** 58 | * Get the radio model off the device 59 | */ 60 | auto IdentifyDevice() const->std::string; 61 | 62 | /** 63 | * Read some register off the device 64 | */ 65 | auto ReadRegister(const TYTRegister& reg) const->std::vector; 66 | 67 | /** 68 | * Gets the current time from the radio's RTC 69 | * This doesn't work during TX/RX 70 | */ 71 | auto GetTime() const->time_t; 72 | 73 | /** 74 | * Set the time on the radio to the current machine time 75 | */ 76 | auto SetTime() const -> void; 77 | 78 | /** 79 | * Reboot the device 80 | */ 81 | auto Reboot() const -> void; 82 | 83 | /** 84 | * Send a TYT Command to the device 85 | */ 86 | auto SendTYTCommand(const TYTCommand& cmd) const -> void; 87 | }; 88 | } // namespace radio_tool::dfu -------------------------------------------------------------------------------- /include/radio_tool/fw/ailunce_fw.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 Niccol� Izzo IU2KIN 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | namespace radio_tool::fw 26 | { 27 | class AilunceFW : public FirmwareSupport 28 | { 29 | public: 30 | AilunceFW() {} 31 | 32 | auto Read(const std::string& file) -> void override; 33 | auto Write(const std::string& file) -> void override; 34 | auto ToString() const->std::string override; 35 | auto Decrypt() -> void override; 36 | auto Encrypt() -> void override; 37 | auto SetRadioModel(const std::string&) -> void override; 38 | auto IsCompatible(const FirmwareSupport* Other) const -> bool override; 39 | 40 | /** 41 | * @note This is not the "firmware_model" which exists in the firmware header 42 | */ 43 | auto GetRadioModel() const -> const std::string override; 44 | 45 | /** 46 | * Tests a file if its a valid firmware file 47 | */ 48 | static auto SupportsFirmwareFile(const std::string& file) -> bool; 49 | 50 | /** 51 | * Tests if a radio model is supported by this firmware handler 52 | */ 53 | static auto SupportsRadioModel(const std::string& model) -> bool; 54 | 55 | /** 56 | * Create an instance of this class for the firmware factory 57 | */ 58 | static auto Create() -> std::unique_ptr 59 | { 60 | return std::make_unique(); 61 | } 62 | 63 | private: 64 | std::string radio_model; 65 | auto ApplyXOR() -> void; 66 | 67 | }; 68 | } // namespace radio_tool::fw 69 | -------------------------------------------------------------------------------- /include/radio_tool/fw/cipher/cs800.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | * 18 | * Some or all of this file is copied from CSFWTOOL 19 | * https://github.com/KG5RKI/CSFWTOOL 20 | */ 21 | #pragma once 22 | 23 | namespace radio_tool::fw::cipher 24 | { 25 | constexpr auto cs800_length = 0x100; 26 | 27 | /** 28 | * Connect Systems CS800 (Key=0x00) 29 | * https://github.com/KG5RKI/CSFWTOOL 30 | */ 31 | const unsigned char cs800_0[cs800_length] = { 32 | 0x60, 0x5e, 0x5d, 0x5c, 0x5a, 0x59, 0x36, 0x34, 0x33, 0x31, 0x30, 0x2e, 0x2d, 0x2b, 0x2a, 0x28, 33 | 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x75, 0x76, 0x77, 0x78, 0x78, 0x79, 34 | 0x07, 0x08, 0x09, 0x09, 0x0a, 0x0b, 0x7a, 0x04, 0x05, 0x06, 0x06, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 35 | 0x03, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x41, 0x42, 0x44, 0x45, 0x47, 36 | 0x0a, 0x09, 0x09, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x08, 0x07, 0x06, 0x06, 0x05, 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 38 | 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7d, 0x7c, 0x7c, 0x7b, 0x7b, 0x7a, 39 | 0x7a, 0x78, 0x77, 0x76, 0x72, 0x19, 0x18, 0x17, 0x16, 0x14, 0x13, 0x71, 0x70, 0x6f, 0x6e, 0x6d, 40 | 0x57, 0x56, 0x54, 0x53, 0x51, 0x50, 0x4e, 0x4d, 0x4b, 0x4a, 0x48, 0x47, 0x45, 0x44, 0x42, 0x41, 41 | 0x57, 0x59, 0x5a, 0x5c, 0x5d, 0x5e, 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x68, 0x6a, 0x6b, 42 | 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 43 | 0x1a, 0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x24, 0x25, 0x12, 0x13, 0x14, 0x16, 0x17, 0x18, 0x19, 44 | 0x27, 0x25, 0x24, 0x22, 0x75, 0x75, 0x79, 0x78, 0x74, 0x73, 0x21, 0x20, 0x1e, 0x1d, 0x1c, 0x1a, 45 | 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x53, 0x54, 0x56, 46 | 0x27, 0x28, 0x2a, 0x3a, 0x3c, 0x3d, 0x2b, 0x2d, 0x2e, 0x34, 0x36, 0x37, 0x39, 0x30, 0x31, 0x33, 47 | 0x3f, 0x6c, 0x6b, 0x6a, 0x68, 0x67, 0x3d, 0x3c, 0x3a, 0x39, 0x37, 0x66, 0x65, 0x64, 0x62, 0x61 48 | }; 49 | 50 | /** 51 | * Connect Systems CS800 (Key=0x01) 52 | * https://github.com/KG5RKI/CSFWTOOL 53 | */ 54 | const unsigned char cs800_1[cs800_length] = { 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 56 | 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x09, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 57 | 0x12, 0x13, 0x2e, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x24, 0x25, 58 | 0x57, 0x59, 0x5a, 0x5c, 0x5d, 0x5e, 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x68, 0x6a, 0x6b, 59 | 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x75, 0x76, 0x77, 0x78, 0x78, 0x79, 60 | 0x2d, 0x33, 0x42, 0x44, 0x45, 0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x37, 0x51, 0x37, 0x54, 0x56, 61 | 0x7a, 0x7a, 0x7b, 0x7b, 0x2b, 0x7c, 0x7d, 0x7d, 0x7d, 0x30, 0x7e, 0x30, 0x7e, 0x30, 0x7e, 0x7e, 62 | 0x7f, 0x7e, 0x28, 0x7e, 0x7e, 0x1d, 0x2b, 0x7e, 0x7d, 0x7d, 0x7d, 0x7c, 0x7c, 0x7b, 0x7b, 0x7a, 63 | 0x2b, 0x3c, 0x78, 0x3c, 0x77, 0x76, 0x3c, 0x75, 0x30, 0x73, 0x3a, 0x71, 0x70, 0x3a, 0x6e, 0x6d, 64 | 0x6c, 0x6b, 0x6a, 0x68, 0x67, 0x66, 0x65, 0x64, 0x62, 0x61, 0x60, 0x5e, 0x5d, 0x5c, 0x5a, 0x59, 65 | 0x57, 0x56, 0x54, 0x53, 0x51, 0x50, 0x4e, 0x4d, 0x4b, 0x4a, 0x48, 0x47, 0x45, 0x44, 0x42, 0x41, 66 | 0x3f, 0x3d, 0x3c, 0x3a, 0x39, 0x37, 0x36, 0x34, 0x33, 0x31, 0x30, 0x2e, 0x2d, 0x2b, 0x2a, 0x28, 67 | 0x27, 0x25, 0x24, 0x22, 0x21, 0x20, 0x1e, 0x1d, 0x1c, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x14, 0x13, 68 | 0x12, 0x3c, 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x09, 0x08, 0x07, 0x06, 0x3a, 0x05, 69 | 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 70 | 0x27, 0x28, 0x2a, 0x2b, 0x2d, 0x2e, 0x30, 0x31, 0x33, 0x34, 0x36, 0x37, 0x39, 0x3a, 0x3c, 0x3d 71 | }; 72 | 73 | } // namespace radio_tool::fw::cipher -------------------------------------------------------------------------------- /include/radio_tool/fw/cipher/dr5xx0.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | * 18 | * Some or all of this file is copied from CSFWTOOL 19 | * https://github.com/KG5RKI/CSFWTOOL 20 | */ 21 | #pragma once 22 | 23 | namespace radio_tool::fw::cipher 24 | { 25 | constexpr auto dr5xx0_length = 0x100; 26 | 27 | /** 28 | * Connect Systems DR5XX0 29 | * https://github.com/KG5RKI/CSFWTOOL 30 | */ 31 | const unsigned char dr5xx0[dr5xx0_length] = { 32 | 0x3F, 0x41, 0x42, 0x44, 0x45, 0x47, 0x48, 0x4A, 0x4B, 0x4D, 0x4E, 0x50, 0x51, 0x53, 0x54, 0x56, 33 | 0x57, 0x59, 0x5A, 0x5C, 0x5D, 0x5E, 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x68, 0x6A, 0x6B, 34 | 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x75, 0x76, 0x77, 0x78, 0x78, 0x79, 35 | 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 36 | 0x7F, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7D, 0x7D, 0x7C, 0x7C, 0x7B, 0x7B, 0x7A, 37 | 0x7A, 0x79, 0x78, 0x78, 0x77, 0x76, 0x75, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70, 0x6F, 0x6E, 0x6D, 38 | 0x6C, 0x6B, 0x6A, 0x68, 0x67, 0x66, 0x65, 0x64, 0x62, 0x61, 0x60, 0x5E, 0x5D, 0x5C, 0x5A, 0x59, 39 | 0x57, 0x56, 0x54, 0x53, 0x51, 0x50, 0x4E, 0x4D, 0x4B, 0x4A, 0x48, 0x47, 0x45, 0x44, 0x42, 0x41, 40 | 0x3F, 0x3D, 0x3C, 0x3A, 0x39, 0x37, 0x36, 0x34, 0x33, 0x31, 0x30, 0x2E, 0x2D, 0x2B, 0x2A, 0x28, 41 | 0x27, 0x25, 0x24, 0x22, 0x21, 0x20, 0x1E, 0x1D, 0x1C, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x14, 0x13, 42 | 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x09, 0x08, 0x07, 0x06, 0x06, 0x05, 43 | 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 45 | 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x09, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 46 | 0x12, 0x13, 0x14, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1C, 0x1D, 0x1E, 0x20, 0x21, 0x22, 0x24, 0x25, 47 | 0x27, 0x28, 0x2A, 0x2B, 0x2D, 0x2E, 0x30, 0x31, 0x33, 0x34, 0x36, 0x37, 0x39, 0x3A, 0x3C, 0x3D 48 | }; 49 | } // namespace radio_tool::fw::cipher -------------------------------------------------------------------------------- /include/radio_tool/fw/cipher/md9600.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | namespace radio_tool::fw::cipher 21 | { 22 | constexpr auto md9600_length = 1024; 23 | 24 | //md9600 fw encryption key 25 | // -KG5RKI 26 | const unsigned char md9600[md9600_length] = { 27 | 0xa2, 0xfa, 0xbb, 0x4b, 0x90, 0x8f, 0x17, 0x20, 0x96, 0x36, 0x43, 0x84, 0xf7, 0xac, 0x4e, 0x55, 28 | 0xea, 0xe5, 0xb4, 0x36, 0x55, 0xb9, 0x39, 0xe2, 0xd8, 0xda, 0x18, 0xc0, 0x0d, 0x09, 0x5d, 0xb8, 29 | 0x0e, 0x89, 0x90, 0x46, 0x38, 0xd4, 0x93, 0xcc, 0x2f, 0x8e, 0xcd, 0x2d, 0x22, 0xb7, 0x89, 0x97, 30 | 0x51, 0x24, 0x98, 0xa0, 0xcc, 0x30, 0x3e, 0x95, 0x7d, 0xaf, 0x4c, 0x0e, 0x68, 0x23, 0x89, 0xc6, 31 | 0x32, 0x33, 0x56, 0xaa, 0xe0, 0x58, 0x92, 0x30, 0xe2, 0xda, 0xbc, 0xea, 0x50, 0xfb, 0x57, 0x5b, 32 | 0x73, 0x71, 0x93, 0x09, 0x87, 0x1a, 0x29, 0xd3, 0xbf, 0xec, 0x87, 0x85, 0x8a, 0x2b, 0x2d, 0xaa, 33 | 0x15, 0xde, 0x57, 0xa2, 0x11, 0x83, 0xdc, 0xf4, 0xb6, 0x02, 0x56, 0xe5, 0x08, 0xe0, 0x83, 0x49, 34 | 0x59, 0xb5, 0xeb, 0x99, 0x0f, 0xe0, 0xc3, 0x46, 0xa7, 0x79, 0x12, 0x4d, 0xfa, 0x87, 0x12, 0x0c, 35 | 0xbf, 0x73, 0xd9, 0x53, 0x52, 0xbd, 0x38, 0xbf, 0xb4, 0xee, 0xe4, 0x43, 0xd2, 0xce, 0xd3, 0x08, 36 | 0x0a, 0xd6, 0xe9, 0x77, 0xeb, 0xe8, 0xd4, 0x94, 0x3c, 0x3e, 0x35, 0x8d, 0x40, 0xa1, 0x00, 0x92, 37 | 0x39, 0xdb, 0x25, 0xe8, 0x2b, 0x6e, 0x70, 0x39, 0xe2, 0x86, 0xad, 0x2f, 0x36, 0x2d, 0x11, 0x41, 38 | 0x8e, 0xbe, 0xd5, 0xcc, 0xa3, 0x9c, 0x24, 0x65, 0x87, 0x23, 0x37, 0x6e, 0xe5, 0xdf, 0xbf, 0xe7, 39 | 0x8a, 0xfc, 0x83, 0x87, 0x24, 0xfe, 0x4a, 0x0b, 0x4a, 0xb3, 0xfb, 0xcf, 0xbd, 0x65, 0x03, 0x9b, 40 | 0xee, 0x53, 0xf7, 0xbf, 0xc0, 0x63, 0x7a, 0x62, 0x8e, 0x11, 0x62, 0x17, 0x70, 0xab, 0x16, 0xb1, 41 | 0xba, 0xc0, 0x3a, 0x59, 0xc6, 0xd6, 0x8f, 0xdd, 0xf4, 0x5b, 0x14, 0x4b, 0xee, 0xde, 0x72, 0xbf, 42 | 0x31, 0x7f, 0x96, 0x79, 0xc9, 0xa4, 0xa0, 0x32, 0x5b, 0xee, 0xfc, 0xb0, 0x69, 0x6c, 0xce, 0x99, 43 | 0xd2, 0x0e, 0x94, 0x85, 0x98, 0x5c, 0x07, 0x56, 0xe6, 0x67, 0x41, 0xcc, 0x52, 0x00, 0x25, 0x54, 44 | 0x5f, 0x29, 0xfc, 0x21, 0x46, 0xc9, 0x5c, 0x7e, 0xf6, 0xa4, 0x4e, 0x63, 0x59, 0x89, 0xaf, 0x46, 45 | 0xd9, 0xcd, 0xd7, 0x33, 0x23, 0xf9, 0x79, 0x1f, 0x2a, 0xc0, 0xca, 0x7a, 0x6f, 0x34, 0xe6, 0x03, 46 | 0x81, 0x39, 0x6f, 0xe0, 0xbf, 0x39, 0x77, 0xee, 0x65, 0x19, 0xa0, 0x56, 0xc7, 0x6c, 0x81, 0x61, 47 | 0xd7, 0xe7, 0x4c, 0x8d, 0xed, 0x15, 0xae, 0xe0, 0xc8, 0x4c, 0xf7, 0x7c, 0xd0, 0xe0, 0x7b, 0x74, 48 | 0x9d, 0x96, 0x38, 0xde, 0xbd, 0x5c, 0xb9, 0x29, 0xb2, 0x37, 0x3a, 0xb1, 0x3b, 0x7c, 0x0c, 0x91, 49 | 0xd5, 0x43, 0x3b, 0xb8, 0x80, 0x19, 0x6f, 0x40, 0xc6, 0xf5, 0x10, 0xfb, 0xfa, 0x6e, 0xad, 0x4e, 50 | 0xbe, 0x2a, 0x9f, 0x42, 0xc7, 0x9a, 0xe9, 0xd8, 0xe5, 0xe4, 0x63, 0x9d, 0x3d, 0x21, 0x18, 0x7f, 51 | 0xd9, 0xc9, 0xec, 0xdf, 0x64, 0x6b, 0x82, 0xe7, 0x2e, 0xa2, 0x5c, 0x1e, 0x77, 0x44, 0x44, 0x39, 52 | 0xe9, 0xdc, 0xeb, 0x35, 0x66, 0x5b, 0xd1, 0xa2, 0x04, 0x0a, 0x64, 0x42, 0x56, 0xc3, 0x6c, 0xd2, 53 | 0xee, 0x61, 0xa6, 0x28, 0x1f, 0x75, 0xaf, 0x7e, 0x08, 0x3b, 0x24, 0x0e, 0xcd, 0xcc, 0x08, 0xdf, 54 | 0x28, 0x94, 0x66, 0xde, 0x21, 0x07, 0x37, 0x30, 0x19, 0x90, 0x85, 0xc7, 0x0d, 0xca, 0xd1, 0x33, 55 | 0x19, 0xf3, 0xb3, 0xbb, 0x3b, 0x9e, 0xc0, 0xad, 0x5a, 0xa7, 0xb0, 0xf2, 0x87, 0x6c, 0xc1, 0xe5, 56 | 0x82, 0x3a, 0x56, 0x66, 0x80, 0x06, 0xe4, 0x29, 0x2b, 0x5e, 0x0e, 0x54, 0xeb, 0x9f, 0x0f, 0x4a, 57 | 0x64, 0x67, 0x59, 0xc1, 0x40, 0x4d, 0x7b, 0x1b, 0x2e, 0xd0, 0x48, 0xf3, 0x2a, 0x8e, 0x36, 0xf6, 58 | 0x00, 0xb7, 0x04, 0xf4, 0x0b, 0xc0, 0xa0, 0x36, 0x43, 0x5c, 0x47, 0x13, 0x77, 0xa8, 0xee, 0xbe, 59 | 0xd6, 0xa5, 0xe1, 0x62, 0xb4, 0xec, 0xaa, 0x71, 0x8b, 0x9d, 0x34, 0x39, 0x40, 0x99, 0x30, 0xb8, 60 | 0xa8, 0xf1, 0xb8, 0xb1, 0x4b, 0x9e, 0x32, 0xff, 0x68, 0x72, 0x78, 0x2a, 0x39, 0x4e, 0x36, 0x38, 61 | 0x77, 0x96, 0x93, 0xc5, 0x21, 0xe2, 0x13, 0x56, 0x7a, 0xf6, 0xbb, 0xeb, 0x51, 0xf5, 0x77, 0xd3, 62 | 0x84, 0xd1, 0xba, 0xc4, 0xc7, 0x06, 0x64, 0x2b, 0xa2, 0x88, 0xe8, 0xc1, 0xb9, 0xf9, 0xae, 0x5f, 63 | 0x50, 0x20, 0xb6, 0x13, 0x0e, 0x97, 0x7f, 0x73, 0x01, 0xc3, 0x27, 0x31, 0xe3, 0x09, 0xd3, 0xf0, 64 | 0x9c, 0x3f, 0x51, 0x56, 0x07, 0x61, 0xfc, 0x63, 0xf9, 0x86, 0xe0, 0x01, 0x80, 0x12, 0x1f, 0xdc, 65 | 0x68, 0x2c, 0x94, 0x73, 0x04, 0x73, 0xb5, 0x70, 0x2b, 0xec, 0xbe, 0x34, 0x80, 0x3f, 0x0c, 0xb7, 66 | 0xf6, 0x24, 0xc6, 0x8f, 0x94, 0x18, 0xc3, 0x4e, 0x76, 0x54, 0xa8, 0x11, 0x15, 0xff, 0x51, 0x56, 67 | 0xc8, 0xa3, 0x73, 0x0e, 0x8a, 0xde, 0x7f, 0xf4, 0xfd, 0x5a, 0xc9, 0x1c, 0xaf, 0xfe, 0xe9, 0xcf, 68 | 0x9c, 0x66, 0x61, 0x96, 0xf5, 0x91, 0x81, 0x95, 0x20, 0xda, 0x88, 0x1a, 0x00, 0x2a, 0x0c, 0x76, 69 | 0x76, 0x6b, 0x9c, 0x0c, 0x28, 0x40, 0xa3, 0xa7, 0x81, 0xf3, 0x8f, 0x11, 0xf9, 0xaf, 0x33, 0xe1, 70 | 0x96, 0xef, 0x6a, 0x94, 0xb2, 0x36, 0xfe, 0xdf, 0x00, 0x01, 0xc8, 0x44, 0xca, 0xf9, 0x18, 0xe4, 71 | 0x7c, 0x6e, 0x57, 0x94, 0x66, 0x01, 0xea, 0x32, 0xbe, 0xa0, 0x5a, 0x3a, 0xe4, 0xb8, 0xb2, 0x94, 72 | 0xea, 0xa5, 0x29, 0xb0, 0x54, 0x6e, 0x01, 0xd5, 0x1c, 0xaf, 0xaf, 0xb6, 0xfa, 0xd6, 0x3c, 0x47, 73 | 0xe2, 0x92, 0xeb, 0xce, 0xcd, 0x89, 0x1c, 0x3d, 0xbc, 0x4a, 0x70, 0xbf, 0xfa, 0x82, 0x2e, 0x91, 74 | 0xa2, 0x72, 0xe6, 0x13, 0x62, 0xa0, 0x54, 0x1f, 0x7e, 0xcd, 0x86, 0x99, 0x18, 0x28, 0x41, 0x47, 75 | 0xae, 0xc1, 0xa2, 0xe3, 0xe4, 0x40, 0x01, 0x6f, 0x84, 0xd7, 0x1a, 0xc9, 0xc3, 0x75, 0x6f, 0x7f, 76 | 0xc6, 0x3d, 0xe8, 0xe4, 0x64, 0x36, 0xbd, 0x64, 0x2e, 0x44, 0x95, 0x14, 0xac, 0x57, 0xf0, 0x8d, 77 | 0xea, 0xe2, 0xc2, 0xfb, 0x33, 0x8f, 0x60, 0x71, 0x1d, 0x31, 0xa0, 0x80, 0xc6, 0xf9, 0x3c, 0x07, 78 | 0x5c, 0xee, 0x78, 0x4c, 0xe3, 0x97, 0x05, 0x4c, 0x32, 0xfa, 0x24, 0x50, 0x3f, 0xcb, 0x0f, 0xc1, 79 | 0x9d, 0xdd, 0x94, 0x3d, 0x43, 0xdc, 0x03, 0xea, 0x8f, 0x3e, 0x4a, 0x0b, 0x8b, 0x77, 0x5f, 0xd1, 80 | 0x6e, 0x6c, 0xde, 0x73, 0x66, 0x2b, 0xf4, 0x81, 0x94, 0xd9, 0x7b, 0x75, 0x58, 0xeb, 0x66, 0x8b, 81 | 0xd0, 0x9a, 0x60, 0xd2, 0x9b, 0x90, 0xb0, 0x83, 0xe3, 0xe8, 0x60, 0x92, 0x9a, 0x55, 0x9e, 0x84, 82 | 0x03, 0xa1, 0x62, 0x80, 0x75, 0x5a, 0x51, 0xa8, 0x5c, 0xc8, 0xe2, 0xaa, 0x80, 0x21, 0xbf, 0x91, 83 | 0x8a, 0x00, 0x6e, 0xe2, 0xc4, 0x14, 0x30, 0xe4, 0x20, 0x15, 0x29, 0x3f, 0x7c, 0xfd, 0xc2, 0xc8, 84 | 0x24, 0x74, 0x4c, 0x9c, 0x98, 0x8c, 0xe6, 0x6c, 0x90, 0xae, 0xa0, 0x17, 0x3e, 0xd5, 0xe0, 0x7e, 85 | 0xd3, 0xf9, 0x05, 0x94, 0x44, 0xcf, 0x4b, 0xb4, 0x4e, 0xaf, 0xee, 0x38, 0xb8, 0xd5, 0x93, 0x47, 86 | 0xd8, 0xcd, 0xe3, 0xee, 0x58, 0x29, 0x79, 0x72, 0x3a, 0x75, 0xfe, 0xe5, 0x1a, 0x6d, 0x92, 0xf8, 87 | 0xb3, 0x6d, 0x6e, 0x10, 0xa5, 0x28, 0xc8, 0x9c, 0x76, 0x9d, 0xf7, 0xa5, 0xd6, 0x47, 0xd8, 0xa6, 88 | 0x27, 0x94, 0x70, 0x9f, 0x3c, 0x99, 0xd3, 0x65, 0x61, 0x04, 0x44, 0x3c, 0x9c, 0x52, 0x9d, 0xa7, 89 | 0x33, 0x42, 0xf2, 0x7f, 0x6e, 0x89, 0x71, 0x43, 0x9e, 0xc7, 0x8c, 0xaf, 0x5e, 0xba, 0x5b, 0x90, 90 | 0x19, 0xb1, 0x3b, 0xd6, 0xcd, 0x44, 0xbc, 0xeb, 0x0e, 0x43, 0xba, 0x43, 0x4d, 0xec, 0xc9, 0x35 91 | }; 92 | } // namespace radio_tool::fw::cipher -------------------------------------------------------------------------------- /include/radio_tool/fw/cipher/uv3x0.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | namespace radio_tool::fw::cipher 21 | { 22 | constexpr auto uv3x0_length = 1024; 23 | 24 | const unsigned char uv3x0[uv3x0_length] = { 25 | 0x00, 0xaa, 0x89, 0x89, 0x1f, 0x4b, 0xec, 0xcf, 0x42, 0x45, 0x14, 0x54, 0x00, 0x65, 0xeb, 0x66, 26 | 0x41, 0x7d, 0x4c, 0x88, 0x49, 0x5a, 0x21, 0x0d, 0xf2, 0xf5, 0xc8, 0xe6, 0x38, 0xed, 0xbc, 0xb9, 27 | 0xfb, 0x35, 0x71, 0x33, 0x01, 0x0a, 0x7f, 0x9e, 0x3b, 0x29, 0x03, 0xb6, 0x49, 0x3e, 0x42, 0xb8, 28 | 0x3f, 0x9f, 0x90, 0xbd, 0xaa, 0x3a, 0x71, 0x46, 0xce, 0xcd, 0xfd, 0x18, 0x32, 0x55, 0x89, 0x4a, 29 | 0x5f, 0xc8, 0x83, 0x9c, 0xe4, 0x06, 0x9e, 0x0a, 0x9d, 0x0d, 0x2f, 0xa1, 0x35, 0x6d, 0xd7, 0x92, 30 | 0xea, 0xfd, 0x63, 0x85, 0x90, 0xcb, 0xf0, 0x2f, 0xd9, 0x59, 0x53, 0x27, 0xd3, 0x06, 0xb8, 0xf5, 31 | 0xb2, 0xca, 0x88, 0x6c, 0xd0, 0x26, 0x91, 0x3b, 0xf2, 0x5b, 0x61, 0xbe, 0xcd, 0xdb, 0xf2, 0x1a, 32 | 0xc9, 0xfd, 0x8d, 0x88, 0x04, 0xf4, 0xe8, 0xf1, 0x9a, 0x02, 0x92, 0xbc, 0x24, 0xe9, 0x90, 0xe4, 33 | 0x7e, 0xa3, 0x49, 0x4d, 0xce, 0x52, 0x9f, 0x58, 0xc1, 0x7a, 0x5f, 0xb5, 0x18, 0x6e, 0xdb, 0x78, 34 | 0x64, 0x08, 0xd5, 0x6f, 0x0d, 0x9d, 0x9f, 0xb3, 0x99, 0x30, 0x81, 0x7e, 0x2b, 0xe6, 0x5b, 0x3c, 35 | 0x4a, 0xba, 0x8b, 0xe5, 0xe4, 0x72, 0x11, 0x89, 0x93, 0xd2, 0xf1, 0x2d, 0x1e, 0x0f, 0xd9, 0xd5, 36 | 0x43, 0x87, 0x04, 0xe2, 0xb4, 0xae, 0x5e, 0x9e, 0x5f, 0x4c, 0xe9, 0x16, 0xf2, 0xe6, 0x5f, 0x28, 37 | 0x9f, 0x79, 0x19, 0xdc, 0x1d, 0x6f, 0x2f, 0xf8, 0xef, 0xcb, 0xe1, 0xce, 0xe8, 0xa7, 0x36, 0x59, 38 | 0xef, 0xe0, 0xe2, 0x88, 0x00, 0x10, 0x6d, 0xda, 0x73, 0xbc, 0x92, 0x2b, 0x81, 0xcf, 0xe6, 0xce, 39 | 0x04, 0x47, 0xba, 0xdb, 0x7e, 0x2f, 0x41, 0xca, 0x5d, 0xcd, 0xf6, 0x41, 0x7d, 0x1c, 0x38, 0x2b, 40 | 0xef, 0x7d, 0x37, 0x0a, 0xf9, 0xa9, 0x14, 0x8e, 0x5d, 0xea, 0x44, 0x66, 0xde, 0x8b, 0x36, 0x56, 41 | 0x01, 0x8c, 0x35, 0x8a, 0x11, 0x9b, 0x8f, 0x2a, 0x65, 0x40, 0xf7, 0x2e, 0xe6, 0x58, 0x28, 0x74, 42 | 0xcb, 0xc4, 0xcb, 0x0f, 0xa7, 0x62, 0x9b, 0xe3, 0xa6, 0x3c, 0xc7, 0x6f, 0x13, 0x00, 0x97, 0xe9, 43 | 0x1e, 0xb1, 0x53, 0x90, 0xdd, 0x9b, 0x61, 0x3e, 0x90, 0x8c, 0xad, 0x3c, 0x29, 0x41, 0x4e, 0x5b, 44 | 0x0c, 0x1f, 0x66, 0x40, 0x13, 0x24, 0x49, 0x00, 0xd5, 0x1c, 0xe2, 0xed, 0x28, 0x18, 0x53, 0xaf, 45 | 0xe4, 0x1c, 0xdc, 0x96, 0xea, 0x18, 0xfe, 0x2e, 0x65, 0x19, 0xe0, 0x14, 0x50, 0xc1, 0xf1, 0x09, 46 | 0x39, 0xf5, 0xcf, 0x45, 0x44, 0xd5, 0x68, 0x0d, 0x72, 0xf1, 0x5f, 0x88, 0x23, 0xb9, 0xb1, 0xcf, 47 | 0xda, 0x36, 0x98, 0x43, 0x41, 0xf8, 0xaf, 0x23, 0x6d, 0x50, 0x57, 0x5e, 0x62, 0xbf, 0x5a, 0xa5, 48 | 0xda, 0xad, 0xcf, 0xc5, 0x42, 0x5e, 0x3e, 0x34, 0x06, 0x23, 0x04, 0xe9, 0x0e, 0xcd, 0xf8, 0x71, 49 | 0x89, 0x67, 0x4e, 0x40, 0xe9, 0x25, 0xbc, 0x45, 0x2e, 0x97, 0xdc, 0xc1, 0x68, 0x22, 0xd2, 0x58, 50 | 0x77, 0xb1, 0x2e, 0x69, 0x16, 0xa8, 0x14, 0x9b, 0x18, 0x1a, 0x9a, 0xb8, 0xf0, 0x3b, 0x71, 0xbf, 51 | 0x77, 0x18, 0xc8, 0x34, 0xea, 0x85, 0x6d, 0xbb, 0x32, 0x57, 0x35, 0xe5, 0x69, 0xd4, 0x9f, 0x4a, 52 | 0x99, 0x68, 0xb4, 0xd8, 0xc7, 0x9a, 0x31, 0x6a, 0x30, 0x3d, 0xe8, 0x9c, 0xd2, 0xeb, 0x64, 0xde, 53 | 0x2e, 0xaf, 0xcc, 0xc8, 0x4d, 0x02, 0x09, 0xae, 0x01, 0xf9, 0x2b, 0x73, 0x6d, 0xbc, 0x09, 0xa2, 54 | 0xc7, 0x3a, 0x28, 0xba, 0x5d, 0x1b, 0xdf, 0xca, 0xd6, 0xf6, 0xb8, 0x3e, 0xbb, 0xc5, 0x18, 0xf9, 55 | 0x36, 0x96, 0x23, 0xa4, 0x19, 0x83, 0xda, 0x45, 0x21, 0xe3, 0x86, 0x13, 0x7d, 0xc2, 0x5a, 0x89, 56 | 0x8a, 0x8f, 0x54, 0xb9, 0xe1, 0x15, 0x64, 0xe3, 0x93, 0xad, 0xd0, 0x46, 0xb3, 0xb1, 0xd7, 0x36, 57 | 0x15, 0x33, 0x95, 0x6f, 0x56, 0xef, 0x26, 0xa9, 0x1c, 0x7f, 0x0e, 0x6c, 0x9f, 0xce, 0xd8, 0x26, 58 | 0x69, 0xcf, 0xfe, 0x7b, 0x5a, 0x6f, 0x09, 0xdc, 0xee, 0xc8, 0xf9, 0x5b, 0xc3, 0x97, 0xe7, 0xbd, 59 | 0x55, 0xf0, 0xe9, 0xd1, 0x0c, 0x30, 0x36, 0x01, 0x7a, 0x34, 0x8b, 0x27, 0xdd, 0xc8, 0xcd, 0xa2, 60 | 0xec, 0x62, 0xef, 0xa8, 0xd0, 0x11, 0x16, 0xdd, 0x70, 0xb0, 0xfb, 0x25, 0xf1, 0x5f, 0x91, 0xb7, 61 | 0x7d, 0x34, 0xe9, 0x74, 0x44, 0x2d, 0x52, 0x76, 0xc1, 0x69, 0xc4, 0xeb, 0x3f, 0x98, 0x7f, 0x24, 62 | 0x9b, 0xb1, 0xef, 0xe9, 0x4b, 0xe3, 0xd3, 0x10, 0x9f, 0xcd, 0x9e, 0x4e, 0x47, 0xf1, 0x1d, 0x4c, 63 | 0x16, 0x66, 0x5b, 0xfd, 0x06, 0xce, 0xc2, 0x30, 0x7b, 0x88, 0x82, 0x61, 0xcc, 0x27, 0x37, 0xd5, 64 | 0xff, 0x22, 0xc6, 0xe6, 0xd4, 0xcc, 0x87, 0x9b, 0x06, 0x87, 0xaa, 0x7b, 0xcd, 0x35, 0xd3, 0xa3, 65 | 0xa7, 0xf0, 0x08, 0x17, 0x58, 0xfb, 0xcd, 0x56, 0x2f, 0xf8, 0x8d, 0x31, 0x8c, 0x5b, 0x3c, 0xdc, 66 | 0x9f, 0x1e, 0x3b, 0x46, 0x72, 0xb7, 0x7c, 0xa6, 0x2a, 0x47, 0xe6, 0x56, 0x8a, 0x14, 0xfb, 0xe5, 67 | 0xb8, 0x39, 0xb8, 0x68, 0x44, 0x9c, 0xbc, 0x10, 0x66, 0x21, 0xad, 0x02, 0x87, 0x1d, 0xd8, 0x62, 68 | 0x03, 0x0e, 0x17, 0xb1, 0x2e, 0x89, 0xf8, 0x5a, 0x95, 0x73, 0x1b, 0x87, 0x86, 0x74, 0xdc, 0x39, 69 | 0xd2, 0xa9, 0x32, 0x98, 0xd1, 0x99, 0xd7, 0x88, 0xa7, 0x6b, 0xaa, 0x7c, 0xc6, 0x56, 0x51, 0x8f, 70 | 0xb4, 0x58, 0x22, 0xd1, 0x0f, 0x2b, 0x44, 0xde, 0xce, 0x75, 0x11, 0xb6, 0xc9, 0x3f, 0xbf, 0xc8, 71 | 0x7c, 0xa8, 0x40, 0x50, 0x07, 0xda, 0x66, 0xe3, 0x7a, 0x3e, 0x4b, 0x48, 0x50, 0xec, 0xf0, 0x8a, 72 | 0x39, 0x66, 0x24, 0x4b, 0x1d, 0x85, 0xa8, 0x5b, 0x5d, 0xb3, 0x90, 0x8a, 0x5c, 0x5b, 0xec, 0xba, 73 | 0x3e, 0x9e, 0xa8, 0x38, 0xef, 0x48, 0xb1, 0x4c, 0x67, 0x02, 0x59, 0x0e, 0x2d, 0xc9, 0xfd, 0x7c, 74 | 0x1a, 0x9e, 0xe5, 0xca, 0x60, 0x7f, 0x6b, 0xf9, 0xcb, 0x97, 0x60, 0xab, 0x46, 0xb2, 0xab, 0x36, 75 | 0xa0, 0xf3, 0x33, 0xf7, 0x90, 0xc9, 0x00, 0xe9, 0xf7, 0x1f, 0x9d, 0x75, 0x66, 0xd3, 0xc0, 0x8c, 76 | 0xe0, 0x6a, 0x2c, 0xf4, 0xe1, 0x02, 0xd7, 0xdf, 0x9e, 0x87, 0x48, 0xc2, 0x8f, 0x2a, 0x44, 0x64, 77 | 0x2b, 0x0f, 0xa9, 0x36, 0xf3, 0x46, 0x9a, 0xe2, 0xb1, 0xfd, 0xdc, 0x26, 0x02, 0xf4, 0x80, 0xe3, 78 | 0x12, 0x31, 0xc3, 0x71, 0xa7, 0xf4, 0x32, 0x36, 0x61, 0xed, 0x12, 0x77, 0x40, 0xad, 0xfe, 0x6d, 79 | 0x66, 0x5b, 0xd2, 0x9c, 0x1e, 0xa8, 0xc8, 0x60, 0x1e, 0x04, 0xe1, 0xc9, 0x09, 0x13, 0x87, 0xa8, 80 | 0x38, 0x5a, 0x70, 0xea, 0xba, 0x3f, 0xc5, 0x25, 0x99, 0x30, 0x84, 0x71, 0x5f, 0x22, 0x23, 0x79, 81 | 0xd9, 0x3d, 0x76, 0xd2, 0x1b, 0xd5, 0xd2, 0x8b, 0xc4, 0x9d, 0x73, 0x05, 0x84, 0x17, 0x1b, 0x04, 82 | 0xdb, 0x4f, 0xfc, 0x07, 0x23, 0xc9, 0xd8, 0xd5, 0xd0, 0xb8, 0x67, 0x59, 0xf7, 0x70, 0xf9, 0xaf, 83 | 0x0d, 0x1e, 0x5c, 0x7f, 0xf2, 0xb7, 0x00, 0x8a, 0x2d, 0x2e, 0x59, 0x82, 0x7a, 0xea, 0x85, 0x1f, 84 | 0x82, 0x77, 0x2f, 0x6f, 0xe9, 0x7c, 0xb3, 0x6e, 0x8d, 0xed, 0x82, 0xd6, 0x0d, 0x81, 0xc9, 0x38, 85 | 0x89, 0x67, 0x4d, 0x4c, 0xa9, 0x35, 0x99, 0x86, 0xe1, 0x21, 0x5c, 0xe9, 0xf3, 0x73, 0x0d, 0x20, 86 | 0xb5, 0x3a, 0xd0, 0xcb, 0x14, 0x3e, 0x9d, 0x17, 0x59, 0x37, 0x9f, 0x91, 0xab, 0x3c, 0xda, 0x3c, 87 | 0xd5, 0x7e, 0x11, 0xe0, 0x4a, 0x36, 0xe7, 0xa6, 0x66, 0xdc, 0x44, 0xe2, 0xf7, 0x9a, 0xfa, 0x30, 88 | 0xfc, 0x00, 0xa9, 0xc2, 0xad, 0xf9, 0xe0, 0xf8, 0xbb, 0xfe, 0x84, 0x31, 0xd8, 0x89, 0x76, 0xe2, 89 | }; 90 | } -------------------------------------------------------------------------------- /include/radio_tool/fw/cs_fw.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | * 18 | * Some or all of this file is copied from CSFWTOOL 19 | * https://github.com/KG5RKI/CSFWTOOL 20 | */ 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | 27 | namespace radio_tool::fw 28 | { 29 | typedef struct 30 | { 31 | uint32_t baseaddr_offset; // 0x00 - 0x08000000 + this (0x20000 or 0x10000 usually), 0 if spi flash data 32 | uint32_t unkaddr1; // 0x04 - 0 33 | uint32_t unkaddr2; // 0x08 - 0 34 | uint32_t rsrc_size; // 0x0C - 0 if image bin, size if spi flash data (ex. 0x00069010 for RCDB) 35 | uint32_t unksize1; // 0x10 - 0 36 | uint32_t imagesize; // 0x14 - total image data size is this + imageHeaderSize 37 | uint8_t padding1[0x24]; // 0x18 38 | uint32_t rsrcHeaderSize; // 0x3C - 0x80 if spi data, 0 if image data 39 | uint32_t unkHeaderSize; // 0x40 - 0 40 | uint32_t imageHeaderSize; // 0x44 - 0x80 41 | uint8_t padding2[0x24]; // 0x48 42 | uint32_t version; // 0x6C - 0x00000001 usually 43 | uint8_t resv[0x10]; // 0x70 44 | } CS800D_header; // total size 0x80 45 | static_assert(sizeof(CS800D_header) == 0x80); 46 | 47 | class CSFW : public FirmwareSupport 48 | { 49 | public: 50 | auto Read(const std::string &fw) -> void override; 51 | auto Write(const std::string &fw) -> void override; 52 | auto ToString() const -> std::string override; 53 | auto GetRadioModel() const -> const std::string override; 54 | auto SetRadioModel(const std::string&) -> void override; 55 | auto Decrypt() -> void override; 56 | auto Encrypt() -> void override; 57 | auto IsCompatible(const FirmwareSupport* Other) const -> bool override; 58 | 59 | /** 60 | * Tests a file if its a valid firmware file 61 | */ 62 | static auto SupportsFirmwareFile(const std::string &file) -> bool; 63 | 64 | static auto SupportsRadioModel(const std::string &model) -> bool; 65 | 66 | /** 67 | * Create an instance of this class for the firmware factory 68 | */ 69 | static auto Create() -> std::unique_ptr 70 | { 71 | return std::make_unique(); 72 | } 73 | private: 74 | CS800D_header header; 75 | uint16_t checksum; 76 | 77 | auto MakeChecksum() const -> uint16_t; 78 | auto MakeFiledata() const -> std::vector; 79 | auto UpdateHeader() -> void; 80 | }; 81 | } // namespace radio_tool::fw -------------------------------------------------------------------------------- /include/radio_tool/fw/fw.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace radio_tool::fw 26 | { 27 | class FirmwareSegment 28 | { 29 | public: 30 | FirmwareSegment(const uint16_t& idx, const uint32_t& addr, const uint32_t& size, const std::vector::const_iterator& begin, const std::vector::const_iterator& end) 31 | : index(idx), address(addr), size(size), data(begin, end) 32 | { 33 | } 34 | 35 | /** 36 | * Index of the segment 37 | */ 38 | const uint16_t index; 39 | 40 | /** 41 | * The address the segment should be written to on the device 42 | */ 43 | const uint32_t address; 44 | 45 | /** 46 | * The size of the data segment 47 | */ 48 | const uint32_t size; 49 | 50 | /** 51 | * A copy of the data from the firwmare file 52 | */ 53 | const std::vector data; 54 | }; 55 | 56 | class FirmwareSupport 57 | { 58 | public: 59 | virtual ~FirmwareSupport() = default; 60 | 61 | /** 62 | * Read the firmware file from disk 63 | */ 64 | virtual auto Read(const std::string& fw) -> void = 0; 65 | 66 | /** 67 | * Write the firmware file to disk 68 | */ 69 | virtual auto Write(const std::string& fw) -> void = 0; 70 | 71 | /** 72 | * Returns general info about the firmware file 73 | */ 74 | virtual auto ToString() const->std::string = 0; 75 | 76 | /** 77 | * Returns the radio model this firmware file is for 78 | */ 79 | virtual auto GetRadioModel() const -> const std::string = 0; 80 | 81 | /** 82 | * Set the radio model this firmware file is for 83 | */ 84 | virtual auto SetRadioModel(const std::string&) -> void = 0; 85 | 86 | /** 87 | * Decrypt the firmware data 88 | */ 89 | virtual auto Decrypt() -> void = 0; 90 | 91 | /** 92 | * Encrypt the firmware data 93 | */ 94 | virtual auto Encrypt() -> void = 0; 95 | 96 | /** 97 | * Check if another firwamware handle is compatible with this 98 | */ 99 | virtual auto IsCompatible(const FirmwareSupport* Other) const -> bool = 0; 100 | 101 | /** 102 | * Gets the firmware binary 103 | */ 104 | auto GetData() const -> const std::vector& 105 | { 106 | return data; 107 | } 108 | 109 | /** 110 | * Get segments to write in the firmware 111 | */ 112 | virtual auto GetDataSegments() const -> const std::vector 113 | { 114 | std::vector ret; 115 | 116 | auto r_idx = 0u; 117 | auto r_offset = 0u; 118 | for (const auto& r : memory_ranges) 119 | { 120 | ret.push_back(FirmwareSegment( 121 | r_idx++, 122 | r.first, 123 | r.second, 124 | data.begin() + r_offset, 125 | data.begin() + r_offset + r.second 126 | )); 127 | r_offset += r.second; 128 | } 129 | 130 | return ret; 131 | } 132 | 133 | /** 134 | * Adds a data segment to this firmware 135 | * @note Normally used when wrapping new firmware 136 | * @remarks Data will be padded if its too short 137 | */ 138 | virtual auto AppendSegment(const uint32_t& addr, const std::vector& new_data) -> void 139 | { 140 | auto extra = align != 0 ? new_data.size() % align : 0; 141 | auto new_size = new_data.size() + (extra > 0 ? align - extra : 0); 142 | data.reserve(data.size() + new_size); 143 | std::copy(new_data.begin(), new_data.end(), std::back_inserter(data)); 144 | if (extra > 0) 145 | { 146 | std::fill_n(std::back_inserter(data), align - extra, 0xff); 147 | } 148 | memory_ranges.push_back({ addr, new_size }); 149 | } 150 | 151 | protected: 152 | /** 153 | * Constructor with segment alignment 154 | */ 155 | FirmwareSupport(const uint32_t& align = 0) 156 | : align(align) 157 | { } 158 | 159 | /** 160 | * Segment memory alignment 161 | */ 162 | const uint32_t align; 163 | 164 | /** 165 | * The firmware binary 166 | */ 167 | std::vector data; 168 | 169 | /** 170 | * Memory ranges to write the firmware file to 171 | * 172 | */ 173 | std::vector> memory_ranges; 174 | }; 175 | } // namespace radio_tool::fw -------------------------------------------------------------------------------- /include/radio_tool/fw/fw_factory.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace radio_tool::fw 32 | { 33 | class FirmwareSupportTest 34 | { 35 | public: 36 | FirmwareSupportTest( 37 | std::function &&fnFile, 38 | std::function &&fnRadio, 39 | std::function()> &&fnCreate 40 | ) : SupportsFirmwareFile(fnFile), SupportsRadioModel(fnRadio), CreateHandler(fnCreate) 41 | { 42 | 43 | } 44 | const std::function SupportsFirmwareFile; 45 | 46 | const std::function SupportsRadioModel; 47 | 48 | const std::function()> CreateHandler; 49 | }; 50 | 51 | /** 52 | * All firmware handlers 53 | */ 54 | const std::vector AllFirmwareHandlers = { 55 | FirmwareSupportTest(TYTFW::SupportsFirmwareFile, TYTFW::SupportsRadioModel, TYTFW::Create), 56 | FirmwareSupportTest(CSFW::SupportsFirmwareFile, CSFW::SupportsRadioModel, CSFW::Create), 57 | FirmwareSupportTest(TYTSGLFW::SupportsFirmwareFile, TYTSGLFW::SupportsRadioModel, TYTSGLFW::Create), 58 | /* Below supports random files - no checks */ 59 | FirmwareSupportTest(YaesuFW::SupportsFirmwareFile, YaesuFW::SupportsRadioModel, YaesuFW::Create), 60 | FirmwareSupportTest(AilunceFW::SupportsFirmwareFile, AilunceFW::SupportsRadioModel, AilunceFW::Create) 61 | }; 62 | 63 | class FirmwareFactory 64 | { 65 | public: 66 | /** 67 | * Return a handler for the firmware file 68 | * @note Normally used for firmware only operations 69 | */ 70 | static auto GetFirmwareFileHandler(const std::string &file) -> std::unique_ptr 71 | { 72 | for (const auto &fn : AllFirmwareHandlers) 73 | { 74 | if (fn.SupportsFirmwareFile(file)) 75 | { 76 | return fn.CreateHandler(); 77 | } 78 | } 79 | throw std::runtime_error("Firmware file not supported"); 80 | } 81 | 82 | /** 83 | * Return a handler for the firmware file 84 | * @note Normally used for firmware only operations 85 | */ 86 | static auto GetFirmwareModelHandler(const std::string &model) -> std::unique_ptr 87 | { 88 | for (const auto &fn : AllFirmwareHandlers) 89 | { 90 | if (fn.SupportsRadioModel(model)) 91 | { 92 | return fn.CreateHandler(); 93 | } 94 | } 95 | throw std::runtime_error("Firmware model not supported"); 96 | } 97 | }; 98 | } // namespace radio_tool::fw 99 | -------------------------------------------------------------------------------- /include/radio_tool/fw/tyt_fw_sgl.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | namespace radio_tool::fw 31 | { 32 | constexpr auto NotAscii = [](unsigned char ch) { 33 | return !(ch >= ' ' && ch <= '~'); 34 | }; 35 | 36 | class SGLHeader 37 | { 38 | public: 39 | SGLHeader( 40 | const uint16_t& sgl_version, 41 | const uint32_t& len, 42 | const std::string& group, 43 | const std::string& model, 44 | const std::string& version, 45 | const std::string& key, 46 | const uint8_t& binary_offset, 47 | const uint16_t& header2_offset) 48 | : sgl_version(sgl_version), 49 | length(len), 50 | binary_offset(binary_offset), 51 | header2_offset(header2_offset), 52 | radio_group(group.begin(), std::find_if(group.begin(), group.end(), NotAscii)), 53 | radio_model(model.begin(), std::find_if(model.begin(), model.end(), NotAscii)), 54 | protocol_version(version), 55 | model_key(key) 56 | { 57 | if (sgl_version > 0x100) { 58 | throw std::runtime_error("Version max is 0x100"); 59 | } 60 | if (binary_offset > 0x80) { 61 | throw std::runtime_error("Binary offset max is 0x80"); 62 | } 63 | if (header2_offset < 0x1e || header2_offset > 0x100) { 64 | throw std::runtime_error("Header 2 offset must be between 0x1e <-> 0x100"); 65 | } 66 | } 67 | 68 | auto ToString() const->std::string; 69 | 70 | auto Serialize(bool encrypt = true) const->std::vector; 71 | 72 | /** 73 | * Genrate a new instance of this header with new secret values 74 | */ 75 | auto AsNew(const uint32_t& binary_len) const -> const SGLHeader; 76 | 77 | /** 78 | * Check if this header is compatible with another (excluding secrets) 79 | */ 80 | auto IsCompatible(const SGLHeader& other) const -> bool; 81 | 82 | const uint16_t sgl_version; 83 | const uint32_t length; 84 | const uint8_t binary_offset; 85 | const uint16_t header2_offset; 86 | const std::string radio_group; //BF-DMR = 0x10 87 | const std::string radio_model; //1801 = 0x08 88 | const std::string protocol_version; //V1.00.1 = 0x08 89 | const std::string model_key; //DV01xxxx = 0x08 90 | }; 91 | 92 | /** 93 | * Class to store all config for each TYT radio model (SGL firmware) 94 | */ 95 | class TYTSGLRadioConfig 96 | { 97 | public: 98 | TYTSGLRadioConfig(const std::string& model, const SGLHeader& header, const uint8_t* cipher, const uint32_t& cipher_l, const uint16_t& xor_offset) 99 | : radio_model(model), header(header), cipher(cipher), cipher_len(cipher_l), xor_offset(xor_offset) 100 | { 101 | } 102 | 103 | /** 104 | * The model of the radio 105 | */ 106 | const std::string radio_model; 107 | 108 | /** 109 | * Decrypted firmware file header 110 | */ 111 | const SGLHeader header; 112 | 113 | /** 114 | * The cipher key for encrypting/decrypting the firmware 115 | */ 116 | const uint8_t* cipher; 117 | 118 | /** 119 | * The length of the cipher 120 | */ 121 | const uint32_t cipher_len; 122 | 123 | /** 124 | * Offset into xor key 125 | */ 126 | const uint16_t xor_offset; 127 | }; 128 | 129 | namespace tyt::config::sgl 130 | { 131 | const std::vector Magic = { 'S', 'G', 'L', '!' }; 132 | 133 | const std::vector All = { 134 | TYTSGLRadioConfig("GD77", SGLHeader(1, 0, "SG-MD-760", "MD-760", "V1.00.01", "DV01xxx", 0x00, 0xff), fw::cipher::sgl, fw::cipher::sgl_length, 0x807), 135 | TYTSGLRadioConfig("GD77S", SGLHeader(1, 0, "SG-MD-730", "MD-730", "V1.00.01", "DV02xxx", 0x00, 0xff), fw::cipher::sgl, fw::cipher::sgl_length, 0x2a8e), 136 | TYTSGLRadioConfig("BF5R", SGLHeader(1, 0, "BF-5R", "BF-5R", "V1.00.01", "DV02xxx", 0x00, 0xff), fw::cipher::sgl, fw::cipher::sgl_length, 0x306e), 137 | TYTSGLRadioConfig("DM1801", SGLHeader(1, 0, "BF-DMR", "1801", "V1.00.01", "DV03xxx", 0x00, 0xff), fw::cipher::sgl, fw::cipher::sgl_length, 0x2c7c), 138 | }; 139 | } 140 | 141 | class TYTSGLFW : public FirmwareSupport 142 | { 143 | public: 144 | TYTSGLFW() : FirmwareSupport(), config(nullptr) {} 145 | 146 | auto Read(const std::string& file) -> void override; 147 | auto Write(const std::string& file) -> void override; 148 | auto ToString() const->std::string override; 149 | auto Decrypt() -> void override; 150 | auto Encrypt() -> void override; 151 | auto SetRadioModel(const std::string&) -> void override; 152 | auto IsCompatible(const FirmwareSupport* Other) const -> bool override; 153 | 154 | auto GetConfig() const -> const TYTSGLRadioConfig* { 155 | return config; 156 | } 157 | 158 | /** 159 | * @note This is not the "firmware_model" which exists in the firmware header 160 | */ 161 | auto GetRadioModel() const -> const std::string override; 162 | 163 | /** 164 | * Tests a file if its a valid firmware file 165 | */ 166 | static auto SupportsFirmwareFile(const std::string& file) -> bool; 167 | 168 | /** 169 | * Tests if a radio model is supported by this firmware handler 170 | */ 171 | static auto SupportsRadioModel(const std::string& model) -> bool; 172 | 173 | /** 174 | * Test the file if it matches any known headers 175 | */ 176 | static auto ReadHeader(const std::string& file) -> const SGLHeader; 177 | 178 | /** 179 | * Create an instance of this class for the firmware factory 180 | */ 181 | static auto Create() -> std::unique_ptr 182 | { 183 | return std::make_unique(); 184 | } 185 | 186 | private: 187 | const TYTSGLRadioConfig* config; 188 | }; 189 | 190 | } // namespace radio_tool::fw -------------------------------------------------------------------------------- /include/radio_tool/fw/yaesu_fw.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace radio_tool::fw 29 | { 30 | /** 31 | * Class to store all config for each Yaesu radio model 32 | */ 33 | class YaesuRadioConfig 34 | { 35 | public: 36 | YaesuRadioConfig(const std::string& model) 37 | : radio_model(model) 38 | { 39 | } 40 | 41 | /** 42 | * The model of the radio 43 | */ 44 | const std::string radio_model; 45 | }; 46 | 47 | class YaesuFW : public FirmwareSupport 48 | { 49 | public: 50 | YaesuFW() {} 51 | 52 | auto Read(const std::string& file) -> void override; 53 | auto Write(const std::string& file) -> void override; 54 | auto ToString() const->std::string override; 55 | auto Decrypt() -> void override; 56 | auto Encrypt() -> void override; 57 | auto SetRadioModel(const std::string&) -> void override; 58 | auto IsCompatible(const FirmwareSupport* Other) const -> bool override; 59 | 60 | /** 61 | * @note This is not the "firmware_model" which exists in the firmware header 62 | */ 63 | auto GetRadioModel() const -> const std::string override; 64 | 65 | 66 | /** 67 | * Tests a file if its a valid firmware file 68 | */ 69 | static auto SupportsFirmwareFile(const std::string& file) -> bool; 70 | 71 | /** 72 | * Tests if a radio model is supported by this firmware handler 73 | */ 74 | static auto SupportsRadioModel(const std::string& model) -> bool; 75 | 76 | /** 77 | * Create an instance of this class for the firmware factory 78 | */ 79 | static auto Create() -> std::unique_ptr 80 | { 81 | return std::make_unique(); 82 | } 83 | 84 | private: 85 | std::string radio_model; 86 | }; 87 | 88 | } // namespace radio_tool::fw 89 | -------------------------------------------------------------------------------- /include/radio_tool/h8sx/h8sx.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #define CHECK_ERR(errstr) \ 31 | do \ 32 | { \ 33 | if (err < LIBUSB_SUCCESS) \ 34 | { \ 35 | std::string e = std::string(errstr) + \ 36 | std::string(libusb_error_name(err)); \ 37 | throw radio_tool::h8sx::H8SXException(e); \ 38 | } \ 39 | } while (0) 40 | 41 | #if defined(__GNUC__) 42 | #define PACK(__Declaration__) __Declaration__ __attribute__((__packed__)) 43 | #elif defined(_MSC_VER) 44 | #define PACK(__Declaration__) __pragma(pack(push, 1)) __Declaration__ __pragma(pack(pop)) 45 | #endif 46 | 47 | #define BULK_EP_IN 0x82 48 | #define BULK_EP_OUT 0x01 49 | #define BUF_SIZE 64 * 1024 // Max transfer size 64KB 50 | 51 | namespace radio_tool::h8sx 52 | { 53 | enum class H8SXCmd : uint8_t 54 | { 55 | /* 56 | * Begin the inquiry phase 57 | */ 58 | BEGIN_INQUIRY = 0x55, 59 | 60 | /* 61 | * Inquiry regarding device codes 62 | */ 63 | DEVICE_INQUIRY = 0x20, 64 | 65 | /* 66 | * Selection of device code 67 | */ 68 | DEVICE_SELECT = 0x10, 69 | 70 | /* 71 | * Inquiry regarding numbers of clock modes 72 | * and values of each mode 73 | */ 74 | CLOCK_MODE_INQUIRY = 0x21, 75 | 76 | /* 77 | * Indication of the selected clock mode 78 | */ 79 | CLOCK_MODE_SELECT = 0x11, 80 | 81 | /* 82 | * Inquiry regarding the unit of program data 83 | */ 84 | PROG_UNIT_INQUIRY = 0x27, 85 | 86 | /* 87 | * Selection of new bit rate 88 | */ 89 | BITRATE_SELECT = 0x3F, 90 | 91 | /* 92 | * Erasing of user MAT and user boot MAT, and 93 | * entry to programming/erasing state 94 | */ 95 | BEGIN_PROGRAMMING = 0x40, 96 | 97 | /* 98 | * Transfers the user MAT programming 99 | * program 100 | */ 101 | USER_MAT_SELECT = 0x43, 102 | 103 | /* 104 | * Programs 128 bytes of data 105 | */ 106 | PROGRAM_128B = 0x50, 107 | 108 | /* 109 | * Checks the checksum of the user MAT 110 | */ 111 | USER_MAT_CHECKSUM = 0x4B, 112 | }; 113 | 114 | // Supported device inquiry response 115 | PACK(struct dev_inq_hdr_t { 116 | uint8_t cmd = 0; 117 | uint8_t size = 0; 118 | uint8_t ndev = 0; 119 | uint8_t nchar = 0; 120 | char code[4] = {0}; 121 | }); 122 | 123 | PACK(struct dev_sel_t { 124 | uint8_t cmd = 0; 125 | uint8_t size = 0; 126 | char code[4] = {0}; 127 | uint8_t sum = 0; 128 | }); 129 | 130 | PACK(struct prog_chunk_t { 131 | uint8_t cmd = static_cast(H8SXCmd::PROGRAM_128B); 132 | uint32_t addr = 0; 133 | uint8_t data[1024] = {0}; 134 | uint8_t sum = 0; 135 | }); 136 | 137 | PACK(struct prog_end_t { 138 | uint8_t cmd = static_cast(H8SXCmd::PROGRAM_128B); 139 | uint32_t addr = 0xffffffff; 140 | uint8_t sum = 0xb4; 141 | }); 142 | 143 | PACK(struct sum_chk_t { 144 | uint8_t cmd; 145 | uint8_t size; 146 | uint32_t chk; 147 | uint8_t sum; 148 | }); 149 | 150 | class H8SX 151 | { 152 | public: 153 | H8SX(libusb_device_handle *device) 154 | : timeout(5000), device(device) {} 155 | 156 | auto Init() const -> void; 157 | auto IdentifyDevice() const -> std::string; 158 | auto Download(const std::vector &) const -> void; 159 | 160 | private: 161 | libusb_context *usb_ctx; 162 | 163 | auto GetDeviceString(const libusb_device_descriptor &, libusb_device_handle *) const -> std::wstring; 164 | auto Checksum(const uint8_t *data, const size_t len) const -> uint8_t; 165 | auto InquireDevice(struct dev_inq_hdr_t** hdr) const -> void; 166 | 167 | protected: 168 | const uint16_t timeout; 169 | libusb_device_handle *device; 170 | 171 | auto CheckDevice() const -> void; 172 | 173 | /** 174 | * Ensures the state is H8SX_IDLE or H8SX_DNLOAD_IDLE 175 | */ 176 | auto InitDownload() const -> void; 177 | 178 | /** 179 | * Ensures the state is H8SX_IDLE or H8SX_DPLOAD_IDLE 180 | */ 181 | auto InitUpload() const -> void; 182 | }; 183 | } // namespace radio_tool::h8sx 184 | -------------------------------------------------------------------------------- /include/radio_tool/h8sx/h8sx_exception.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | 23 | namespace radio_tool::h8sx { 24 | class H8SXException : public std::exception { 25 | public: 26 | H8SXException(const std::string& str) 27 | : msg(str) { } 28 | 29 | auto what() const noexcept -> const char* { 30 | return msg.c_str(); 31 | } 32 | private: 33 | const std::string msg; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /include/radio_tool/hid/hid.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2021 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | 23 | namespace radio_tool::hid 24 | { 25 | class HID 26 | { 27 | public: 28 | HID(libusb_device_handle *device) 29 | : timeout(5000), device(device) { 30 | } 31 | 32 | auto InterruptRead(const uint8_t &ep, const uint16_t &len) const -> std::vector; 33 | auto InterruptWrite(const uint8_t &ep, const std::vector&) const -> void; 34 | 35 | auto BulkRead(const uint8_t &ep, const uint16_t &len) const -> std::vector; 36 | auto BulkWrite(const uint8_t &ep, const std::vector&) const -> void; 37 | protected: 38 | const uint16_t timeout; 39 | libusb_device_handle *device; 40 | 41 | 42 | auto HandleEvents() const -> void; 43 | }; 44 | }; -------------------------------------------------------------------------------- /include/radio_tool/hid/tyt_hid.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2021 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | namespace radio_tool::hid 27 | { 28 | namespace tyt 29 | { 30 | namespace commands 31 | { 32 | const std::vector A = { 'A' }; 33 | const std::vector Update = { '#', 'U', 'P', 'D', 'A', 'T', 'E', '?' }; 34 | const std::vector Download = { 'D', 'O', 'W', 'N', 'L', 'O', 'A', 'D' }; 35 | const std::vector FlashProgram = { 'F', '-', 'P', 'R', 'O', 'G' }; 36 | const std::vector FlashErase = { 'F', '-', 'E', 'R', 'A', 'S', 'E' }; 37 | const std::vector EraseROM = { 'E', 'R', 'A', 'S', 'E', 'R', 'O', 'M' }; 38 | const std::vector FlashVersion = { 'F', '-', 'V', 'E', 'R' }; 39 | const std::vector FlashCompany = { 'F', '-', 'C', 'O' }; 40 | const std::vector FlashSerialNumber = { 'F', '-', 'S', 'N' }; 41 | const std::vector FlashTime = { 'F', '-', 'T', 'I', 'M', 'E' }; // ? write time ? 42 | const std::vector FlashMod = { 'F', '-', 'M', 'O', 'D' }; // ? mode ? 43 | const std::vector Program = { 'P', 'R', 'O', 'G', 'R', 'A', 'M' }; 44 | const std::vector End = { 'E', 'N', 'D' }; 45 | }; 46 | 47 | enum class CommandType : uint16_t 48 | { 49 | HostToDevice = 0x01, 50 | DeviceToHost = 0x03 51 | }; 52 | 53 | class Command 54 | { 55 | public: 56 | Command(const CommandType& t, const uint16_t& l, const std::vector& d) 57 | : type(t), length(l), data(d) {} 58 | 59 | const CommandType type; 60 | const uint16_t length; 61 | const std::vector data; 62 | 63 | auto operator==(const Command& other) const -> bool 64 | { 65 | return type == other.type && length == other.length && std::equal(data.begin(), data.end(), other.data.begin()); 66 | } 67 | }; 68 | 69 | /** 70 | * OK response to device 71 | */ 72 | const Command OK = Command(CommandType::HostToDevice, 1, commands::A); 73 | 74 | /** 75 | * OK response from device 76 | */ 77 | const Command OKResponse = Command(CommandType::DeviceToHost, 1, commands::A); 78 | }; 79 | 80 | class TYTHID : public HID 81 | { 82 | public: 83 | const unsigned char EP_IN = LIBUSB_ENDPOINT_IN | 0x01; 84 | const unsigned char EP_OUT = LIBUSB_ENDPOINT_OUT | 0x02; 85 | 86 | static const auto VID = 0x15a2; 87 | static const auto PID = 0x0073; 88 | 89 | TYTHID(libusb_device_handle* device) 90 | : HID(device), signalCallback(), signalReady(), tx(nullptr) {} 91 | 92 | auto Setup() -> void; 93 | 94 | auto SendCommand(const tyt::Command& cmd) -> tyt::Command; 95 | auto SendCommand(const std::vector& cmd) -> tyt::Command; 96 | auto SendCommand(const std::vector& cmd, const uint8_t& size, const uint8_t& fill) -> tyt::Command; 97 | 98 | auto SendCommandAndOk(const tyt::Command& cmd) -> void; 99 | auto SendCommandAndOk(const std::vector& cmd) -> void; 100 | auto SendCommandAndOk(const std::vector& cmd, const uint8_t& size, const uint8_t& fill) -> void; 101 | 102 | auto WaitForReply()->tyt::Command; 103 | 104 | auto OnTransfer(libusb_transfer* tx) -> void; 105 | 106 | private: 107 | std::mutex signalCallback; 108 | std::condition_variable signalReady; 109 | struct libusb_transfer* tx; 110 | }; 111 | } -------------------------------------------------------------------------------- /include/radio_tool/radio/ailunce_radio.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 Niccol� Izzo IU2KIN 4 | * Copyright (c) 2022 v0l 5 | * 6 | * radio_tool is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * radio_tool is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with radio_tool. If not, see . 18 | */ 19 | #pragma once 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | namespace radio_tool::radio 27 | { 28 | class AilunceRadio : public RadioOperations 29 | { 30 | public: 31 | // Prolific Technology, Inc. - USB-Serial Controller 32 | static const auto VID = 0x067b; 33 | static const auto PID = 0x2303; 34 | 35 | AilunceRadio(const std::string &prt, const std::string &fname) 36 | : device(prt, fname) {} 37 | 38 | auto WriteFirmware(const std::string &file) -> void override; 39 | auto ToString() const -> const std::string override; 40 | 41 | static auto SupportsDevice(const std::string &) -> bool; 42 | 43 | static auto Create(const std::string &port) -> AilunceRadio* 44 | { 45 | return new AilunceRadio(port, "firmware.bin"); 46 | } 47 | 48 | private: 49 | device::YModemDevice device; 50 | static auto GetComPortUSBIds(const std::string& port) -> std::pair; 51 | }; 52 | } // namespace radio_tool::radio 53 | -------------------------------------------------------------------------------- /include/radio_tool/radio/radio.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace radio_tool::radio 27 | { 28 | class RadioOperations; 29 | typedef std::function CreateRadioOps; 30 | 31 | /** 32 | * Information related to a detected radio 33 | */ 34 | class RadioInfo 35 | { 36 | public: 37 | const uint16_t index; 38 | const std::wstring manufacturer; 39 | const std::wstring model; 40 | const std::string port; 41 | virtual auto ToString() const -> const std::wstring = 0; 42 | virtual auto OpenDevice() const -> RadioOperations * = 0; 43 | 44 | protected: 45 | RadioInfo(const uint16_t &index, const std::wstring &manufacturer, const std::wstring &model, const std::string &port) 46 | : index(index), manufacturer(manufacturer), model(model), port(port) 47 | { 48 | } 49 | }; 50 | 51 | /** 52 | * Generic interface for operations which we want to perform on radios 53 | */ 54 | class RadioOperations 55 | { 56 | public: 57 | virtual ~RadioOperations() = default; 58 | 59 | /** 60 | * Write a firmware file to the device (Firmware Upgrade) 61 | */ 62 | virtual auto WriteFirmware(const std::string &file) -> void = 0; 63 | 64 | // virtual auto WriteCodeplug(); 65 | // virtual auto ReadCodeplug(); 66 | 67 | /** 68 | * Get general info about the radio 69 | */ 70 | virtual auto ToString() const -> const std::string = 0; 71 | }; 72 | 73 | /** 74 | * Interface for listing devices 75 | */ 76 | class RadioOperationsFactory 77 | { 78 | public: 79 | virtual auto ListDevices(const uint16_t &idx_offset) const -> const std::vector = 0; 80 | }; 81 | } // namespace radio_tool::radio -------------------------------------------------------------------------------- /include/radio_tool/radio/radio_factory.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | 22 | namespace radio_tool::radio 23 | { 24 | /** 25 | * Primary factory for accessing and listing supported devices 26 | */ 27 | class RadioFactory 28 | { 29 | public: 30 | auto OpenDevice(const uint16_t& index) const -> RadioOperations*; 31 | auto ListDevices() const -> const std::vector; 32 | }; 33 | } // namespace radio_tool::radio -------------------------------------------------------------------------------- /include/radio_tool/radio/serial_radio_factory.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace radio_tool::radio 29 | { 30 | class SerialRadioInfo : public RadioInfo 31 | { 32 | public: 33 | SerialRadioInfo( 34 | const CreateRadioOps l, 35 | const std::string &p, 36 | const uint16_t &idx) 37 | : RadioInfo(idx, L"Unknown", L"Unknown", p), loader(l) {} 38 | 39 | auto ToString() const -> const std::wstring override 40 | { 41 | std::wstringstream os; 42 | os << L"[" << std::wstring(port.begin(), port.end()) << "]: idx=" << std::to_wstring(index) << L", " 43 | << L"Generic serial radio"; 44 | 45 | return os.str(); 46 | } 47 | 48 | auto OpenDevice() const -> RadioOperations * override 49 | { 50 | return loader(); 51 | } 52 | 53 | private: 54 | const CreateRadioOps loader; 55 | }; 56 | 57 | class SerialRadioFactory : public RadioOperationsFactory 58 | { 59 | public: 60 | auto ListDevices(const uint16_t &idx_offset) const -> const std::vector override; 61 | 62 | private: 63 | auto OpDeviceList(std::function) const -> void; 64 | }; 65 | } -------------------------------------------------------------------------------- /include/radio_tool/radio/tyt_radio.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | namespace radio_tool::radio 27 | { 28 | class TYTRadio : public RadioOperations 29 | { 30 | public: 31 | TYTRadio(libusb_device_handle* h) 32 | : dfu(h) {} 33 | 34 | auto WriteFirmware(const std::string& file) -> void override; 35 | auto ToString() const -> const std::string override; 36 | 37 | static auto SupportsDevice(const libusb_device_descriptor& dev) -> bool 38 | { 39 | return dev.idVendor == dfu::TYTDFU::VID && dev.idProduct == dfu::TYTDFU::PID; 40 | } 41 | 42 | /** 43 | * Get the handler used to communicate with this device 44 | */ 45 | auto GetDFU() const -> const dfu::TYTDFU* 46 | { 47 | return &dfu; 48 | } 49 | 50 | static auto Create(libusb_device_handle* h) -> TYTRadio* { 51 | return new TYTRadio(h); 52 | } 53 | private: 54 | const dfu::TYTDFU dfu; 55 | }; 56 | } // namespace radio_tool::radio -------------------------------------------------------------------------------- /include/radio_tool/radio/tyt_sgl_radio.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2021 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | namespace radio_tool::radio 26 | { 27 | class TYTSGLRadio : public RadioOperations 28 | { 29 | public: 30 | TYTSGLRadio(libusb_device_handle* h); 31 | 32 | auto WriteFirmware(const std::string& file) -> void override; 33 | auto ToString() const -> const std::string override; 34 | 35 | static auto SupportsDevice(const libusb_device_descriptor& dev) -> bool 36 | { 37 | if (dev.idVendor == hid::TYTHID::VID && dev.idProduct == hid::TYTHID::PID) 38 | { 39 | return true; 40 | } 41 | return false; 42 | } 43 | 44 | static auto Create(libusb_device_handle* h) -> TYTSGLRadio* 45 | { 46 | return new TYTSGLRadio(h); 47 | } 48 | private: 49 | hid::TYTHID device; 50 | auto checksum(std::vector::const_iterator&& begin, std::vector::const_iterator&& end) const -> uint32_t; 51 | }; 52 | } // namespace radio_tool::radio -------------------------------------------------------------------------------- /include/radio_tool/radio/usb_radio_factory.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | namespace radio_tool::radio 31 | { 32 | class USBRadioInfo : public RadioInfo 33 | { 34 | public: 35 | const uint16_t vid, pid; 36 | 37 | USBRadioInfo( 38 | const CreateRadioOps l, 39 | const std::wstring &mfg, 40 | const std::wstring &prd, 41 | const uint16_t &vid, 42 | const uint16_t &pid, 43 | const uint16_t &idx) 44 | : RadioInfo(idx, mfg, prd, ""), vid(vid), pid(pid), loader(l) 45 | {} 46 | 47 | auto ToString() const -> const std::wstring override 48 | { 49 | std::wstringstream os; 50 | os << L"[" 51 | << std::setfill(L'0') << std::setw(4) << std::hex << vid 52 | << L":" 53 | << std::setfill(L'0') << std::setw(4) << std::hex << pid 54 | << L"]: idx=" << std::setfill(L'0') << std::setw(3) << std::to_wstring(index) << L", " 55 | << manufacturer << L" " << model; 56 | return os.str(); 57 | } 58 | 59 | auto OpenDevice() const -> RadioOperations* override 60 | { 61 | return loader(); 62 | } 63 | 64 | private: 65 | const CreateRadioOps loader; 66 | }; 67 | 68 | /** 69 | * libusb devices are enumerated from here, 70 | * implementors of direct usb drivers with libusb can hook this factory 71 | */ 72 | class USBRadioFactory : public RadioOperationsFactory 73 | { 74 | public: 75 | USBRadioFactory(); 76 | ~USBRadioFactory(); 77 | auto ListDevices(const uint16_t& idx_offset) const -> const std::vector override; 78 | auto HandleEvents() -> void; 79 | private: 80 | auto GetDeviceString(const uint8_t &, libusb_device_handle *) const -> std::wstring; 81 | static auto OpenDevice(const uint8_t &bus, const uint8_t &port, const uint8_t& address) -> libusb_device_handle *; 82 | static auto CreateContext() -> libusb_context *; 83 | 84 | libusb_context* usb_ctx; 85 | std::thread events; 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /include/radio_tool/radio/yaesu_radio.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | namespace radio_tool::radio 27 | { 28 | class YaesuRadio : public RadioOperations 29 | { 30 | public: 31 | static const auto VID = 0x045b; 32 | static const auto PID = 0x0025; 33 | 34 | YaesuRadio(libusb_device_handle* h) 35 | : h8sx(h) { 36 | h8sx.Init(); 37 | } 38 | 39 | auto WriteFirmware(const std::string& file) -> void override; 40 | auto ToString() const -> const std::string override; 41 | 42 | static auto SupportsDevice(const libusb_device_descriptor& dev) -> bool 43 | { 44 | return dev.idVendor == VID && dev.idProduct == PID; 45 | } 46 | 47 | static auto Create(libusb_device_handle* h) -> YaesuRadio* { 48 | return new YaesuRadio(h); 49 | } 50 | private: 51 | h8sx::H8SX h8sx; 52 | }; 53 | } // namespace radio_tool::radio 54 | -------------------------------------------------------------------------------- /include/radio_tool/util/flash.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | namespace radio_tool::flash 29 | { 30 | class FlashSector 31 | { 32 | public: 33 | FlashSector(const uint16_t &idx, const uint32_t §or_start, const uint32_t §or_size) 34 | : index(idx), start(sector_start), size(sector_size) {} 35 | 36 | /** 37 | * Flash sector index (0-N usually) 38 | */ 39 | const uint16_t index; 40 | 41 | /** 42 | * Start address of this flash sector 43 | */ 44 | const uint32_t start; 45 | 46 | /** 47 | * Size of this flash sector 48 | */ 49 | const uint32_t size; 50 | 51 | /** 52 | * End address of this flash sector 53 | */ 54 | constexpr auto End() const -> uint32_t 55 | { 56 | return start + size; 57 | } 58 | 59 | /** 60 | * If this addr is inside this sector 61 | */ 62 | constexpr auto InSector(const uint32_t &addr) const -> bool 63 | { 64 | return addr >= start && addr < End(); 65 | } 66 | 67 | /** 68 | * Get a string describing this sector 69 | */ 70 | auto ToString() const -> const std::string 71 | { 72 | std::stringstream out; 73 | out << "FlashSector[Index=" << index 74 | << ", Start=0x" << std::setw(8) << std::setfill('0') << std::hex << start 75 | << ", End=0x" << std::setw(8) << std::setfill('0') << std::hex << End() 76 | << "]"; 77 | 78 | return out.str(); 79 | } 80 | }; 81 | 82 | 83 | typedef std::vector FlashMap; 84 | 85 | class FlashUtil 86 | { 87 | public: 88 | /** 89 | * Get the sector of an address in a flash map 90 | */ 91 | static auto GetSector(const FlashMap &map, const uint32_t &addr) -> std::optional 92 | { 93 | for (const auto &sec : map) 94 | { 95 | if (sec.InSector(addr)) 96 | { 97 | return sec; 98 | } 99 | } 100 | return {}; 101 | } 102 | 103 | /** 104 | * Create a simple memory layout with all sectors having the same size 105 | */ 106 | static auto MakeSimpleLayout(const uint32_t& start_addr, const uint32_t& sector_size, const uint16_t& sectors) -> FlashMap 107 | { 108 | auto ret = FlashMap(); 109 | for(auto x = 0; x < sectors; x++) 110 | { 111 | ret.push_back(FlashSector(x, start_addr + (sector_size * x), sector_size)); 112 | } 113 | return ret; 114 | } 115 | 116 | /** 117 | * Executes a function, sector aligned over a range of bytes for a give map 118 | */ 119 | static auto AlignedContiguousMemoryOp(const FlashMap& map, const uint32_t& start, const uint32_t& end, 120 | const std::function& fnOp) -> void 121 | { 122 | for (auto addr = start; addr < end;) 123 | { 124 | if(const auto& sec_info = flash::FlashUtil::GetSector(map, addr)) 125 | { 126 | auto n_bytes = std::min(end, sec_info->End()) - addr; 127 | 128 | fnOp(addr, n_bytes, sec_info.value()); 129 | 130 | addr += n_bytes; 131 | } 132 | else 133 | { 134 | break; //unmapped region 135 | } 136 | } 137 | } 138 | }; 139 | 140 | /** 141 | * STM32F40X & STM32F41X Memory organization 142 | */ 143 | const FlashMap STM32F40X = { 144 | {0, 0x08000000, 0x4000}, /* 16k */ 145 | {1, 0x08004000, 0x4000}, 146 | {2, 0x08008000, 0x4000}, 147 | {3, 0x0800c000, 0x4000}, 148 | {4, 0x08010000, 0x10000}, /* 64k */ 149 | {5, 0x08020000, 0x20000}, /* 128k */ 150 | {6, 0x08040000, 0x20000}, 151 | {7, 0x08060000, 0x20000}, 152 | {8, 0x08080000, 0x20000}, 153 | {9, 0x080a0000, 0x20000}, 154 | {10, 0x080c0000, 0x20000}, 155 | {11, 0x080e0000, 0x20000} 156 | }; 157 | 158 | /** 159 | * Winbond W25Q128JV SPI Flash (16MB) 160 | * 256 Blocks 161 | * 4k Sector size 162 | * 16 Sectors 163 | * 164 | * (16 * 4k) * 256 165 | * Used in: DM1701, (Others?) 166 | */ 167 | const FlashMap W25Q128JV = FlashUtil::MakeSimpleLayout(0x00, 0x10000, 0x100); 168 | 169 | /** 170 | * Micron M25P16 SPI Flash (2MB) 171 | * 65k Sector size (512Kbit) 172 | * 32 Sectors 173 | * 174 | * 32 * 64k 175 | */ 176 | const FlashMap M25P16 = FlashUtil::MakeSimpleLayout(0x00, 0x10000, 0x20); 177 | 178 | } // namespace radio_tool::flash 179 | -------------------------------------------------------------------------------- /include/radio_tool/util/log.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace radio_tool::util 4 | { 5 | class Log { 6 | public: 7 | 8 | }; 9 | } -------------------------------------------------------------------------------- /include/radio_tool/version.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #pragma once 19 | 20 | extern const char g_GIT_SHA1[]; 21 | 22 | extern const char g_GIT_SHA1_SHORT[]; 23 | 24 | extern const char g_PROJECT_VERSION[]; 25 | 26 | extern const char g_PROJECT_NAME[]; -------------------------------------------------------------------------------- /src/ailunce_fw.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 Niccol� Izzo IU2KIN 4 | * Copyright (c) 2022 v0l 5 | * 6 | * radio_tool is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * radio_tool is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with radio_tool. If not, see . 18 | */ 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | using namespace radio_tool::fw; 25 | 26 | auto AilunceFW::Read(const std::string &file) -> void 27 | { 28 | auto i = std::ifstream(file, std::ios_base::binary); 29 | if (i.is_open()) 30 | { 31 | i.seekg(0, std::ios_base::end); 32 | auto binarySize = i.tellg(); 33 | memory_ranges.push_back(std::make_pair(0, binarySize)); 34 | i.seekg(std::ios_base::beg); 35 | data.resize(binarySize); 36 | i.read((char *)data.data(), data.size()); 37 | } 38 | i.close(); 39 | } 40 | 41 | auto AilunceFW::Write(const std::string &file) -> void 42 | { 43 | std::ofstream fout(file, std::ios_base::binary); 44 | if (fout.is_open()) 45 | { 46 | fout.write((char *)data.data(), data.size()); 47 | fout.close(); 48 | } 49 | } 50 | 51 | auto AilunceFW::ToString() const -> std::string 52 | { 53 | std::stringstream out; 54 | out << "== Ailunce Firmware == " << std::endl; 55 | auto n = 0; 56 | for (const auto &m : memory_ranges) 57 | { 58 | out << " " << n++ << ": Start=0x" << std::setfill('0') << std::setw(8) << std::hex << m.first 59 | << ", Length=0x" << std::setfill('0') << std::setw(8) << std::hex << m.second 60 | << std::endl; 61 | } 62 | return out.str(); 63 | } 64 | 65 | auto AilunceFW::SupportsFirmwareFile(const std::string &file) -> bool 66 | { 67 | std::ifstream i; 68 | i.open(file, i.binary); 69 | if (i.is_open()) 70 | { 71 | i.close(); 72 | return true; 73 | } 74 | else 75 | { 76 | throw std::runtime_error("Can't open firmware file"); 77 | } 78 | } 79 | 80 | // Ailunce hts are flashed with a USB serial adapter, no way to identify 81 | auto AilunceFW::SupportsRadioModel(const std::string &model) -> bool 82 | { 83 | return model == "HD1"; 84 | } 85 | 86 | auto AilunceFW::GetRadioModel() const -> const std::string 87 | { 88 | return "Ailunce HD1"; 89 | } 90 | 91 | auto AilunceFW::SetRadioModel(const std::string &model) -> void 92 | { 93 | } 94 | 95 | auto AilunceFW::Decrypt() -> void 96 | { 97 | ApplyXOR(); 98 | } 99 | 100 | auto AilunceFW::Encrypt() -> void 101 | { 102 | ApplyXOR(); 103 | } 104 | 105 | auto AilunceFW::ApplyXOR() -> void 106 | { 107 | for (uint32_t i = 0; i < (data.size() / sizeof(uint32_t)); i++) 108 | { 109 | uint32_t *word = reinterpret_cast(data.data()) + i; 110 | if (*word == 0x0 || *word == 0xffffffff) 111 | *word ^= 0xffffffff; 112 | else if (*word & (1 << 28)) 113 | *word ^= 0x01111111; 114 | else 115 | *word ^= 0x07777777; 116 | } 117 | // Last bytes 118 | for (auto z = data.size() - (data.size() % sizeof(uint32_t)); 119 | z < data.size(); z++) 120 | { 121 | if (data[z] == 0x00 || data[z] == 0xff) 122 | data[z] ^= 0xff; 123 | else if (data[z] & 1) 124 | data[z] ^= 0x01; 125 | else 126 | data[z] ^= 0x07; 127 | } 128 | } 129 | 130 | auto AilunceFW::IsCompatible(const FirmwareSupport* Other) const -> bool 131 | { 132 | if (typeid(Other) != typeid(this)) { 133 | return false; 134 | } 135 | 136 | auto afw = dynamic_cast(Other); 137 | return afw->radio_model == radio_model; 138 | } -------------------------------------------------------------------------------- /src/ailunce_radio.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 Niccol� Izzo IU2KIN 4 | * Copyright (c) 2022 v0l 5 | * 6 | * radio_tool is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * radio_tool is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with radio_tool. If not, see . 18 | */ 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | #ifdef _WIN32 25 | #define B57600 57600 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #ifdef COMPORT_DI_LOOKUP 32 | #pragma comment(lib, "Setupapi.lib") 33 | #include 34 | #else 35 | #endif 36 | 37 | #else 38 | #include 39 | #include 40 | #endif 41 | 42 | using namespace radio_tool::radio; 43 | 44 | auto AilunceRadio::ToString() const -> const std::string 45 | { 46 | return "== Ailunce USB Serial Cable =="; 47 | } 48 | 49 | auto AilunceRadio::WriteFirmware(const std::string &file) -> void 50 | { 51 | auto fw = fw::AilunceFW(); 52 | fw.Read(file); 53 | 54 | //XOR raw binary data before sending 55 | fw.Encrypt(); 56 | 57 | device.SetInterfaceAttribs(B57600, 0); 58 | auto fd = device.GetFD(); 59 | // send 1 to start firmware upgrade 60 | #ifdef _WIN32 61 | WriteFile((HANDLE)fd, "1", (DWORD)1, NULL, NULL); 62 | #else 63 | write(fd, "1", 1); 64 | #endif 65 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 66 | 67 | auto r = fw.GetDataSegments()[0]; 68 | device.Write(r.data); 69 | } 70 | 71 | auto AilunceRadio::SupportsDevice(const std::string &port) -> bool 72 | { 73 | // not possible to detect from serial port? 74 | // ideally we could map serial ports to USB devices to validate VID:PID 75 | // 76 | // ✅ possible windows solution: https://aticleworld.com/get-com-port-of-usb-serial-device/ 77 | // possible linux solution: https://unix.stackexchange.com/a/81767 78 | auto ids = GetComPortUSBIds(port); 79 | return (ids.first == VID && ids.second == PID) || true; 80 | } 81 | 82 | auto AilunceRadio::GetComPortUSBIds(const std::string &port) -> std::pair 83 | { 84 | #if defined(_WIN32) && defined(COMPORT_DI_LOOKUP) 85 | auto handle = SetupDiGetClassDevs(NULL, "USB", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT); 86 | if (handle == nullptr) 87 | { 88 | throw std::runtime_error("Failed to open device info"); 89 | } 90 | 91 | BYTE hwIds[1024]; 92 | DEVPROPTYPE propType; 93 | SP_DEVINFO_DATA deviceInfo = {}; 94 | deviceInfo.cbSize = sizeof(SP_DEVINFO_DATA); 95 | 96 | DWORD idx = 0, outSize = 0; 97 | while (SetupDiEnumDeviceInfo(handle, idx++, &deviceInfo)) 98 | { 99 | if (SetupDiGetDeviceRegistryPropertyA(handle, &deviceInfo, SPDRP_HARDWAREID, &propType, (PBYTE)&hwIds, sizeof(hwIds), &outSize)) 100 | { 101 | std::cerr << hwIds << std::endl; 102 | 103 | HKEY regKey; 104 | if ((regKey = SetupDiOpenDevRegKey(handle, &deviceInfo, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ)) == INVALID_HANDLE_VALUE) 105 | { 106 | std::cerr << "Failed to find reg key for device: " << (char *)hwIds << std::endl; 107 | } 108 | 109 | // read com port name 110 | constexpr auto BufferLen = 256; 111 | DWORD dwType = 0; 112 | DWORD portNameSize = BufferLen; 113 | BYTE portName[BufferLen]; 114 | if (RegQueryValueExA(regKey, "PortName", NULL, &dwType, (LPBYTE)&portName, &portNameSize) == ERROR_SUCCESS) 115 | { 116 | // not working for some reason 117 | std::cerr << portName << std::endl; 118 | } 119 | } 120 | } 121 | 122 | SetupDiDestroyDeviceInfoList(handle); 123 | #elif defined(_WIN32) 124 | HKEY comKey = nullptr; 125 | auto openResult = RegOpenKeyExA(HKEY_LOCAL_MACHINE, (LPSTR) "SYSTEM\\CurrentControlSet\\Control\\COM Name Arbiter\\Devices", 0, KEY_READ | KEY_WOW64_64KEY, &comKey); 126 | if (openResult != ERROR_SUCCESS) 127 | { 128 | throw std::runtime_error("Failed to get serial port info from registry"); 129 | } 130 | 131 | constexpr auto BufferSize = 256L; 132 | BYTE value[BufferSize]; 133 | DWORD valueSize = BufferSize; 134 | 135 | auto readResult = RegQueryValueExA(comKey, port.c_str(), NULL, NULL, (LPBYTE)&value, &valueSize); 136 | if (readResult == ERROR_SUCCESS) 137 | { 138 | std::cmatch match; 139 | if (std::regex_match((char *)value, match, std::regex("^.*#vid_([\\w+]{4})\\+pid_([\\w+]{4}).*$"))) 140 | { 141 | auto vid = std::stoi(match[1], nullptr, 16); 142 | auto pid = std::stoi(match[2], nullptr, 16); 143 | return std::make_pair(vid, pid); 144 | } 145 | } 146 | else 147 | { 148 | throw std::runtime_error("Error reading registory key values"); 149 | } 150 | 151 | RegCloseKey(comKey); 152 | #else 153 | 154 | #endif 155 | return std::make_pair(0, 0); 156 | } -------------------------------------------------------------------------------- /src/cs_fw.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | * 18 | * Some or all of this file is copied from CSFWTOOL 19 | * https://github.com/KG5RKI/CSFWTOOL 20 | */ 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | using namespace radio_tool::fw; 32 | 33 | auto CSFW::Read(const std::string& fw) -> void 34 | { 35 | std::ifstream in_file(fw, std::ios_base::binary); 36 | if (in_file.is_open()) 37 | { 38 | in_file.seekg(0, std::fstream::end); 39 | auto len = in_file.tellg(); 40 | in_file.seekg(0, std::fstream::beg); 41 | 42 | in_file.read((char*)&header, sizeof(CS800D_header)); 43 | 44 | //test file size is correct 45 | if (header.imagesize == 0) 46 | { 47 | throw std::runtime_error("Invalid firmware file"); 48 | } 49 | if (header.imagesize + header.imageHeaderSize + sizeof(uint16_t) != len) 50 | { 51 | throw std::runtime_error("Invalid firmware header"); 52 | } 53 | 54 | data.resize(header.imagesize); 55 | in_file.read((char*)data.data(), header.imagesize); 56 | in_file.read((char*)&checksum, sizeof(uint16_t)); 57 | in_file.close(); 58 | 59 | //xor checksum 60 | ((uint8_t*)&checksum)[0] = ((uint8_t*)&checksum)[0] ^ cipher::cs800_0[header.imagesize % cipher::cs800_length]; 61 | ((uint8_t*)&checksum)[1] = ((uint8_t*)&checksum)[1] ^ cipher::cs800_0[(header.imagesize + 1) % cipher::cs800_length]; 62 | 63 | memory_ranges.push_back({ header.baseaddr_offset, header.imagesize }); 64 | 65 | //test checksum 66 | auto cs_check = MakeChecksum(); 67 | if (cs_check != checksum) 68 | { 69 | //checksum not working right now 70 | throw std::runtime_error("Invalid checksum"); 71 | } 72 | } 73 | else 74 | { 75 | throw std::runtime_error("Cant open file"); 76 | } 77 | } 78 | 79 | auto CSFW::UpdateHeader() -> void 80 | { 81 | if (memory_ranges.size() != 1) 82 | { 83 | throw std::runtime_error("CS Firmware can only contain one segment!"); 84 | } 85 | header.imagesize = data.size(); 86 | header.imageHeaderSize = sizeof(CS800D_header); 87 | header.version = 1; 88 | if (memory_ranges.size()) 89 | { 90 | header.baseaddr_offset = memory_ranges[0].first; 91 | } 92 | } 93 | 94 | auto CSFW::Write(const std::string& fw) -> void 95 | { 96 | std::ofstream of(fw, std::ios_base::binary); 97 | if (of.is_open()) 98 | { 99 | UpdateHeader(); 100 | auto data = MakeFiledata(); 101 | of.write((char*)data.data(), data.size()); 102 | 103 | //Apply XOR to make checksum 104 | ApplyXOR(data.begin() + header.imageHeaderSize, data.end(), cipher::cs800_0, cipher::cs800_length); 105 | auto cs = CSChecksum(data.begin(), data.end()); 106 | 107 | //XOR the checksum before writing 108 | ((uint8_t*)&cs)[0] = ((uint8_t*)&cs)[0] ^ cipher::cs800_0[header.imagesize % cipher::cs800_length]; 109 | ((uint8_t*)&cs)[1] = ((uint8_t*)&cs)[1] ^ cipher::cs800_0[(header.imagesize + 1) % cipher::cs800_length]; 110 | 111 | of.write((char*)&cs, sizeof(cs)); 112 | 113 | of.close(); 114 | } 115 | } 116 | 117 | auto CSFW::ToString() const -> std::string 118 | { 119 | std::stringstream out; 120 | 121 | out << "== Connect Systems Firmware ==" << std::endl 122 | << "Image Size: " << FormatBytes(header.imagesize) << std::endl 123 | << "Version: " << header.version << std::endl 124 | << "Checksum: 0x" << std::setw(4) << std::setfill('0') << std::hex << checksum << std::endl 125 | << "Data Segments: " << std::endl; 126 | 127 | auto n = 0u; 128 | for (const auto& m : memory_ranges) 129 | { 130 | out << " " << n++ << ": Start=0x" << std::setfill('0') << std::setw(8) << std::hex << m.first 131 | << ", Length=0x" << std::setfill('0') << std::setw(8) << std::hex << m.second 132 | << std::endl; 133 | } 134 | 135 | return out.str(); 136 | } 137 | 138 | auto CSFW::GetRadioModel() const -> const std::string 139 | { 140 | //TODO: find a way to detect firmware radio model 141 | return "CS800"; 142 | } 143 | 144 | auto CSFW::SetRadioModel(const std::string&) -> void 145 | { 146 | //dont do anything (yet) 147 | } 148 | 149 | auto CSFW::Decrypt() -> void 150 | { 151 | //dont know how to detect dr5xx0 so just use cs800 cipher always 152 | ApplyXOR(data, cipher::cs800_0, cipher::cs800_length); 153 | } 154 | 155 | auto CSFW::Encrypt() -> void 156 | { 157 | //dont know how to detect dr5xx0 so just use cs800 cipher always 158 | ApplyXOR(data, cipher::cs800_0, cipher::cs800_length); 159 | } 160 | 161 | auto CSFW::SupportsFirmwareFile(const std::string& file) -> bool 162 | { 163 | std::ifstream in_file(file, std::ios_base::binary); 164 | if (in_file.is_open()) 165 | { 166 | CS800D_header header = {}; 167 | in_file.read((char*)&header, sizeof(CS800D_header)); 168 | in_file.seekg(0, std::ios_base::end); 169 | auto len = in_file.tellg(); 170 | in_file.close(); 171 | 172 | //test is not resource file 173 | if (header.imagesize == 0) 174 | { 175 | return false; 176 | } 177 | 178 | //test image size matches 179 | if (header.imagesize + header.imageHeaderSize + sizeof(uint16_t) != len) 180 | { 181 | return false; 182 | } 183 | 184 | return true; 185 | } 186 | return false; 187 | } 188 | 189 | auto CSFW::SupportsRadioModel(const std::string& model) -> bool 190 | { 191 | //TODO: Make this better 192 | if (model == "CS800") 193 | { 194 | return true; 195 | } 196 | return false; 197 | } 198 | 199 | auto CSFW::MakeChecksum() const -> uint16_t 200 | { 201 | //Make a copy of the firmware data because we will apply XOR 202 | auto to_check = MakeFiledata(); 203 | 204 | //XOR firmware data 205 | ApplyXOR(to_check.begin() + header.imageHeaderSize, to_check.end(), cipher::cs800_0, cipher::cs800_length); 206 | 207 | return CSChecksum(to_check.begin(), to_check.end()); 208 | } 209 | 210 | auto CSFW::MakeFiledata() const -> std::vector 211 | { 212 | auto h_ptr = (uint8_t*)&header; 213 | std::vector ret; 214 | ret.reserve(header.imageHeaderSize + header.imagesize); 215 | 216 | std::copy(h_ptr, h_ptr + sizeof(CS800D_header), std::back_inserter(ret)); 217 | std::copy(data.begin(), data.end(), std::back_inserter(ret)); 218 | 219 | return ret; 220 | } 221 | 222 | auto CSFW::IsCompatible(const FirmwareSupport* Other) const -> bool 223 | { 224 | if (typeid(Other) != typeid(this)) { 225 | return false; 226 | } 227 | 228 | auto afw = dynamic_cast(Other); 229 | return true; 230 | } -------------------------------------------------------------------------------- /src/dfu.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | using namespace radio_tool::dfu; 26 | 27 | auto DFU::SetAddress(const uint32_t &addr) const -> void 28 | { 29 | std::vector data = { 30 | static_cast(0x21), 31 | static_cast(addr & 0xFF), 32 | static_cast((addr >> 8) & 0xFF), 33 | static_cast((addr >> 16) & 0xFF), 34 | static_cast((addr >> 24) & 0xFF)}; 35 | 36 | Download(data); 37 | } 38 | 39 | auto DFU::Erase(const uint32_t &addr) const -> void 40 | { 41 | std::vector data = { 42 | static_cast(0x41), 43 | static_cast(addr & 0xFF), 44 | static_cast((addr >> 8) & 0xFF), 45 | static_cast((addr >> 16) & 0xFF), 46 | static_cast((addr >> 24) & 0xFF)}; 47 | 48 | Download(data); 49 | } 50 | 51 | auto DFU::Download(const std::vector &data, const uint16_t &wValue) const -> void 52 | { 53 | InitDownload(); 54 | // tehnically we shouldnt const_cast here but libusb *?WONT?* modify this data 55 | auto err = libusb_control_transfer(device, 0x21, static_cast(DFURequest::DNLOAD), wValue, 0, const_cast(data.data()), data.size(), this->timeout); 56 | if (err < LIBUSB_SUCCESS) 57 | { 58 | throw DFUException(libusb_error_name(err)); 59 | } 60 | 61 | //execute command by calling GetStatus 62 | auto status = GetStatus(); 63 | if (status.state != DFUState::DFU_DOWNLOAD_BUSY) 64 | { 65 | throw DFUException("Command execution failed"); 66 | } 67 | else if (status.timeout > 0) 68 | { 69 | //std::this_thread::sleep_for(std::chrono::nanoseconds(status.timeout)); 70 | } 71 | 72 | //check the command executed ok 73 | auto status2 = GetStatus(); 74 | if (status2.state != DFUState::DFU_DOWNLOAD_IDLE) 75 | { 76 | throw DFUException("Command execution failed"); 77 | } 78 | } 79 | 80 | auto DFU::Upload(const uint16_t &size, const uint8_t &wValue) const -> std::vector 81 | { 82 | InitUpload(); 83 | auto data = std::vector(size); 84 | auto err = libusb_control_transfer(device, 0xa1, static_cast(DFURequest::UPLOAD), wValue, 0, data.data(), data.size(), this->timeout); 85 | if (err < LIBUSB_SUCCESS) 86 | { 87 | throw DFUException(libusb_error_name(err)); 88 | } 89 | else 90 | { 91 | data.resize(err); 92 | } 93 | return data; 94 | } 95 | 96 | auto DFU::GetState() const -> DFUState 97 | { 98 | CheckDevice(); 99 | unsigned char state; 100 | auto err = libusb_control_transfer(device, 0xa1, static_cast(DFURequest::GETSTATE), 0, 0, &state, 1, this->timeout); 101 | if (err < LIBUSB_SUCCESS) 102 | { 103 | throw DFUException(libusb_error_name(err)); 104 | } 105 | else 106 | { 107 | auto s = static_cast((int)state); 108 | //std::cerr << "State: " << ::ToString(s) << std::endl; 109 | return s; 110 | } 111 | } 112 | 113 | auto DFU::GetStatus() const -> const DFUStatusReport 114 | { 115 | CheckDevice(); 116 | auto constexpr StatusSize = 6; 117 | 118 | unsigned char data[StatusSize]; 119 | auto err = libusb_control_transfer(device, 0xa1, static_cast(DFURequest::GETSTATUS), 0, 0, data, StatusSize, this->timeout); 120 | if (err < LIBUSB_SUCCESS) 121 | { 122 | throw DFUException(libusb_error_name(err)); 123 | } 124 | else 125 | { 126 | return DFUStatusReport::Parse(data); 127 | } 128 | return DFUStatusReport::Empty(); 129 | } 130 | 131 | auto DFU::Abort() const -> void 132 | { 133 | CheckDevice(); 134 | auto err = libusb_control_transfer(device, 0x21, static_cast(DFURequest::ABORT), 0, 0, nullptr, 0, this->timeout); 135 | if (err < LIBUSB_SUCCESS) 136 | { 137 | throw DFUException(libusb_error_name(err)); 138 | } 139 | } 140 | 141 | auto DFU::Detach() const -> void 142 | { 143 | CheckDevice(); 144 | auto err = libusb_control_transfer(device, 0x21, static_cast(DFURequest::DETACH), 0, 0, nullptr, 0, this->timeout); 145 | if (err < LIBUSB_SUCCESS) 146 | { 147 | throw DFUException(libusb_error_name(err)); 148 | } 149 | } 150 | 151 | auto DFU::CheckDevice() const -> void 152 | { 153 | if (this->device == nullptr) 154 | throw std::runtime_error("Device is not opened"); 155 | } 156 | 157 | auto DFU::InitDownload() const -> void 158 | { 159 | CheckDevice(); 160 | while (1) 161 | { 162 | auto state = GetState(); 163 | switch (state) 164 | { 165 | case DFUState::DFU_DOWNLOAD_IDLE: 166 | case DFUState::DFU_IDLE: 167 | return; 168 | default: 169 | { 170 | Abort(); 171 | break; 172 | } 173 | } 174 | } 175 | } 176 | 177 | auto DFU::InitUpload() const -> void 178 | { 179 | CheckDevice(); 180 | while (1) 181 | { 182 | auto state = GetState(); 183 | switch (state) 184 | { 185 | case DFUState::DFU_UPLOAD_IDLE: 186 | case DFUState::DFU_IDLE: 187 | return; 188 | default: 189 | { 190 | Abort(); 191 | break; 192 | } 193 | } 194 | } 195 | } -------------------------------------------------------------------------------- /src/hid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace radio_tool::hid; 6 | 7 | auto HID::InterruptRead(const uint8_t &ep, const uint16_t &len) const -> std::vector 8 | { 9 | std::vector data(len); 10 | 11 | int rlen = 0; 12 | auto err = libusb_interrupt_transfer(device, ep, data.data(), len, &rlen, timeout); 13 | if (err != LIBUSB_SUCCESS) 14 | { 15 | throw std::runtime_error(libusb_error_name(err)); 16 | } 17 | 18 | if (rlen != len) 19 | { 20 | data.reserve(rlen); 21 | } 22 | return data; 23 | } 24 | 25 | auto HID::InterruptWrite(const uint8_t &ep, const std::vector &data) const -> void 26 | { 27 | int rlen = 0; 28 | auto err = libusb_interrupt_transfer(device, ep, (unsigned char *)data.data(), data.size(), &rlen, timeout); 29 | if (err != LIBUSB_SUCCESS) 30 | { 31 | throw std::runtime_error(libusb_error_name(err)); 32 | } 33 | 34 | if (rlen != data.size()) 35 | { 36 | throw std::runtime_error("Invalid write len!"); 37 | } 38 | } 39 | 40 | auto HID::BulkRead(const uint8_t &ep, const uint16_t &len) const -> std::vector 41 | { 42 | std::vector data(len); 43 | 44 | int rlen = 0; 45 | auto err = libusb_interrupt_transfer(device, ep, data.data(), len, &rlen, timeout); 46 | if (err != LIBUSB_SUCCESS) 47 | { 48 | throw std::runtime_error(libusb_error_name(err)); 49 | } 50 | 51 | if (rlen != len) 52 | { 53 | data.reserve(rlen); 54 | } 55 | return data; 56 | } 57 | 58 | auto HID::BulkWrite(const uint8_t &ep, const std::vector &data) const -> void 59 | { 60 | int rlen = 0; 61 | auto err = libusb_bulk_transfer(device, ep, (unsigned char *)data.data(), data.size(), &rlen, timeout); 62 | if (err != LIBUSB_SUCCESS) 63 | { 64 | throw std::runtime_error(libusb_error_name(err)); 65 | } 66 | 67 | if (rlen != data.size()) 68 | { 69 | throw std::runtime_error("Invalid write len!"); 70 | } 71 | } -------------------------------------------------------------------------------- /src/radio_factory.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | using namespace radio_tool::radio; 25 | 26 | auto RadioFactory::OpenDevice(const uint16_t &index) const -> RadioOperations * 27 | { 28 | auto devices = ListDevices(); 29 | 30 | auto info = devices.at(index); 31 | if (info == nullptr) 32 | { 33 | throw std::runtime_error("Invalid device index"); 34 | } 35 | 36 | return info->OpenDevice(); 37 | } 38 | 39 | auto RadioFactory::ListDevices() const -> const std::vector 40 | { 41 | uint16_t idx_offset = 0; 42 | auto ret = std::vector(); 43 | 44 | auto usb = USBRadioFactory(); 45 | auto usbDevices = usb.ListDevices(idx_offset); 46 | ret.insert(ret.end(), usbDevices.begin(), usbDevices.end()); 47 | idx_offset += (uint16_t)usbDevices.size(); 48 | 49 | auto serial = SerialRadioFactory(); 50 | auto serialDevices = serial.ListDevices(idx_offset); 51 | ret.insert(ret.end(), serialDevices.begin(), serialDevices.end()); 52 | 53 | return ret; 54 | } -------------------------------------------------------------------------------- /src/rdt.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | using namespace radio_tool::codeplug; 24 | 25 | auto RDT::Read(const std::string& file) -> void 26 | { 27 | std::ifstream file_read(file, std::ios_base::in | std::ios_base::binary); 28 | if (file_read.is_open()) 29 | { 30 | header.Read(file_read); 31 | 32 | //skip to timestamp 33 | file_read.seekg(header.GetTimestampOffset(), std::ios_base::cur); 34 | 35 | uint8_t ts_data[7]; 36 | file_read.read((char*)ts_data, 7); 37 | 38 | timestamp = ParseBCDTimestamp(ts_data); 39 | } 40 | else 41 | { 42 | throw std::runtime_error("Cant open file"); 43 | } 44 | 45 | } 46 | 47 | auto RDT::Write(const std::string&) const -> void 48 | { 49 | } 50 | 51 | auto RDT::GetData() const -> const std::vector 52 | { 53 | throw std::runtime_error("Not implemented"); 54 | } 55 | 56 | auto RDT::ToString() const -> const std::string 57 | { 58 | std::stringstream out; 59 | 60 | out 61 | << " == RDT Codeplug ==" << std::endl 62 | << "Radio: " << header.radio << std::endl 63 | << "Created: " << ctime(×tamp) //<< std::endl 64 | << "Target: " << header.target_name << std::endl; 65 | return out.str(); 66 | } -------------------------------------------------------------------------------- /src/serial_radio_factory.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #ifdef _WIN32 28 | #define WIN32_LEAN_AND_MEAN 1 29 | #include 30 | #else 31 | #include 32 | namespace fs = std::filesystem; 33 | #endif 34 | 35 | using namespace radio_tool::radio; 36 | 37 | struct DeviceMapper 38 | { 39 | std::function SupportsDevice; 40 | std::function CreateOperations; 41 | }; 42 | 43 | const std::vector Drivers = { 44 | {AilunceRadio::SupportsDevice, AilunceRadio::Create} }; 45 | 46 | auto SerialRadioFactory::ListDevices(const uint16_t& idx_offset) const -> const std::vector 47 | { 48 | auto ret = std::vector(); 49 | 50 | OpDeviceList( 51 | [&ret, idx_offset](const std::string& port, const uint16_t& idx) 52 | { 53 | for (auto& driver : Drivers) 54 | { 55 | auto fnOpen = [&driver, port]() 56 | { 57 | return driver.CreateOperations(port); 58 | }; 59 | 60 | if (driver.SupportsDevice(port)) 61 | { 62 | ret.push_back(new SerialRadioInfo(fnOpen, port, idx_offset + idx)); 63 | } 64 | } 65 | }); 66 | return ret; 67 | } 68 | 69 | #ifdef _WIN32 70 | auto SerialRadioFactory::OpDeviceList(std::function fn) const -> void 71 | { 72 | HKEY comKey = nullptr; 73 | auto openResult = RegOpenKeyExA(HKEY_LOCAL_MACHINE, (LPSTR)"HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_READ | KEY_WOW64_64KEY, &comKey); 74 | if (openResult != ERROR_SUCCESS) 75 | { 76 | throw std::runtime_error("Failed to enumerate serial ports"); 77 | } 78 | 79 | constexpr auto BufferSize = 1024L; 80 | auto idx = 0UL; 81 | char name[BufferSize] = {}, value[BufferSize] = {}; 82 | while (1) 83 | { 84 | auto nameSize = BufferSize; 85 | auto valueSize = BufferSize; 86 | memset(name, 0, BufferSize); 87 | memset(value, 0, BufferSize); 88 | 89 | auto readResult = RegEnumValueA(comKey, idx, name, (LPDWORD)&nameSize, NULL, NULL, (LPBYTE)value, (LPDWORD)&valueSize); 90 | if (readResult == ERROR_SUCCESS) 91 | { 92 | fn(std::string(value), (uint16_t)idx); 93 | } 94 | else if (readResult == ERROR_NO_MORE_ITEMS) 95 | { 96 | break; 97 | } 98 | else 99 | { 100 | throw std::runtime_error("Error reading registory key values"); 101 | } 102 | idx++; 103 | } 104 | 105 | RegCloseKey(comKey); 106 | } 107 | 108 | #else 109 | auto SerialRadioFactory::OpDeviceList(std::function op) const -> void 110 | { 111 | #ifdef __APPLE__ 112 | auto p = fs::path("/dev"); 113 | auto idx = 0; 114 | for (const auto& de : fs::directory_iterator(p)) 115 | { 116 | auto stem = de.path().stem().string(); 117 | if (stem == "tty" || stem == "cu") 118 | { 119 | op(de.path().string(), idx++); 120 | } 121 | } 122 | #else 123 | //https://stackoverflow.com/a/65764414 124 | auto p = fs::path("/dev/serial/by-id"); 125 | if (!fs::exists(p)) 126 | { 127 | return; 128 | } 129 | 130 | auto idx = 0; 131 | for (auto& de : fs::directory_iterator(p)) 132 | { 133 | if (fs::is_symlink(de.symlink_status())) 134 | { 135 | auto canonical_path = fs::canonical(de); 136 | op(canonical_path.string(), idx++); 137 | } 138 | } 139 | #endif 140 | } 141 | #endif -------------------------------------------------------------------------------- /src/tyt_dfu.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | using namespace radio_tool::dfu; 25 | 26 | auto TYTDFU::IdentifyDevice() const -> std::string 27 | { 28 | auto data = ReadRegister(TYTRegister::RadioInfo); 29 | 30 | //model is null-terminated str, get len with strlen 31 | auto slen = strlen((const char*)data.data()); 32 | return std::string(data.begin(), data.begin() + slen + 1); 33 | } 34 | 35 | auto TYTDFU::ReadRegister(const TYTRegister& reg) const -> std::vector 36 | { 37 | Download({ static_cast(TYTDFU::RegisterCommand), 38 | static_cast(reg) }); 39 | 40 | return Upload(TYTDFU::RegisterSize); 41 | } 42 | 43 | auto TYTDFU::GetTime() const -> time_t 44 | { 45 | InitUpload(); 46 | auto time = ReadRegister(TYTRegister::RTC); 47 | 48 | return ParseBCDTimestamp(time.data()); 49 | } 50 | 51 | auto TYTDFU::SetTime() const -> void 52 | { 53 | Download({ TYTDFU::CustomCommand, 54 | static_cast(TYTCommand::SetRTC) }); 55 | 56 | time_t rawtime; 57 | time(&rawtime); 58 | auto timeinfo = localtime(&rawtime); 59 | auto ts = MakeBCDTimestamp(*timeinfo); 60 | ts.insert(ts.begin(), 0xb5); 61 | 62 | Download(ts); 63 | //Reboot(); 64 | } 65 | 66 | auto TYTDFU::Reboot() const -> void 67 | { 68 | Download({ TYTDFU::CustomCommand, 69 | static_cast(TYTCommand::ProgrammingMode) }); 70 | 71 | //this will normally throw an exception because the device 72 | //will not respond it will reboot immediately 73 | Download({ TYTDFU::CustomCommand, 74 | static_cast(TYTCommand::Reboot) }); 75 | } 76 | 77 | auto TYTDFU::SendTYTCommand(const TYTCommand& cmd) const -> void 78 | { 79 | Download({ TYTDFU::CustomCommand, 80 | static_cast(cmd) }); 81 | } -------------------------------------------------------------------------------- /src/tyt_fw.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #include 19 | #include 20 | 21 | using namespace radio_tool::fw; 22 | 23 | auto TYTFW::Read(const std::string& file) -> void 24 | { 25 | const auto HeaderSize = 0x100; 26 | 27 | auto i = std::ifstream(file, std::ios_base::binary); 28 | if (i.is_open()) 29 | { 30 | auto header = ReadHeader(i); 31 | CheckHeader(header); 32 | 33 | firmware_model = std::string(header.radio, header.radio + strlen((const char*)header.radio)); 34 | counterMagic = std::vector(header.counter_magic, header.counter_magic + 1 + header.counter_magic[0]); 35 | radio_model = GetRadioFromMagic(counterMagic); 36 | 37 | auto binarySize = 0; 38 | for (uint32_t nMem = 0; nMem < header.n_regions; nMem++) 39 | { 40 | uint32_t rStart = 0, rLength = 0; 41 | i.read((char*)&rStart, 4); 42 | i.read((char*)&rLength, 4); 43 | memory_ranges.push_back(std::make_pair(rStart, rLength)); 44 | binarySize += rLength; 45 | } 46 | 47 | //skip to binary 48 | i.seekg(HeaderSize); 49 | 50 | data.resize(binarySize); 51 | i.read((char*)data.data(), data.size()); 52 | 53 | //meh ignore footer 54 | } 55 | i.close(); 56 | } 57 | 58 | auto TYTFW::Write(const std::string& file) -> void 59 | { 60 | std::ofstream fout(file, std::ios_base::binary); 61 | if (fout.is_open()) 62 | { 63 | //make header 64 | TYTFirmwareHeader h = {}; 65 | h.n1 = 0x30000230; 66 | h.n2 = 0x47004000; 67 | std::copy(tyt::magic::begin.begin(), tyt::magic::begin.end(), h.magic); 68 | std::copy(firmware_model.begin(), firmware_model.end(), h.radio); 69 | for (auto cx = 0; cx < 76; cx++) 70 | { 71 | if (cx > 0x20) 72 | { 73 | h.counter_magic[cx] = 0xff; 74 | } 75 | else 76 | { 77 | h.counter_magic[cx] = cx; 78 | } 79 | } 80 | std::copy(counterMagic.begin(), counterMagic.end(), h.counter_magic); 81 | h.n_regions = memory_ranges.size(); 82 | 83 | //write the header 84 | fout.write((char*)&h, sizeof(TYTFirmwareHeader)); 85 | 86 | //write region info 87 | for (const auto& rx : memory_ranges) 88 | { 89 | fout.write((char*)&rx.first, sizeof(uint32_t)); 90 | fout.write((char*)&rx.second, sizeof(uint32_t)); 91 | } 92 | 93 | //add padding 94 | for (uint32_t pad_x = 0; pad_x < 0x80 - (sizeof(uint32_t) * memory_ranges.size() * 2); pad_x++) 95 | { 96 | fout.put(0xff); 97 | } 98 | 99 | //write firmware data 100 | fout.write((char*)data.data(), data.size()); 101 | 102 | //add footer padding 103 | for (auto pad_end = 0; pad_end < 0x100 - 16; pad_end++) 104 | { 105 | fout.put(0xff); 106 | } 107 | 108 | //add end magic 109 | fout.write((char*)tyt::magic::end.data(), tyt::magic::end.size()); 110 | 111 | fout.close(); 112 | } 113 | } 114 | 115 | auto TYTFW::ToString() const -> std::string 116 | { 117 | std::stringstream out; 118 | out << "== TYT Firmware == " << std::endl 119 | << "Radio: " << firmware_model << " (" << radio_model << ")" << std::endl 120 | << "Size: " << FormatBytes(data.size()) << std::endl 121 | << "Data Segments: " << std::endl; 122 | auto n = 0; 123 | for (const auto& m : memory_ranges) 124 | { 125 | out << " " << n++ << ": Start=0x" << std::setfill('0') << std::setw(8) << std::hex << m.first 126 | << ", Length=0x" << std::setfill('0') << std::setw(8) << std::hex << m.second 127 | << std::endl; 128 | } 129 | return out.str(); 130 | } 131 | 132 | auto TYTFW::ReadHeader(std::ifstream& i) -> TYTFirmwareHeader 133 | { 134 | TYTFirmwareHeader ret = {}; 135 | i.seekg(0, i.beg); 136 | i.read((char*)&ret, sizeof(TYTFirmwareHeader)); 137 | 138 | if (ret.n_regions == std::numeric_limits::max()) 139 | { 140 | ret.n_regions = 1; //if 0xFFFFFFFF then assume 1 141 | } 142 | 143 | return ret; 144 | } 145 | 146 | auto TYTFW::CheckHeader(const TYTFirmwareHeader& header) -> void 147 | { 148 | if (!std::equal(tyt::magic::begin.begin(), tyt::magic::begin.end(), header.magic)) 149 | { 150 | throw std::runtime_error("Invalid start magic"); 151 | } 152 | 153 | if (header.counter_magic[0] > 3) 154 | { 155 | throw std::runtime_error("Invalid counter magic length"); 156 | } 157 | 158 | auto magic_match = false; 159 | for (const auto& r : tyt::config::All) 160 | { 161 | //header.counter_magic should always be longer than r.second 162 | if (std::equal(r.counter_magic.begin(), r.counter_magic.end(), header.counter_magic)) 163 | { 164 | magic_match = true; 165 | break; 166 | } 167 | } 168 | if (!magic_match) 169 | { 170 | throw std::runtime_error("Counter magic is invalid, or not supported"); 171 | } 172 | 173 | if ((header.n_regions * 8) > 0x80) 174 | { 175 | throw std::runtime_error("Memory region count out of bounds"); 176 | } 177 | } 178 | 179 | auto TYTFW::SupportsFirmwareFile(const std::string& file) -> bool 180 | { 181 | std::ifstream i; 182 | i.open(file, i.binary); 183 | if (i.is_open()) 184 | { 185 | auto header = ReadHeader(i); 186 | i.close(); 187 | 188 | try 189 | { 190 | CheckHeader(header); 191 | } 192 | catch (std::exception&) 193 | { 194 | return false; 195 | } 196 | 197 | return true; 198 | } 199 | else 200 | { 201 | throw std::runtime_error("Can't open firmware file"); 202 | } 203 | } 204 | 205 | auto TYTFW::SupportsRadioModel(const std::string& model) -> bool 206 | { 207 | for (const auto& mx : tyt::config::All) 208 | { 209 | if (mx.radio_model == model) 210 | { 211 | return true; 212 | } 213 | } 214 | return false; 215 | } 216 | 217 | auto TYTFW::GetRadioModel() const -> const std::string 218 | { 219 | return GetRadioFromMagic(counterMagic); 220 | } 221 | 222 | 223 | auto TYTFW::SetRadioModel(const std::string& model) -> void 224 | { 225 | for (const auto& rg : tyt::config::All) 226 | { 227 | if (rg.radio_model == model) 228 | { 229 | counterMagic = rg.counter_magic; 230 | radio_model = rg.radio_model; 231 | firmware_model = rg.firmware_model; 232 | break; 233 | } 234 | } 235 | } 236 | 237 | auto TYTFW::Decrypt() -> void 238 | { 239 | ApplyXOR(); 240 | } 241 | 242 | auto TYTFW::Encrypt() -> void 243 | { 244 | ApplyXOR(); 245 | } 246 | 247 | auto TYTFW::ApplyXOR() -> void 248 | { 249 | const uint8_t* xor_model = nullptr; 250 | uint32_t xor_len = 1024; 251 | 252 | for (const auto& r : tyt::config::All) 253 | { 254 | if (std::equal(r.counter_magic.begin(), r.counter_magic.end(), counterMagic.begin(), counterMagic.end())) 255 | { 256 | xor_model = r.cipher; 257 | xor_len = r.cipher_len; 258 | break; 259 | } 260 | } 261 | 262 | if (xor_model == nullptr) 263 | { 264 | throw std::runtime_error("No cipher found"); 265 | } 266 | 267 | radio_tool::ApplyXOR(data, xor_model, xor_len); 268 | } 269 | 270 | auto TYTFW::IsCompatible(const FirmwareSupport* Other) const -> bool 271 | { 272 | if (typeid(Other) != typeid(this)) { 273 | return false; 274 | } 275 | 276 | auto afw = dynamic_cast(Other); 277 | return afw->radio_model == radio_model 278 | && afw->firmware_model == firmware_model; 279 | } -------------------------------------------------------------------------------- /src/tyt_hid.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | using namespace radio_tool::hid; 24 | 25 | auto TYTHID::Setup() -> void 26 | { 27 | auto err = 0; 28 | 29 | err = libusb_set_configuration(device, 0x01); 30 | if (err != LIBUSB_SUCCESS) 31 | { 32 | libusb_close(device); 33 | throw std::runtime_error(libusb_error_name(err)); 34 | } 35 | err = libusb_claim_interface(device, 0x00); 36 | if (err != LIBUSB_SUCCESS) 37 | { 38 | libusb_close(device); 39 | throw std::runtime_error(libusb_error_name(err)); 40 | } 41 | err = libusb_control_transfer(device, 0x21, 0x0a, 0, 0, nullptr, 0, timeout); 42 | if (err != LIBUSB_SUCCESS) 43 | { 44 | libusb_close(device); 45 | throw std::runtime_error(libusb_error_name(err)); 46 | } 47 | /* 48 | auto buffer = (uint8_t*)malloc(64); 49 | auto tx = libusb_alloc_transfer(0); 50 | libusb_fill_interrupt_transfer( 51 | tx, device, TYTHID::EP_IN, buffer, 64, [](libusb_transfer* tx) 52 | { 53 | auto self = (TYTHID*)tx->user_data; 54 | self->OnTransfer(tx); 55 | }, 56 | this, 5000); 57 | libusb_submit_transfer(tx); 58 | */ 59 | } 60 | 61 | auto TYTHID::OnTransfer(libusb_transfer* tx) -> void 62 | { 63 | if (tx->status == LIBUSB_TRANSFER_COMPLETED || 64 | tx->status == LIBUSB_TRANSFER_TIMED_OUT) 65 | { 66 | { 67 | std::lock_guard lk(signalCallback); 68 | this->tx = tx; 69 | } 70 | signalReady.notify_one(); 71 | 72 | //wait again for item to be read 73 | { 74 | std::unique_lock lk(signalCallback); 75 | auto tx_local = &this->tx; 76 | signalReady.wait(lk, [tx_local] 77 | { return *tx_local == nullptr; }); 78 | } 79 | } 80 | libusb_submit_transfer(tx); 81 | } 82 | 83 | auto TYTHID::SendCommand(const tyt::Command& cmd) -> tyt::Command 84 | { 85 | std::vector payload((int)cmd.data.size() + 4); 86 | std::fill(payload.begin(), payload.end(), 0x00); 87 | 88 | auto nums = (uint16_t*)payload.data(); 89 | nums[0] = (uint16_t)cmd.type; 90 | nums[1] = cmd.data.size(); 91 | std::copy(cmd.data.begin(), cmd.data.end(), payload.begin() + 4); 92 | 93 | InterruptWrite(TYTHID::EP_OUT, payload); 94 | auto data = InterruptRead(TYTHID::EP_IN, 42); 95 | auto type = ((uint16_t)data[1] << 8) | data[0]; 96 | auto len = ((uint16_t)data[3] << 8) | data[2]; 97 | return tyt::Command((tyt::CommandType)type, len, 98 | std::vector(data.begin() + 4, data.begin() + 4 + len)); 99 | } 100 | 101 | auto TYTHID::SendCommand(const std::vector& cmd) -> tyt::Command 102 | { 103 | return SendCommand(tyt::Command(tyt::CommandType::HostToDevice, cmd.size(), cmd)); 104 | } 105 | 106 | auto TYTHID::SendCommand(const std::vector& cmd, const uint8_t& size, const uint8_t& fill) -> tyt::Command 107 | { 108 | auto ncmd = std::vector(size, fill); 109 | std::copy(cmd.begin(), cmd.end(), ncmd.begin()); 110 | 111 | return SendCommand(ncmd); 112 | } 113 | 114 | auto TYTHID::WaitForReply() -> tyt::Command 115 | { 116 | std::unique_lock lk(signalCallback); 117 | auto tx_local = &this->tx; 118 | signalReady.wait(lk, [tx_local] 119 | { return *tx_local != nullptr; }); 120 | 121 | if (tx->status == LIBUSB_TRANSFER_COMPLETED) 122 | { 123 | //setup return 124 | auto nums = (uint16_t*)tx->buffer; 125 | auto ret = tyt::Command((tyt::CommandType)nums[0], nums[1], std::vector(tx->buffer + 4, tx->buffer + 4 + nums[1])); 126 | radio_tool::PrintHex(ret.data.begin(), ret.data.end()); 127 | 128 | tx = nullptr; 129 | lk.unlock(); 130 | signalReady.notify_one(); 131 | return ret; 132 | } 133 | 134 | throw std::runtime_error("USB TRANSFER ERROR"); 135 | } 136 | 137 | auto TYTHID::SendCommandAndOk(const tyt::Command& cmd) -> void 138 | { 139 | auto ok = SendCommand(cmd); 140 | if (!(ok == tyt::OKResponse)) 141 | { 142 | radio_tool::PrintHex(ok.data.begin(), ok.data.end()); 143 | throw std::runtime_error("Invalid usb response from device"); 144 | } 145 | } 146 | 147 | auto TYTHID::SendCommandAndOk(const std::vector& cmd) -> void 148 | { 149 | auto ok = SendCommand(cmd); 150 | if (!(ok == tyt::OKResponse)) 151 | { 152 | radio_tool::PrintHex(ok.data.begin(), ok.data.end()); 153 | throw std::runtime_error("Invalid usb response from device"); 154 | } 155 | } 156 | 157 | auto TYTHID::SendCommandAndOk(const std::vector& cmd, const uint8_t& size, const uint8_t& fill) -> void 158 | { 159 | auto ok = SendCommand(cmd, size, fill); 160 | if (!(ok == tyt::OKResponse)) 161 | { 162 | radio_tool::PrintHex(ok.data.begin(), ok.data.end()); 163 | throw std::runtime_error("Invalid usb response from device"); 164 | } 165 | } -------------------------------------------------------------------------------- /src/tyt_radio.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | using namespace radio_tool::radio; 30 | 31 | auto TYTRadio::ToString() const -> const std::string 32 | { 33 | std::stringstream out; 34 | 35 | auto model = dfu.IdentifyDevice(); 36 | auto time = dfu.GetTime(); 37 | 38 | out << "== TYT Radio Info ==" << std::endl 39 | << "Radio: " << model << std::endl 40 | << "RTC: " << (time == -1 ? "N/A" : ctime(&time)); 41 | 42 | return out.str(); 43 | } 44 | 45 | auto TYTRadio::WriteFirmware(const std::string& file) -> void 46 | { 47 | constexpr auto TransferSize = 1024u; 48 | 49 | auto fw = fw::TYTFW(); 50 | fw.Read(file); 51 | 52 | auto dfu = this->dfu; 53 | dfu.SendTYTCommand(dfu::TYTCommand::FirmwareUpgrade); 54 | for (auto& r : fw.GetDataSegments()) 55 | { 56 | flash::FlashUtil::AlignedContiguousMemoryOp(flash::STM32F40X, r.address, r.address + r.size, 57 | [&dfu](const uint32_t& addr, const uint32_t& size, const flash::FlashSector& sector) { 58 | std::cerr << "Erasing: 0x" << std::setw(8) << std::setfill('0') << std::hex << addr 59 | << " [Size=0x" << std::hex << size << "]" << std::endl 60 | << "-- " << sector.ToString() << std::endl; 61 | 62 | dfu.Erase(addr); 63 | }); 64 | 65 | auto b_offset = 0u; 66 | flash::FlashUtil::AlignedContiguousMemoryOp(flash::STM32F40X, r.address, r.address + r.size, 67 | [&dfu, &r, &TransferSize, &b_offset](const uint32_t& addr, const uint32_t& size, const flash::FlashSector&) { 68 | const auto& binary_data = r.data; 69 | const auto blocks = (int)ceil(size / (double)TransferSize); 70 | 71 | std::cerr << "Writing: 0x" << std::setw(8) << std::setfill('0') << std::hex << addr 72 | << " [Size=0x" << std::hex << size << "]" << std::endl; 73 | dfu.SetAddress(addr); 74 | for (auto wValue = 0; wValue < blocks; wValue++) 75 | { 76 | auto block_offset = b_offset + (TransferSize * wValue); 77 | auto to_write = std::vector( 78 | binary_data.begin() + block_offset, 79 | binary_data.begin() + block_offset + std::min(TransferSize, r.size - block_offset) 80 | ); 81 | 82 | /*std::cerr 83 | << "-- wValue=0x" << std::setw(2) << std::setfill('0') << std::hex << (2 + wValue) 84 | << ", Size=0x" << to_write.size() 85 | << std::endl;*/ 86 | dfu.Download(to_write, 2 + wValue); 87 | } 88 | b_offset += size; 89 | }); 90 | } 91 | } -------------------------------------------------------------------------------- /src/tyt_sgl_radio.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2021 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "radio_tool/util.hpp" 27 | 28 | using namespace radio_tool::radio; 29 | 30 | TYTSGLRadio::TYTSGLRadio(libusb_device_handle *h) : device(h) 31 | { 32 | device.Setup(); 33 | } 34 | 35 | auto TYTSGLRadio::ToString() const -> const std::string 36 | { 37 | std::stringstream out; 38 | 39 | out << "== TYT SGL Radio Info ==" << std::endl 40 | << "Radio: " 41 | << "ASD" << std::endl 42 | << "RTC: " 43 | << "000"; 44 | 45 | return out.str(); 46 | } 47 | 48 | auto TYTSGLRadio::WriteFirmware(const std::string &file) -> void 49 | { 50 | fw::TYTSGLFW fw; 51 | fw.Read(file); 52 | auto config = fw.GetConfig(); 53 | 54 | auto rsp = device.SendCommand(hid::tyt::commands::Download); 55 | if (std::equal(rsp.data.begin(), rsp.data.end(), hid::tyt::commands::Update.begin())) 56 | { 57 | device.SendCommandAndOk(hid::tyt::OK); 58 | } 59 | else 60 | { 61 | auto download_rsp = std::string(rsp.data.begin(), rsp.data.end()); 62 | auto update_rsp = std::string(hid::tyt::commands::Update.begin(), hid::tyt::commands::Update.end()); 63 | std::stringstream msg("Invalid response, expected '"); 64 | msg << update_rsp << "'" 65 | << " got '" << download_rsp << "'"; 66 | 67 | throw new std::runtime_error(msg.str()); 68 | } 69 | 70 | // send key 71 | auto rsp_key = device.SendCommand(std::vector(config->header.model_key.begin(), config->header.model_key.end()), 0x08, 0xff); 72 | if (!std::equal(rsp_key.data.begin(), rsp_key.data.end(), config->header.model_key.begin())) 73 | { 74 | auto key_rsp = std::string(rsp_key.data.begin(), rsp_key.data.end()); 75 | std::stringstream msg("Invalid response, expected firmware key '"); 76 | msg << config->header.model_key << "'" 77 | << " got '" << key_rsp << "'"; 78 | 79 | throw new std::runtime_error(msg.str()); 80 | } 81 | 82 | device.SendCommandAndOk(hid::tyt::commands::FlashProgram, 0x08, 0xff); 83 | 84 | device.SendCommandAndOk(std::vector(config->header.radio_group.begin(), config->header.radio_group.end()), 0x10, 0xff); 85 | device.SendCommandAndOk(std::vector(config->header.radio_model.begin(), config->header.radio_model.end()), 0x08, 0xff); 86 | device.SendCommandAndOk(std::vector(config->header.protocol_version.begin(), config->header.protocol_version.end())); 87 | 88 | device.SendCommandAndOk(hid::tyt::commands::FlashErase, 0x08, 0xff); 89 | device.SendCommandAndOk(hid::tyt::OK); 90 | device.SendCommandAndOk(hid::tyt::commands::Program, 0x08, 0xff); 91 | 92 | constexpr auto TransferSize = 0x20u; 93 | constexpr auto HeaderSize = 0x06u; 94 | constexpr auto ChecksumBlockSize = 0x400u; 95 | 96 | auto buf = std::vector(TransferSize + HeaderSize); 97 | auto binary = fw.GetDataSegments()[0]; 98 | auto address = 0; 99 | auto checksumBlock = 0; 100 | while (address < binary.size) 101 | { 102 | auto transferSize = std::min(TransferSize, binary.size - address); 103 | *(uint32_t *)buf.data() = bswap32(address); 104 | *(uint16_t *)(buf.data() + 4) = bswap16(transferSize); 105 | 106 | auto src = binary.data.begin() + address; 107 | std::copy(src, src + transferSize, buf.begin() + HeaderSize); 108 | 109 | device.SendCommandAndOk(buf); 110 | 111 | address += transferSize; 112 | if (address % ChecksumBlockSize == 0 || address == binary.size) 113 | { 114 | auto start = ChecksumBlockSize * checksumBlock; 115 | auto end = address; 116 | 117 | auto checksumCommand = std::vector(hid::tyt::commands::End.size() + 5, 0xff); 118 | std::copy(hid::tyt::commands::End.begin(), hid::tyt::commands::End.end(), checksumCommand.begin()); 119 | *(uint32_t *)(checksumCommand.data() + hid::tyt::commands::End.size() + 1) = checksum(binary.data.begin() + start, binary.data.begin() + end); 120 | device.SendCommandAndOk(checksumCommand); 121 | 122 | checksumBlock++; 123 | std::cerr << "Sent block " << checksumBlock << std::endl; 124 | } 125 | } 126 | } 127 | 128 | auto TYTSGLRadio::checksum(std::vector::const_iterator &&begin, std::vector::const_iterator &&end) const -> uint32_t 129 | { 130 | uint32_t counter = 0; 131 | while (begin != end) 132 | { 133 | counter += *begin; 134 | std::advance(begin, 1); 135 | } 136 | return counter; 137 | } -------------------------------------------------------------------------------- /src/version.cpp.in: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2020 v0l 4 | * 5 | * radio_tool is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * radio_tool is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with radio_tool. If not, see . 17 | */ 18 | 19 | #include 20 | 21 | #define GIT_SHA1 "@GIT_SHA1@" 22 | #define GIT_SHA1_SHORT "@GIT_SHA1_SHORT@" 23 | #define PROJECT_VERSION "@PROJECT_VERSION@" 24 | #define PROJECT_NAME "@PROJECT_NAME@" 25 | 26 | const char g_GIT_SHA1[] = GIT_SHA1; 27 | 28 | const char g_GIT_SHA1_SHORT[] = GIT_SHA1_SHORT; 29 | 30 | const char g_PROJECT_VERSION[] = PROJECT_VERSION; 31 | 32 | const char g_PROJECT_NAME[] = PROJECT_NAME; -------------------------------------------------------------------------------- /src/yaesu_fw.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 v0l 4 | * Niccol� Izzo 5 | * 6 | * radio_tool is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * radio_tool is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with radio_tool. If not, see . 18 | */ 19 | #include 20 | #include 21 | 22 | using namespace radio_tool::fw; 23 | 24 | auto YaesuFW::Read(const std::string& file) -> void 25 | { 26 | auto i = std::ifstream(file, std::ios_base::binary); 27 | if (i.is_open()) 28 | { 29 | // Compute binary file size 30 | i.seekg(0, std::ios_base::end); 31 | auto binarySize = i.tellg(); 32 | i.seekg(0); 33 | 34 | // Read binary 35 | data.resize(binarySize); 36 | i.read((char*)data.data(), binarySize); 37 | 38 | // Pad with 0xFF until multiple of 1KiB 39 | data.resize(binarySize + ((1024 - binarySize % 1024) % 1024), 0xFF); 40 | } 41 | i.close(); 42 | } 43 | 44 | auto YaesuFW::Write(const std::string& file) -> void 45 | { 46 | std::ofstream fout(file, std::ios_base::binary); 47 | if (fout.is_open()) 48 | { 49 | // write firmware data 50 | fout.write((char*)data.data(), data.size()); 51 | fout.close(); 52 | } 53 | } 54 | 55 | auto YaesuFW::ToString() const -> std::string 56 | { 57 | std::stringstream out; 58 | out << "== Yaesu Firmware == " << std::endl 59 | << "Size: " << radio_tool::FormatBytes(data.size()) << std::endl; 60 | return out.str(); 61 | } 62 | 63 | auto YaesuFW::Decrypt() -> void {} 64 | auto YaesuFW::Encrypt() -> void {} 65 | auto YaesuFW::SetRadioModel(const std::string&) -> void {} 66 | auto YaesuFW::GetRadioModel() const -> const std::string 67 | { 68 | return "Unknown"; 69 | } 70 | 71 | auto YaesuFW::SupportsFirmwareFile(const std::string& file) -> bool 72 | { 73 | std::ifstream i; 74 | i.open(file, i.binary); 75 | if (i.is_open()) 76 | { 77 | return true; 78 | } 79 | else 80 | { 81 | throw std::runtime_error("Can't open firmware file"); 82 | } 83 | } 84 | 85 | auto YaesuFW::SupportsRadioModel(const std::string& model) -> bool 86 | { 87 | return true; 88 | } 89 | 90 | auto YaesuFW::IsCompatible(const FirmwareSupport* Other) const -> bool 91 | { 92 | if (typeid(Other) != typeid(this)) { 93 | return false; 94 | } 95 | 96 | auto afw = dynamic_cast(Other); 97 | return afw->radio_model == radio_model; 98 | } -------------------------------------------------------------------------------- /src/yaesu_radio.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is part of radio_tool. 3 | * Copyright (c) 2022 v0l 4 | * Niccolò Izzo 5 | * 6 | * radio_tool is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * radio_tool is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with radio_tool. If not, see . 18 | */ 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | using namespace radio_tool::radio; 29 | 30 | auto YaesuRadio::ToString() const -> const std::string 31 | { 32 | std::stringstream out; 33 | 34 | auto model = h8sx.IdentifyDevice(); 35 | 36 | out << "== Yaesu Radio Info ==" << std::endl 37 | << "Radio: " << model << std::endl; 38 | 39 | return out.str(); 40 | } 41 | 42 | auto YaesuRadio::WriteFirmware(const std::string& file) -> void 43 | { 44 | auto fw = fw::YaesuFW(); 45 | fw.Read(file); 46 | 47 | auto to_write = fw.GetData(); 48 | h8sx.Download(to_write); 49 | } 50 | -------------------------------------------------------------------------------- /src/ymodem_device.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/v0l/radio_tool/a1108b5af04aad706dc9988db7cddad6d91434f5/src/ymodem_device.cpp -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0.0) 2 | project(radio_tool_tests VERSION 0.1.0) 3 | 4 | include(ExternalData) 5 | set(ExternalData_URL_TEMPLATES 6 | "https://data.v0l.io/radio_tool/firmware/%(algo)/%(hash)" 7 | ) 8 | 9 | if (${CMAKE_CXX_COMPILER_ID} STREQUAL GNU OR ${CMAKE_CXX_COMPILER_ID} STREQUAL AppleClang) 10 | link_libraries(PkgConfig::LibUSB) 11 | include_directories(${LibUSB_INCLUDEDIR}) 12 | elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) 13 | include_directories(${VCPKG_INCLUDE_DIR}) 14 | link_directories(${VCPKG_LIB_DIR}) 15 | link_libraries(libusb-1.0) 16 | endif() 17 | 18 | include_directories(../include) 19 | link_libraries(radiotool) 20 | 21 | if(XOR_TOOL_INC) 22 | add_executable(test_xor test_xor_tool.cpp) 23 | include_directories(${XOR_TOOL_INC}) 24 | add_definitions(-DXOR_TOOL) 25 | endif() 26 | 27 | add_executable(test_fw test_fw.cpp) 28 | add_executable(test_util test_util.cpp) 29 | 30 | #Add firmware tests, "radio" is the model returned from GetRadioModel() 31 | function(AddFirmwareTest file radio) 32 | ExternalData_Add_Test(data_${file} 33 | NAME test_fw_${file} 34 | COMMAND test_fw DATA{./firmware/${file}} ${radio} 35 | ) 36 | if(XOR_TOOL_INC) 37 | ExternalData_Add_Test(data_${file} 38 | NAME test_xor_${file} 39 | COMMAND test_xor DATA{./firmware/${file}} 40 | ) 41 | endif() 42 | ExternalData_Add_Target(data_${file}) 43 | endfunction() 44 | 45 | #DM-1701 46 | AddFirmwareTest(dm1701_2.03.bin "DM1701") 47 | 48 | #MD-2017 49 | AddFirmwareTest(TYT2017_UV_CSV__V3.33.bin "MD2017") 50 | AddFirmwareTest(TYT2017_UV_CSV__V3.35.bin "MD2017") 51 | AddFirmwareTest(TYT2017_UV_CSV__V3.36.bin "MD2017") 52 | AddFirmwareTest(TYT2017_UV_CSV_GPS__P3.33.bin "MD2017 GPS") 53 | AddFirmwareTest(TYT2017_UV_CSV_GPS__P3.35.bin "MD2017 GPS") 54 | AddFirmwareTest(TYT2017_UV_CSV_GPS__P3.38.bin "MD2017 GPS") 55 | AddFirmwareTest(TYT2017_UV_GPS_REC__S3.31.bin "MD2017 GPS") 56 | AddFirmwareTest(TYT2017_UV_GPS_REC__S3.38.bin "MD2017 GPS") 57 | AddFirmwareTest(TYT2017_UV_REC__D3.31.bin "MD2017") 58 | AddFirmwareTest(TYT2017_UV_REC__D3.36.bin "MD2017") 59 | AddFirmwareTest(TYT2017_UVCSV_GPS_P3.35.bin "MD2017 GPS") 60 | AddFirmwareTest(TYT2017_UVCSV_V3.35.bin "MD2017") 61 | AddFirmwareTest(TYT2017_UVGPS_REC_S3.31.bin "MD2017 GPS") 62 | AddFirmwareTest(TYT2017_UVGPS_REC_S3.38.bin "MD2017 GPS") 63 | AddFirmwareTest(TYT2017_UVREC_D3.31.bin "MD2017") 64 | AddFirmwareTest(TYT2017_UVREC_D3.36.bin "MD2017") 65 | AddFirmwareTest(md2017_csv_v4.15.bin "MD2017") 66 | AddFirmwareTest(md2017_csv_gps_p4.17.bin "MD2017 GPS") 67 | AddFirmwareTest(md2017_rec_gps_s4.17.bin "MD2017 GPS") 68 | AddFirmwareTest(md2017_rec_d4.15.bin "MD2017") 69 | 70 | #MD-UV380 71 | AddFirmwareTest(uv380_csv_v18.11.bin "UV3X0") 72 | AddFirmwareTest(uv380_rec_d18.11.bin "UV3X0") 73 | 74 | #MD-UV390 75 | AddFirmwareTest(uv390_csv_gps_p18.11.bin "UV3X0 GPS") 76 | AddFirmwareTest(uv390_rec_gps_s18.11.bin "UV3X0 GPS") 77 | 78 | #MD-9600 79 | AddFirmwareTest(md9600_rec_gps_s6.13.bin "MD9600") 80 | AddFirmwareTest(md9600_csv_gps_p6.13.bin "MD9600") 81 | AddFirmwareTest(md9600_csv_v6.09.bin "MD9600") 82 | AddFirmwareTest(md9600_rec_d6.09.bin "MD9600") 83 | 84 | #MD-390 85 | AddFirmwareTest(TYT_Vocoder_MD390_S13.12.bin "MD390") 86 | AddFirmwareTest(TYT_Vocoder_MD390_S13.20.bin "MD390") 87 | AddFirmwareTest(TYT_Vocoder_MD390_S15.02.bin "MD390") 88 | AddFirmwareTest(TYT_Vocoder_MD390_S15.04.bin "MD390") 89 | 90 | #MD-380 91 | AddFirmwareTest(TYT_Vocoder_MD380_D13.14.bin "MD380") 92 | AddFirmwareTest(TYT_Vocoder_MD380_D13.20.bin "MD380") 93 | AddFirmwareTest(TYT_Vocoder_MD380_D14.07.bin "MD380") 94 | AddFirmwareTest(TYT_TFT_MD380_D3.20.bin "MD380") 95 | AddFirmwareTest(D013.034.bin "MD380") 96 | 97 | #MD-446 98 | AddFirmwareTest(TYT_Vocoder_MD446_D13.20.bin "MD380") 99 | AddFirmwareTest(TYT_TFT_MD446_D3.20.bin "MD380") 100 | 101 | #MD-280 102 | AddFirmwareTest(MD280.002.018.bin "MD280") 103 | 104 | #RT3S 105 | AddFirmwareTest(RT3S_CSV__V16.06.bin "UV3X0") 106 | AddFirmwareTest(RT3S_CSV_GPS__P16.06.bin "UV3X0 GPS") 107 | AddFirmwareTest(RT3S_GPS_REC__S16.06.bin "UV3X0 GPS") 108 | AddFirmwareTest(RT3S_REC__D16.06.bin "UV3X0") 109 | 110 | #CS800 111 | AddFirmwareTest(CS800D_Host_MS.30.14_Use_Flashburn3.0_Upgrade.bin "CS800") 112 | AddFirmwareTest(TEST_CS800_4000__Mobile_M100000_Host_S3.02.07_Auth_Test_Ver_1_.bin "CS800") 113 | 114 | #GD-77 115 | AddFirmwareTest(GD-77_V3.2.1.sgl "GD77") 116 | AddFirmwareTest(GD-77_V3.2.2.sgl "GD77") 117 | AddFirmwareTest(GD-77_V4.2.6.sgl "GD77") 118 | AddFirmwareTest(GD-77_V4.2.8.sgl "GD77") 119 | 120 | #GD-77S 121 | AddFirmwareTest(GD-77S_V1.2.0.sgl "GD77S") 122 | AddFirmwareTest(GD-77S_V1.3.0.sgl "GD77S") 123 | 124 | #BF-5R 125 | AddFirmwareTest(BF-5R_V2.1.0.sgl "BF5R") 126 | AddFirmwareTest(BF-5R_V2.1.6.sgl "BF5R") 127 | AddFirmwareTest(RD-5R_V2.0.9.sgl "BF5R") -------------------------------------------------------------------------------- /test/dummy_device.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | using namespace radio_tool::dfu; 10 | using namespace radio_tool::flash; 11 | 12 | namespace radio_tool::test 13 | { 14 | /** 15 | * A dummy device to check firwmare writing process is correct 16 | */ 17 | class DummyDevice : DFU 18 | { 19 | public: 20 | DummyDevice(const std::string& file, const FlashMap &map) 21 | : DFU(nullptr), file(file), map(map), address(0), state(DFUState::DFU_IDLE), status(DFUStatus::OK) 22 | { 23 | out = std::ofstream(file, std::ios_base::out | std::ios_base::binary); 24 | } 25 | 26 | auto SetAddress(const uint32_t& addr) -> void 27 | { 28 | address = addr; 29 | SeekToAddr(address); 30 | } 31 | 32 | auto Erase(const uint32_t&) const -> void 33 | { 34 | //nothing 35 | } 36 | 37 | auto Download(const std::vector &data, const uint16_t &wValue = 0) -> void 38 | { 39 | auto addr_offset = address + (data.size() * (wValue - 2)); 40 | 41 | SeekToAddr(addr_offset); 42 | out.write((const char*)data.data(), data.size()); 43 | state = DFUState::DFU_DOWNLOAD_BUSY; 44 | } 45 | 46 | auto Upload(const uint16_t &size, const uint8_t &wValue = 0) -> std::vector 47 | { 48 | state = DFUState::DFU_UPLOAD_BUSY; 49 | return std::vector(); 50 | } 51 | 52 | auto GetState() const -> DFUState 53 | { 54 | return state; 55 | } 56 | auto GetStatus() -> const DFUStatusReport 57 | { 58 | auto ret = DFUStatusReport(status, 0, state, 0); 59 | if(state == DFUState::DFU_DOWNLOAD_BUSY) { 60 | state = DFUState::DFU_DOWNLOAD_IDLE; 61 | } 62 | if(state == DFUState::DFU_UPLOAD_BUSY) 63 | { 64 | state = DFUState::DFU_UPLOAD_IDLE; 65 | } 66 | return ret; 67 | } 68 | auto Abort() -> void 69 | { 70 | state = DFUState::DFU_IDLE; 71 | } 72 | auto Detach() const -> void 73 | { 74 | //nothing 75 | } 76 | private: 77 | const std::string file; 78 | const FlashMap map; 79 | std::ofstream out; 80 | 81 | uint32_t address; 82 | DFUState state; 83 | DFUStatus status; 84 | 85 | constexpr auto FilePos(const uint32_t &addr) const -> const uint32_t 86 | { 87 | return address - map.front().start; 88 | } 89 | 90 | constexpr auto SeekToAddr(const uint32_t &addr) -> void 91 | { 92 | out.seekp(FilePos(addr)); 93 | } 94 | }; 95 | } // namespace radio_tool::test -------------------------------------------------------------------------------- /test/dump_sgl_info.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define HEX(x) std::setw(x) << std::setfill('0') << std::hex 8 | 9 | void HexDump(const void* data, size_t size) 10 | { 11 | char ascii[17]; 12 | size_t i, j; 13 | ascii[16] = '\0'; 14 | for (i = 0; i < size; ++i) { 15 | printf("%02X ", ((unsigned char*)data)[i]); 16 | if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { 17 | ascii[i % 16] = ((unsigned char*)data)[i]; 18 | } 19 | else { 20 | ascii[i % 16] = '.'; 21 | } 22 | if ((i + 1) % 8 == 0 || i + 1 == size) { 23 | printf(" "); 24 | if ((i + 1) % 16 == 0) { 25 | printf("| %s \n", ascii); 26 | } 27 | else if (i + 1 == size) { 28 | ascii[(i + 1) % 16] = '\0'; 29 | if ((i + 1) % 16 <= 8) { 30 | printf(" "); 31 | } 32 | for (j = (i + 1) % 16; j < 16; ++j) { 33 | printf(" "); 34 | } 35 | printf("| %s \n", ascii); 36 | } 37 | } 38 | } 39 | } 40 | 41 | int main(int argc, char **argv) 42 | { 43 | auto magic = "SGL!"; 44 | 45 | std::ifstream in(argv[1], std::ifstream::binary); 46 | if (in.is_open()) 47 | { 48 | std::cout << argv[1] << std::endl; 49 | 50 | in.seekg(0, in.end); 51 | auto file_len = in.tellg(); 52 | in.seekg(0, in.beg); 53 | 54 | auto h1_len = 16; 55 | char h1[h1_len]; 56 | in.read(h1, h1_len); 57 | 58 | // skip 4 for xor "SGL!" 59 | for (auto x0 = 4; x0 < h1_len; x0++) 60 | { 61 | h1[x0] ^= magic[x0 % 4]; 62 | } 63 | 64 | std::cout << "Header 1 (16):" << std::endl; 65 | HexDump(h1, h1_len); 66 | 67 | auto h2_offset = *(uint16_t*)(h1 + 12); 68 | std::cout << "Offset H2: " << h2_offset << std::endl; 69 | 70 | in.seekg(h2_offset, in.beg); 71 | 72 | auto h2_len = 0x67; 73 | char h2[h2_len]; 74 | in.read(h2, h2_len); 75 | 76 | char* h2_xor = h1 + 14; 77 | for (auto x0 = 0; x0 < h2_len; x0++) 78 | { 79 | h2[x0] ^= h2_xor[x0 % 2]; 80 | } 81 | std::cout << "Header 2 (" << h2_len << "):" << std::endl; 82 | HexDump(h2, h2_len); 83 | 84 | auto flen = *(uint32_t*)(h2 + 6); 85 | std::cout << "File Length: 0x" << std::hex << std::setw(8) << std::setfill('0') << flen << std::endl; 86 | 87 | in.seekg(0x400, in.beg); 88 | uint32_t binary_start = (int)h1[11]; 89 | in.seekg(binary_start, in.cur); 90 | std::cout << "Binary Start Offset: 1024 + " << std::dec << binary_start << std::endl; 91 | 92 | uint32_t binary_len = file_len - 0x400L - binary_start; 93 | char binary[binary_len]; 94 | in.read(binary, binary_len); 95 | std::cout << "Binary (" << binary_len << "):" << std::endl; 96 | //HexDump(binary, binary_len); 97 | 98 | std::cout << std::endl; 99 | /*return; 100 | auto rh = 1024; 101 | char h512[rh]; 102 | in.seekg(offset, std::ifstream::beg); 103 | in.read(h512, rh); 104 | 105 | for(auto x1 = 0; x1 < rh; x1++) 106 | { 107 | h512[x1] = h512[x1] ^ header_xor[x1 % 2]; 108 | } 109 | 110 | auto vp = std::vector(h512, h512+rh); 111 | PrintHex(vp.begin(), vp.end());*/ 112 | } 113 | } -------------------------------------------------------------------------------- /test/firmware/BF-5R_V2.1.0.sgl.sha256: -------------------------------------------------------------------------------- 1 | 60f7afc08effeac6a008fc272014ad5ba0bf882993f94a094ab58d5857e84062 -------------------------------------------------------------------------------- /test/firmware/BF-5R_V2.1.6.sgl.sha256: -------------------------------------------------------------------------------- 1 | c31c536e5c3e43f6f3f27fd0eb1731bf5003d112d6ee64d77e5e3bd8416f6561 -------------------------------------------------------------------------------- /test/firmware/CS800D_Host_MS.30.14_Use_Flashburn3.0_Upgrade.bin.sha256: -------------------------------------------------------------------------------- 1 | e23bcc631c8e62c6f7a7ab7af6342f0c194e4195dcae0b26e662e1993dbd2a00 -------------------------------------------------------------------------------- /test/firmware/CS800D_RCDB_Upgradde.bin.sha256: -------------------------------------------------------------------------------- 1 | 671f7a22e300eebee5936062923bf9f10c3df65a4f52003f2ff2376ba9ccf23f -------------------------------------------------------------------------------- /test/firmware/D013.034.bin.sha256: -------------------------------------------------------------------------------- 1 | c375de54f172346d3f9aecc73cbfa024e753b482e484765b1a890182cfac157e -------------------------------------------------------------------------------- /test/firmware/GD-77S_V1.2.0.sgl.sha256: -------------------------------------------------------------------------------- 1 | 9265558d410821f441391bfa9cb67ad2f919c7856055c1d59be0c12e3e8320b9 -------------------------------------------------------------------------------- /test/firmware/GD-77S_V1.3.0.sgl.sha256: -------------------------------------------------------------------------------- 1 | 8e1a0b355a4aae2f6d0eee13114dd9674e372e90359fd52d2cb3dd53983cf9af -------------------------------------------------------------------------------- /test/firmware/GD-77_V3.2.1.sgl.sha256: -------------------------------------------------------------------------------- 1 | 5f9d38b9cc5723762da11cc4e00a63190c2487ed2f822678abd5fde6eaf0ff9e -------------------------------------------------------------------------------- /test/firmware/GD-77_V3.2.2.sgl.sha256: -------------------------------------------------------------------------------- 1 | 5ba2b6e09162e5d7f5b3937b378e38fd424180043c1a9daeb8f6b35939ece94a -------------------------------------------------------------------------------- /test/firmware/GD-77_V4.2.6.sgl.sha256: -------------------------------------------------------------------------------- 1 | d50a86c537af993e5dd355bbbbd36d7a575c1d9b4b6dbefb973ef9b714786452 -------------------------------------------------------------------------------- /test/firmware/GD-77_V4.2.8.sgl.sha256: -------------------------------------------------------------------------------- 1 | db5a87ea797512597056684b5027300d426265cbe4115158287a941b88d60309 -------------------------------------------------------------------------------- /test/firmware/MD280.002.018.bin.sha256: -------------------------------------------------------------------------------- 1 | 705facf8a0877a745128f223ae17b4f5ab623694824664ea69942cba9b09690b -------------------------------------------------------------------------------- /test/firmware/RD-5R_V2.0.9.sgl.sha256: -------------------------------------------------------------------------------- 1 | d4e21559511666d84636fe802af11538bf112abff0d85e9c32c5837983c7e68a -------------------------------------------------------------------------------- /test/firmware/RT3S_CSV_GPS__P16.06.bin.sha256: -------------------------------------------------------------------------------- 1 | 4a9c930b2b0d21b8705fa85be2eabd8f32447f544b4d99bd7874fe5093439868 -------------------------------------------------------------------------------- /test/firmware/RT3S_CSV__V16.06.bin.sha256: -------------------------------------------------------------------------------- 1 | a47e88fa7ac451078fe12b1fa65218cea7f9b16b3c14d82e206d7de0d5ce8775 -------------------------------------------------------------------------------- /test/firmware/RT3S_GPS_REC__S16.06.bin.sha256: -------------------------------------------------------------------------------- 1 | c2c52a878a973729d31b15de9d13c6f0da332ac4deb263b9a0fae3ca2ae4a63c -------------------------------------------------------------------------------- /test/firmware/RT3S_REC__D16.06.bin.sha256: -------------------------------------------------------------------------------- 1 | dcb6deb0fe4354bf0add04c6961010c66aed5b5bcea5a3cb9c301793f173a760 -------------------------------------------------------------------------------- /test/firmware/TEST_CS800_4000__Mobile_M100000_Host_S3.02.07_Auth_Test_Ver_1_.bin.sha256: -------------------------------------------------------------------------------- 1 | caab58d107e76fbc2c1a203f062ea1accbb6f46d400a895d85eab2c978492533 -------------------------------------------------------------------------------- /test/firmware/TYT2017_UVCSV_GPS_P3.35.bin.sha256: -------------------------------------------------------------------------------- 1 | 513ba43c2ba41bec01f6ac8ce6f5df19126e289e1f3e6c685caeb682a8db594b -------------------------------------------------------------------------------- /test/firmware/TYT2017_UVCSV_V3.35.bin.sha256: -------------------------------------------------------------------------------- 1 | ed8fc2a81742fdfe806ac1d39b19fe30eb3accb9847b5e0dd910fe141e3efed8 -------------------------------------------------------------------------------- /test/firmware/TYT2017_UVGPS_REC_S3.31.bin.sha256: -------------------------------------------------------------------------------- 1 | 877b05407d1b399302bce8ab623254be0f84feb9bf08620d2649bb58edd5fecf -------------------------------------------------------------------------------- /test/firmware/TYT2017_UVGPS_REC_S3.38.bin.sha256: -------------------------------------------------------------------------------- 1 | 8a216f6261c491e2b848d558e8ce22022e8fbf4212785444a27b83321423871f -------------------------------------------------------------------------------- /test/firmware/TYT2017_UVREC_D3.31.bin.sha256: -------------------------------------------------------------------------------- 1 | fa233af7affaf5f9fd1d08961d10f0a556eecbcb0c911abc719ac558b42c828f -------------------------------------------------------------------------------- /test/firmware/TYT2017_UVREC_D3.36.bin.sha256: -------------------------------------------------------------------------------- 1 | feebf0f0a7220e870b918568f5827f00db42bc0ba35fe7c6e75e9d29c79ae9d8 -------------------------------------------------------------------------------- /test/firmware/TYT2017_UV_CSV_GPS__P3.33.bin.sha256: -------------------------------------------------------------------------------- 1 | f3c1e7b0b005f6391c082b5a0d3dcd5faf08c50896a1c6ba4994be796dd22e33 -------------------------------------------------------------------------------- /test/firmware/TYT2017_UV_CSV_GPS__P3.35.bin.sha256: -------------------------------------------------------------------------------- 1 | 513ba43c2ba41bec01f6ac8ce6f5df19126e289e1f3e6c685caeb682a8db594b -------------------------------------------------------------------------------- /test/firmware/TYT2017_UV_CSV_GPS__P3.38.bin.sha256: -------------------------------------------------------------------------------- 1 | c4d21a8bbb6768c6a8cd20b747a51805cc59c2a4d9f7796b6a623ab70876a993 -------------------------------------------------------------------------------- /test/firmware/TYT2017_UV_CSV__V3.33.bin.sha256: -------------------------------------------------------------------------------- 1 | 8ad30ef5685b9541db50c9348492ed82aef486adf48fb51c661240bfe34121d7 -------------------------------------------------------------------------------- /test/firmware/TYT2017_UV_CSV__V3.35.bin.sha256: -------------------------------------------------------------------------------- 1 | ed8fc2a81742fdfe806ac1d39b19fe30eb3accb9847b5e0dd910fe141e3efed8 -------------------------------------------------------------------------------- /test/firmware/TYT2017_UV_CSV__V3.36.bin.sha256: -------------------------------------------------------------------------------- 1 | 7d55707ef8fe0f59726d3bb174e36f3e8c0e88c38c5caec675d268533c868bd7 -------------------------------------------------------------------------------- /test/firmware/TYT2017_UV_GPS_REC__S3.31.bin.sha256: -------------------------------------------------------------------------------- 1 | 877b05407d1b399302bce8ab623254be0f84feb9bf08620d2649bb58edd5fecf -------------------------------------------------------------------------------- /test/firmware/TYT2017_UV_GPS_REC__S3.38.bin.sha256: -------------------------------------------------------------------------------- 1 | 8a216f6261c491e2b848d558e8ce22022e8fbf4212785444a27b83321423871f -------------------------------------------------------------------------------- /test/firmware/TYT2017_UV_REC__D3.31.bin.sha256: -------------------------------------------------------------------------------- 1 | fa233af7affaf5f9fd1d08961d10f0a556eecbcb0c911abc719ac558b42c828f -------------------------------------------------------------------------------- /test/firmware/TYT2017_UV_REC__D3.36.bin.sha256: -------------------------------------------------------------------------------- 1 | feebf0f0a7220e870b918568f5827f00db42bc0ba35fe7c6e75e9d29c79ae9d8 -------------------------------------------------------------------------------- /test/firmware/TYT_GPS_MD390_MD380_S003.012.bin.sha256: -------------------------------------------------------------------------------- 1 | 823439219e82f142ddb707003b6d6affa3993e6dd5bee99771a1f7f883de2046 -------------------------------------------------------------------------------- /test/firmware/TYT_TFT_MD380_D3.20.bin.sha256: -------------------------------------------------------------------------------- 1 | 38787da956234f9ec811cae08568f7bdb5f21b4070681ae689a0ba82c845f973 -------------------------------------------------------------------------------- /test/firmware/TYT_TFT_MD446_D3.20.bin.sha256: -------------------------------------------------------------------------------- 1 | 9892b2e95da0eee0ec87604007f157f6f9b249a9fb11ba0fc3798e78956e2587 -------------------------------------------------------------------------------- /test/firmware/TYT_Vocoder_MD380_D13.14.bin.sha256: -------------------------------------------------------------------------------- 1 | db479b26c0c6aed81e9a3d2f7b2bf7476dfccc401c7bdd8976b321b31b967f42 -------------------------------------------------------------------------------- /test/firmware/TYT_Vocoder_MD380_D13.20.bin.sha256: -------------------------------------------------------------------------------- 1 | b92052ea958b15687992cbf796f00a3dbcb33113426def550c32c7dd4e20cd95 -------------------------------------------------------------------------------- /test/firmware/TYT_Vocoder_MD380_D14.07.bin.sha256: -------------------------------------------------------------------------------- 1 | e0a65ef4ba358abd66ce7041b571df5a1b3047b9f113d3cad6f8ab99b6e972be -------------------------------------------------------------------------------- /test/firmware/TYT_Vocoder_MD390_S13.12.bin.sha256: -------------------------------------------------------------------------------- 1 | c8a98648d01c34ec8dca208eb0fff903ac0c9127a46ed482b7ca8e5755396d3d -------------------------------------------------------------------------------- /test/firmware/TYT_Vocoder_MD390_S13.20.bin.sha256: -------------------------------------------------------------------------------- 1 | 5ce02f5f68fcb4d977d3b209d0d3911743ed300ebfb89d583a4a83c10208ed26 -------------------------------------------------------------------------------- /test/firmware/TYT_Vocoder_MD390_S15.02.bin.sha256: -------------------------------------------------------------------------------- 1 | 31d77aab24566699530db33dca881fc827d7de935a5fbb15db249f7060063fce -------------------------------------------------------------------------------- /test/firmware/TYT_Vocoder_MD390_S15.04.bin.sha256: -------------------------------------------------------------------------------- 1 | 1b2bc3c6923a4cadedadd5d76dfc4bbd2638a6b802993187881fb1627160a784 -------------------------------------------------------------------------------- /test/firmware/TYT_Vocoder_MD446_D13.20.bin.sha256: -------------------------------------------------------------------------------- 1 | 6b83a74b72df4b13f74f5ac7ef2472593809055fc252c0aabe4c9eeeef1f115c -------------------------------------------------------------------------------- /test/firmware/dm1701_2.03.bin.sha256: -------------------------------------------------------------------------------- 1 | 35a045d7a71164183b164d6ecfdd9e349c757b3539be67a16fecd68ca6f65948 -------------------------------------------------------------------------------- /test/firmware/md2017_csv_gps_p4.17.bin.sha256: -------------------------------------------------------------------------------- 1 | 336e10ca4bea020e6369f33d5519a76eb0a3c0d5cb973701ef92e820fd42396d -------------------------------------------------------------------------------- /test/firmware/md2017_csv_v4.15.bin.sha256: -------------------------------------------------------------------------------- 1 | 16c8ce5cabdac8c0f4642aa57411fd270e42558550ad91eae453b06a27747e67 -------------------------------------------------------------------------------- /test/firmware/md2017_rec_d4.15.bin.sha256: -------------------------------------------------------------------------------- 1 | cd2e310562b8ad9bb78e9b87ea9499eafef4ab4e3539f81b49e308749e8d65ca -------------------------------------------------------------------------------- /test/firmware/md2017_rec_gps_s4.17.bin.sha256: -------------------------------------------------------------------------------- 1 | b1c225f935474802df90da9b357d06965017b819177691936c5345a78a431dd4 -------------------------------------------------------------------------------- /test/firmware/md9600_csv_gps_p6.13.bin.sha256: -------------------------------------------------------------------------------- 1 | 75fd874fa798931d2b4d3b77abe3e363f92ae0a195795c8162c1d25e4b84f66f -------------------------------------------------------------------------------- /test/firmware/md9600_csv_v6.09.bin.sha256: -------------------------------------------------------------------------------- 1 | 79a561eda2f5843334ea5974f5de511b6e172a1643f9163806d54a94404f0f09 -------------------------------------------------------------------------------- /test/firmware/md9600_rec_d6.09.bin.sha256: -------------------------------------------------------------------------------- 1 | 7b1b1b33e661766a5b0c0b3ddab9c31c96e3855b09f4e280b07f4990b563b68f -------------------------------------------------------------------------------- /test/firmware/md9600_rec_gps_s6.13.bin.sha256: -------------------------------------------------------------------------------- 1 | 4871213d28ca60e38994c48bce293b8fe4337471d0bcce0f2b7f73eb659b9de5 -------------------------------------------------------------------------------- /test/firmware/mk_links.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import hashlib 4 | import os 5 | import glob 6 | 7 | BUF_SIZE = 65536 8 | 9 | for file_in in glob.glob("*.bin"): 10 | sha = hashlib.sha256() 11 | 12 | with open(file_in, 'rb') as f: 13 | while True: 14 | data = f.read(BUF_SIZE) 15 | if not data: 16 | break 17 | sha.update(data) 18 | hashStr = sha.hexdigest() 19 | print("{0}: {1}".format(file_in, hashStr)) 20 | with open("{0}.sha256".format(file_in.replace("(", "_").replace(")", "_").replace("-", "_")), 'w') as fsha: 21 | fsha.write(hashStr) 22 | out_link = "SHA256/{0}".format(hashStr) 23 | if not os.path.exists(out_link): 24 | os.symlink("../{0}".format(file_in), out_link) 25 | -------------------------------------------------------------------------------- /test/firmware/uv380_csv_v18.11.bin.sha256: -------------------------------------------------------------------------------- 1 | fb1897b7123dc6a039a5266972c5bb6f563f574d3769bd1cbdc7bb02b5039cc7 -------------------------------------------------------------------------------- /test/firmware/uv380_rec_d18.11.bin.sha256: -------------------------------------------------------------------------------- 1 | 78650258f65fef33d78fad65678bedd74e44b75e924466829c9a360ce8915f39 -------------------------------------------------------------------------------- /test/firmware/uv390_csv_gps_p18.11.bin.sha256: -------------------------------------------------------------------------------- 1 | e31ecd122f77ccd34e563193b004e8621ff5422676521503521f64f1045f73a9 -------------------------------------------------------------------------------- /test/firmware/uv390_rec_gps_s18.11.bin.sha256: -------------------------------------------------------------------------------- 1 | fbb307fd14577e48e1fb6edb3395d4d684baf12dd9fed66280ad76d12e0e04c2 -------------------------------------------------------------------------------- /test/test_bin2sgl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | gcc -Wall -O2 -static -s -o bin2sgl bin2sgl.c 4 | 5 | echo -e "Getting some random data.." 6 | head -c 1024 /dev/urandom > random.bin 7 | 8 | echo -e "Making radio_tool binary" 9 | ../build/radio_tool --wrap -s 0x00:random.bin -r GD77 -o random_0.bin 10 | 11 | echo -e "Making bin2sgl binary" 12 | ./bin2sgl -f random.bin -m GD-77 13 | 14 | echo ============== 15 | sha256sum random.sgl 16 | sha256sum random_0.bin 17 | 18 | echo ============== 19 | xxd -l 128 random.sgl 20 | echo ============== 21 | xxd -l 128 random_0.bin 22 | 23 | echo ============== 24 | xxd -s -128 random.sgl 25 | echo ============== 26 | xxd -s -128 random_0.bin 27 | 28 | du -b random.sgl 29 | du -b random_0.bin 30 | 31 | diff -y <(xxd random.sgl) <(xxd random_0.bin) > random_diff -------------------------------------------------------------------------------- /test/test_firmware_download.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include "dummy_device.hpp" 5 | 6 | int main(int argc, char** argv) { 7 | if (argc != 3) { 8 | std::cerr << "Usage: " << argv[0] << " " << std::endl; 9 | exit(1); 10 | } 11 | const char* file = argv[1]; 12 | const char* radio = argv[2]; 13 | 14 | std::cout << "Testing: " << file << " (" << radio << ")" << std::endl; 15 | 16 | 17 | exit(0); 18 | } -------------------------------------------------------------------------------- /test/test_fw.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | auto testFirmwareInfo(std::string original_file, std::string new_file) -> void; 8 | 9 | int main(int argc, char** argv) 10 | { 11 | if (argc != 3) 12 | { 13 | std::cerr << "Usage: " << argv[0] << " " << std::endl; 14 | exit(1); 15 | } 16 | const char* file = argv[1]; 17 | const char* radio = argv[2]; 18 | 19 | std::cout << "Testing: " << file << " (" << radio << ")" << std::endl; 20 | 21 | try { 22 | auto h = radio_tool::fw::FirmwareFactory::GetFirmwareFileHandler(file); 23 | h->Read(file); 24 | 25 | std::cout << h->ToString(); 26 | 27 | if (h->GetRadioModel() != std::string(radio)) 28 | { 29 | std::cerr << "Firmware model incorrect" << std::endl; 30 | exit(1); 31 | } 32 | 33 | //Unwrap and rebuild firmware 34 | auto write_test_name = "write_test_"; 35 | auto write_test = "write_test_wrapped.bin"; 36 | std::vector> segs; 37 | for (const auto& seg : h->GetDataSegments()) 38 | { 39 | std::stringstream ss_name; 40 | ss_name << write_test_name << "_0x" << std::setw(8) << std::setfill('0') << std::hex << seg.address; 41 | 42 | std::ofstream fw_out; 43 | fw_out.open(ss_name.str(), std::ios_base::out | std::ios_base::binary); 44 | if (fw_out.is_open()) 45 | { 46 | fw_out.write((const char*)seg.data.data(), seg.data.size()); 47 | fw_out.close(); 48 | segs.push_back({ seg.address, seg.size }); 49 | } 50 | else 51 | { 52 | std::cerr << "Failed to open output file: " << ss_name.str() << std::endl; 53 | exit(1); 54 | } 55 | } 56 | 57 | //Create a new firmware from unwrapped segments 58 | auto fw_new = radio_tool::fw::FirmwareFactory::GetFirmwareModelHandler(h->GetRadioModel()); 59 | for (const auto& seg : segs) 60 | { 61 | std::stringstream ss_name; 62 | ss_name << write_test_name << "_0x" << std::setw(8) << std::setfill('0') << std::hex << seg.first; 63 | 64 | std::ifstream fw_in; 65 | fw_in.open(ss_name.str(), fw_in.binary); 66 | if (fw_in.is_open()) 67 | { 68 | fw_in.seekg(0, fw_in.end); 69 | auto size = fw_in.tellg(); 70 | fw_in.seekg(0, fw_in.beg); 71 | 72 | std::vector fw_data; 73 | fw_data.resize(size); 74 | fw_in.read((char*)fw_data.data(), size); 75 | fw_in.close(); 76 | 77 | fw_new->AppendSegment(seg.first, fw_data); 78 | } 79 | else 80 | { 81 | std::cerr << "Failed to open input file: " << ss_name.str() << std::endl; 82 | exit(1); 83 | } 84 | } 85 | fw_new->SetRadioModel(h->GetRadioModel()); 86 | fw_new->Write(write_test); 87 | 88 | testFirmwareInfo(file, write_test); 89 | } 90 | catch (std::exception e) { 91 | std::cerr << "Error: " << e.what() << std::endl; 92 | exit(1); 93 | } 94 | std::cout << "Passed!" << std::endl; 95 | exit(0); 96 | } 97 | 98 | auto testFirmwareInfo(std::string original_file, std::string new_file) -> void { 99 | auto fw_old = radio_tool::fw::FirmwareFactory::GetFirmwareFileHandler(original_file); 100 | auto fw_new = radio_tool::fw::FirmwareFactory::GetFirmwareFileHandler(new_file); 101 | 102 | if (fw_old == nullptr || fw_new == nullptr) { 103 | std::cerr << "Could not find firmware handler!" << std::endl; 104 | exit(1); 105 | } 106 | 107 | fw_old->Read(original_file); 108 | fw_new->Read(new_file); 109 | 110 | if (fw_old->IsCompatible(fw_new.get())) { 111 | std::cerr << "Firware headers do not match" << std::endl; 112 | std::cerr << "== Old ==" << fw_old->ToString() << std::endl; 113 | std::cerr << "== New ==" << fw_new->ToString() << std::endl; 114 | exit(1); 115 | } 116 | } -------------------------------------------------------------------------------- /test/test_util.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace radio_tool; 6 | int main(int argc, char **argv) 7 | { 8 | std::vector t1 = {'a', 'b', 'c', 'd', 'e'}; 9 | std::vector t2 = {'a', 'b', 'c', 'd', 'e', 'f'}; 10 | std::vector t3 = {'a', 'b', 'c', 'd', 'e', 'f', 'g'}; 11 | 12 | auto t1_i = t1.begin(); 13 | auto t2_i = t2.begin(); 14 | auto t3_i = t3.begin(); 15 | 16 | assert(Fletcher16(t1_i, t1.size()) == 0xC8F0); 17 | assert(Fletcher16(t2_i, t2.size()) == 0x2057); 18 | assert(Fletcher16(t3_i, t3.size()) == 0x0627); 19 | } -------------------------------------------------------------------------------- /test/test_xor_tool.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace radio_tool::fw; 10 | using namespace radio_tool::flash; 11 | 12 | int main(int argc, char **argv) 13 | { 14 | if (argc != 2) 15 | { 16 | std::cerr << "Usage: " << argv[0] << " " << std::endl; 17 | exit(1); 18 | } 19 | const char *file = argv[1]; 20 | 21 | std::cout << "Testing: " << file << std::endl; 22 | 23 | auto h = FirmwareFactory::GetFirmwareHandler(file); 24 | h->Read(file); 25 | 26 | std::cout << h->ToString(); 27 | 28 | //test key 29 | auto key = XORTool::MakeXOR(h->GetData()); 30 | for (const auto ®ion : h->GetDataSegments()) 31 | { 32 | //Only test segments which are mapped to mcu flash section 33 | if (FlashUtil::GetSector(STM32F40X, region.address)) 34 | { 35 | if (radio_tool::fw::XORTool::Verify(region.address, region.data, key)) 36 | { 37 | std::cout 38 | << "Region @ 0x" << std::setfill('0') << std::setw(8) << std::hex << region.address 39 | << " appears to be a valid vector_table" << std::endl; 40 | } 41 | else 42 | { 43 | throw std::runtime_error("XOR appears to be wrong"); 44 | } 45 | } 46 | } 47 | exit(0); 48 | } --------------------------------------------------------------------------------