chore(cpn): refactor firmware flashing to use edgetx rs_dfu (#6521)
Co-authored-by: raphaelcoeffic <1050031+raphaelcoeffic@users.noreply.github.com>
@@ -69,12 +69,6 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: python3 -m pip install --upgrade pip Pillow lz4 clang jinja2
|
||||
|
||||
- name: Install libusb
|
||||
run: brew install libusb
|
||||
|
||||
- name: Install dfu-util
|
||||
run: brew install dfu-util
|
||||
|
||||
- name: Install SDL2
|
||||
run: brew install SDL2
|
||||
|
||||
|
||||
@@ -71,46 +71,6 @@ jobs:
|
||||
echo $PATH
|
||||
$Python3_ROOT_DIR/python3.exe -m pip install clang jinja2 lz4 pillow
|
||||
|
||||
- name: Setup dfu-util and libusb
|
||||
run: |
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Setting up dfu-util and libusb..."
|
||||
|
||||
# Create target directory
|
||||
mkdir -p dfu-util-0.11
|
||||
|
||||
# Download and extract dfu-util
|
||||
echo "Downloading dfu-util binaries..."
|
||||
curl -LO https://dfu-util.sourceforge.net/releases/dfu-util-0.11-binaries.tar.xz
|
||||
tar -xf dfu-util-0.11-binaries.tar.xz
|
||||
cp dfu-util-0.11-binaries/win64/dfu-util.exe dfu-util-0.11/
|
||||
|
||||
# Install 7zip if not available
|
||||
if ! command -v 7z &> /dev/null; then
|
||||
echo "Installing 7zip..."
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y p7zip-full
|
||||
fi
|
||||
|
||||
# Download and extract libusb
|
||||
echo "Downloading libusb..."
|
||||
curl -LO https://github.com/libusb/libusb/releases/download/v1.0.29/libusb-1.0.29.7z
|
||||
7z x -olibusb-1.0.29 libusb-1.0.29.7z > /dev/null
|
||||
cp libusb-1.0.29/VS2022/MS64/dll/* dfu-util-0.11/
|
||||
|
||||
# Clean up temporary files
|
||||
rm -f dfu-util-0.11-binaries.tar.xz libusb-1.0.29.7z
|
||||
rm -rf dfu-util-0.11-binaries libusb-1.0.29
|
||||
|
||||
echo "Setup complete. Contents of dfu-util-0.11:"
|
||||
ls -la dfu-util-0.11/
|
||||
|
||||
echo "LIBUSB1_ROOT_DIR=$(pwd)/dfu-util-0.11" >> $GITHUB_ENV
|
||||
echo "DFU_UTIL_ROOT_DIR=$(pwd)/dfu-util-0.11" >> $GITHUB_ENV
|
||||
|
||||
|
||||
- name: Setup MSVC
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
maxLibQt
|
||||
GIT_REPOSITORY https://github.com/edgetx/maxLibQt
|
||||
GIT_TAG 98f5482fb8b836f48a6a5ee199911882fa420f2b
|
||||
GIT_TAG 7e433da60d3f2e975d46afc91804a88029cd1b78
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(maxLibQt)
|
||||
|
||||
@@ -17,4 +17,4 @@ include_directories(
|
||||
)
|
||||
|
||||
# suppress compiler warnings for this add-in only
|
||||
target_compile_options(miniz PRIVATE -Wno-unused-function)
|
||||
target_compile_options(miniz PRIVATE -Wno-unused-function -Wno-newline-eof)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# Fetch rs_dfu
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
# Determine platform and architecture
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(RS_DFU_PLATFORM "unknown-linux-gnu")
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
set(RS_DFU_PLATFORM "apple-darwin")
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
set(RS_DFU_PLATFORM "pc-windows-msvc")
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported platform: ${CMAKE_SYSTEM_NAME}")
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64")
|
||||
set(RS_DFU_ARCH "x86_64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64")
|
||||
set(RS_DFU_ARCH "aarch64")
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
|
||||
set(RS_DFU_BASE_URL "https://github.com/EdgeTX/rs-dfu/releases/latest/download")
|
||||
set(RS_DFU_FILENAME "rs_dfu-${RS_DFU_ARCH}-${RS_DFU_PLATFORM}")
|
||||
set(RS_DFU_URL "${RS_DFU_BASE_URL}/${RS_DFU_FILENAME}.tar.gz")
|
||||
|
||||
FetchContent_Declare(
|
||||
RsDfu
|
||||
URL ${RS_DFU_URL}
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP true
|
||||
FIND_PACKAGE_ARGS
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(RsDfu)
|
||||
|
||||
set(rs_dfu_DIR "${rsdfu_SOURCE_DIR}/cmake")
|
||||
|
||||
message("Fetched rsdfu source code from Github: ${rsdfu_SOURCE_DIR}")
|
||||
@@ -1,25 +0,0 @@
|
||||
# - try to find program dfu-util
|
||||
|
||||
set(DFU_UTIL_ROOT_DIR
|
||||
"${DFU_UTIL_ROOT_DIR}"
|
||||
CACHE
|
||||
PATH
|
||||
"Root directory to search for dfu-util")
|
||||
|
||||
find_program(DFU_UTIL_PROGRAM
|
||||
NAMES
|
||||
dfu-util
|
||||
HINTS
|
||||
"${DFU_UTIL_ROOT_DIR}")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(DFU_UTIL
|
||||
DEFAULT_MSG
|
||||
DFU_UTIL_PROGRAM)
|
||||
|
||||
if(DFU_UTIL_FOUND)
|
||||
set(DFU_UTIL_PATH "${DFU_UTIL_PROGRAM}")
|
||||
mark_as_advanced(DFU_UTIL_ROOT_DIR)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(DFU_UTIL_PROGRAM)
|
||||
@@ -1,24 +0,0 @@
|
||||
# - try to find libusb-1 library
|
||||
|
||||
set(LIBUSB1_ROOT_DIR
|
||||
"${LIBUSB1_ROOT_DIR}"
|
||||
CACHE
|
||||
PATH
|
||||
"Root directory to search for libusb-1")
|
||||
|
||||
find_library(LIBUSB1_LIBRARY
|
||||
NAMES
|
||||
libusb-1.0
|
||||
libusb-1.0.so
|
||||
libusb-1.0.so.0
|
||||
libusb-1.0.dll
|
||||
libusb-1.0.dylib
|
||||
HINTS
|
||||
"${LIBUSB1_ROOT_DIR}")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LIBUSB1
|
||||
DEFAULT_MSG
|
||||
LIBUSB1_LIBRARY)
|
||||
|
||||
mark_as_advanced(LIBUSB1_LIBRARY)
|
||||
@@ -13,27 +13,15 @@ else()
|
||||
endif()
|
||||
|
||||
if(Qt6Core_FOUND AND NOT DISABLE_COMPANION)
|
||||
# environment variable set in github workflows and build-edgetx Dockerfile
|
||||
if(DEFINED ENV{LIBUSB1_ROOT_DIR})
|
||||
set(LIBUSB1_ROOT_DIR "$ENV{LIBUSB1_ROOT_DIR}")
|
||||
endif()
|
||||
|
||||
find_package(Libusb1)
|
||||
|
||||
if(LIBUSB1_FOUND)
|
||||
if(DEFINED ENV{DFU_UTIL_ROOT_DIR})
|
||||
set(DFU_UTIL_ROOT_DIR "$ENV{DFU_UTIL_ROOT_DIR}")
|
||||
endif()
|
||||
|
||||
find_package(Dfuutil)
|
||||
endif()
|
||||
|
||||
# environment variable set in github workflows and build-edgetx Dockerfile
|
||||
if(DEFINED ENV{OPENSSL_ROOT_DIR})
|
||||
set(OPENSSL_ROOT_DIR "$ENV{OPENSSL_ROOT_DIR}")
|
||||
endif()
|
||||
|
||||
find_package(OpenSSL)
|
||||
|
||||
include(FetchRsDfu)
|
||||
find_package(rs_dfu REQUIRED)
|
||||
endif()
|
||||
|
||||
# Windows-specific includes and libs shared by sub-projects
|
||||
|
||||
@@ -81,6 +81,8 @@ include_directories(
|
||||
${SIMU_SRC_DIRECTORY}
|
||||
${COMPANION_SRC_DIRECTORY}/thirdparty/qcustomplot
|
||||
${COMPANION_SRC_DIRECTORY}/storage
|
||||
${COMPANION_SRC_DIRECTORY}/flash
|
||||
${COMPANION_SRC_DIRECTORY}/progress
|
||||
)
|
||||
|
||||
############# Do macro replacements on input files #############
|
||||
@@ -175,6 +177,7 @@ add_library(common ${common_SRCS} ${common_RCC})
|
||||
target_link_libraries(common
|
||||
datamodels
|
||||
firmwares
|
||||
progress
|
||||
shared
|
||||
simulation
|
||||
storage
|
||||
@@ -196,8 +199,10 @@ include(FetchMaxLibQt)
|
||||
|
||||
add_subdirectory(datamodels)
|
||||
add_subdirectory(firmwares)
|
||||
add_subdirectory(flash)
|
||||
add_subdirectory(generaledit)
|
||||
add_subdirectory(modeledit)
|
||||
add_subdirectory(progress)
|
||||
add_subdirectory(shared)
|
||||
add_subdirectory(simulation)
|
||||
add_subdirectory(storage)
|
||||
@@ -211,10 +216,7 @@ include_directories(${maxLibQt_SOURCE_DIR}/widgets)
|
||||
|
||||
set(companion_NAMES
|
||||
apppreferencesdialog
|
||||
burnconfigdialog
|
||||
comparedialog
|
||||
customizesplashdialog
|
||||
flashfirmwaredialog
|
||||
helpers_html
|
||||
labels
|
||||
logsdialog
|
||||
@@ -224,15 +226,7 @@ set(companion_NAMES
|
||||
modelslist
|
||||
multimodelprinter
|
||||
printdialog
|
||||
process_copy
|
||||
process_flash
|
||||
process_sync
|
||||
profilechooser
|
||||
progressdialog
|
||||
progresswidget
|
||||
radiointerface
|
||||
radionotfound
|
||||
splashlibrarydialog
|
||||
styleeditdialog
|
||||
dialogs/filesyncdialog
|
||||
)
|
||||
@@ -254,11 +248,6 @@ set(companion_SRCS
|
||||
companion.cpp
|
||||
)
|
||||
|
||||
set(companion_HDRS
|
||||
${companion_HDRS}
|
||||
splashlabel.h
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set(icon_RC images/winicons/icon.rc)
|
||||
endif()
|
||||
@@ -277,6 +266,7 @@ target_link_libraries(${COMPANION_NAME} PRIVATE
|
||||
qcustomplot
|
||||
miniz
|
||||
updates
|
||||
flash
|
||||
wizard
|
||||
)
|
||||
|
||||
@@ -363,15 +353,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps"
|
||||
RENAME "${COMPANION_NAME}.svg")
|
||||
|
||||
# udev rules
|
||||
install(FILES "${COMPANION_TARGETS_DIR}/45-companion-taranis.rules"
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/udev/rules.d"
|
||||
RENAME "45-${COMPANION_NAME}-taranis.rules")
|
||||
|
||||
install(FILES "${COMPANION_TARGETS_DIR}/45-usbasp.rules"
|
||||
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/udev/rules.d"
|
||||
RENAME "45-${COMPANION_NAME}-usbasp.rules")
|
||||
|
||||
if(OPENSSL_FOUND)
|
||||
get_filename_component(OPENSSL_SSL_LIBRARY_DIR ${OPENSSL_SSL_LIBRARY} DIRECTORY)
|
||||
install(DIRECTORY ${OPENSSL_SSL_LIBRARY_DIR}/
|
||||
@@ -381,18 +362,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
PATTERN "libssl.so.*")
|
||||
endif()
|
||||
|
||||
if(LIBUSB1_FOUND)
|
||||
get_filename_component(LIBUSB1_LIBRARY_DIR ${LIBUSB1_LIBRARY} DIRECTORY)
|
||||
install(DIRECTORY ${LIBUSB1_LIBRARY_DIR}/
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
|
||||
FILES_MATCHING PATTERN "libusb-1.0.so.*")
|
||||
if(DFU_UTIL_FOUND)
|
||||
# dfuutil is an app
|
||||
install(FILES "${DFU_UTIL_PATH}"
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(OperatingSystem "Linux")
|
||||
# Shortcut target
|
||||
add_custom_target(companion DEPENDS ${COMPANION_NAME})
|
||||
@@ -415,30 +384,6 @@ elseif(WIN32)
|
||||
install(FILES ${LICENSE_FILE}
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
# supporting utilities
|
||||
if(LIBUSB1_FOUND)
|
||||
cmake_path(GET LIBUSB1_LIBRARY
|
||||
PARENT_PATH
|
||||
LIBUSB1_LIBRARY_DIR)
|
||||
|
||||
if(MINGW)
|
||||
# finds dll.a directory but we need dlls but should check extension just to be sure and future proof
|
||||
set(LIBUSB1_LIBRARY_DIR "${LIBUSB1_LIBRARY_DIR}/../bin")
|
||||
endif()
|
||||
|
||||
set(LIBUSB1_LIBRARY_FILE "${LIBUSB1_LIBRARY_DIR}/libusb-1.0.dll")
|
||||
|
||||
if(EXISTS "${LIBUSB1_LIBRARY_FILE}")
|
||||
install(FILES "${LIBUSB1_LIBRARY_FILE}"
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
if(DFU_UTIL_FOUND)
|
||||
install(FILES "${DFU_UTIL_PATH}"
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
endif(LIBUSB1_FOUND)
|
||||
|
||||
if(OPENSSL_FOUND)
|
||||
cmake_path(GET OPENSSL_SSL_LIBRARY
|
||||
PARENT_PATH
|
||||
@@ -511,14 +456,6 @@ elseif(APPLE)
|
||||
install(FILES ${MAC_ICON_FILE}
|
||||
DESTINATION ${companion_res_dir}
|
||||
COMPONENT Runtime)
|
||||
|
||||
if(DFU_UTIL_FOUND)
|
||||
# Copy dfu-util, resolve symlink first
|
||||
file(REAL_PATH "${DFU_UTIL_PATH}" DFU_UTIL_ABSOLUTE_PATH)
|
||||
install(PROGRAMS ${DFU_UTIL_ABSOLUTE_PATH}
|
||||
DESTINATION ${companion_res_dir}
|
||||
COMPONENT Runtime)
|
||||
endif(DFU_UTIL_FOUND)
|
||||
endif()
|
||||
|
||||
############# Packaging ####################
|
||||
@@ -605,7 +542,6 @@ elseif(APPLE)
|
||||
CONTENT "
|
||||
qt_deploy_runtime_dependencies(
|
||||
EXECUTABLE ${companion_app_dir}
|
||||
ADDITIONAL_EXECUTABLES ${companion_res_dir}/dfu-util
|
||||
NO_TRANSLATIONS
|
||||
NO_COMPILER_RUNTIME
|
||||
GENERATE_QT_CONF
|
||||
|
||||
@@ -56,6 +56,10 @@ AppPreferencesDialog::AppPreferencesDialog(QWidget * parent, UpdateFactories * f
|
||||
connect(ui->boardCB, SIGNAL(currentIndexChanged(int)), this, SLOT(onBaseFirmwareChanged()));
|
||||
connect(ui->opt_appDebugLog, &QCheckBox::toggled, this, &AppPreferencesDialog::toggleAppLogSettings);
|
||||
connect(ui->opt_fwTraceLog, &QCheckBox::toggled, this, &AppPreferencesDialog::toggleAppLogSettings);
|
||||
connect(ui->backupPath, &QLineEdit::editingFinished, this, &AppPreferencesDialog::onBackupPathEditingFinished);
|
||||
connect(ui->backupPathButton, &QPushButton::clicked, this, &AppPreferencesDialog::onBackupPathButtonClicked);
|
||||
connect(ui->profileBackupPath, &QLineEdit::editingFinished, this, &AppPreferencesDialog::onProfileBackupPathEditingFinished);
|
||||
connect(ui->profileBackupPathButton, &QPushButton::clicked, this, &AppPreferencesDialog::onProfileBackupPathButtonClicked);
|
||||
|
||||
#if !defined(USE_SDL)
|
||||
ui->joystickCB->hide();
|
||||
@@ -172,8 +176,8 @@ void AppPreferencesDialog::accept()
|
||||
profile.defaultMode(ui->stickmodeCB->currentData().toInt());
|
||||
profile.burnFirmware(ui->burnFirmware->isChecked());
|
||||
profile.sdPath(ui->sdPath->text());
|
||||
profile.pBackupDir(ui->profilebackupPath->text());
|
||||
profile.penableBackup(ui->pbackupEnable->isChecked());
|
||||
profile.pBackupDir(ui->profileBackupPath->text());
|
||||
profile.penableBackup(ui->profileBackupEnable->isChecked());
|
||||
profile.splashFile(ui->SplashFileName->text());
|
||||
profile.runSDSync(ui->chkPromptSDSync->isChecked());
|
||||
profile.radioSimCaseColor(ui->lblRadioColorSample->palette().button().color());
|
||||
@@ -243,7 +247,7 @@ void AppPreferencesDialog::on_btnRadioColor_clicked()
|
||||
|
||||
void AppPreferencesDialog::initSettings()
|
||||
{
|
||||
const Profile & profile = g.currentProfile();
|
||||
Profile & profile = g.currentProfile();
|
||||
|
||||
ui->burnFirmware->setChecked(profile.burnFirmware());
|
||||
|
||||
@@ -257,19 +261,15 @@ void AppPreferencesDialog::initSettings()
|
||||
ui->libraryPath->setText(g.libDir());
|
||||
ui->ge_lineedit->setText(g.gePath());
|
||||
|
||||
if (!g.backupDir().isEmpty()) {
|
||||
if (QDir(g.backupDir()).exists()) {
|
||||
ui->backupPath->setText(g.backupDir());
|
||||
ui->backupEnable->setEnabled(true);
|
||||
ui->backupEnable->setChecked(g.enableBackup());
|
||||
}
|
||||
else {
|
||||
ui->backupEnable->setDisabled(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ui->backupEnable->setDisabled(true);
|
||||
ui->backupPath->setText(g.backupDir());
|
||||
if (!ui->backupPath->text().isEmpty() && QDir(ui->backupPath->text()).exists()) {
|
||||
ui->backupEnable->setEnabled(true);
|
||||
ui->backupEnable->setChecked(g.enableBackup());
|
||||
} else {
|
||||
ui->backupEnable->setChecked(false);
|
||||
ui->backupEnable->setEnabled(false);
|
||||
}
|
||||
|
||||
ui->splashincludeCB->setCurrentIndex(g.embedSplashes());
|
||||
|
||||
ui->opt_appDebugLog->setChecked(g.appDebugLog());
|
||||
@@ -336,17 +336,22 @@ void AppPreferencesDialog::initSettings()
|
||||
ui->stickmodeCB->setModel(GeneralSettings::stickModeItemModel());
|
||||
ui->stickmodeCB->setCurrentIndex(ui->stickmodeCB->findData(profile.defaultMode()));
|
||||
ui->sdPath->setText(profile.sdPath());
|
||||
if (!profile.pBackupDir().isEmpty()) {
|
||||
if (QDir(profile.pBackupDir()).exists()) {
|
||||
ui->profilebackupPath->setText(profile.pBackupDir());
|
||||
ui->pbackupEnable->setEnabled(true);
|
||||
ui->pbackupEnable->setChecked(profile.penableBackup());
|
||||
|
||||
ui->profileBackupPath->setText(profile.pBackupDir());
|
||||
if (!ui->profileBackupPath->text().isEmpty()) {
|
||||
if (QDir(ui->profileBackupPath->text()).exists()) {
|
||||
ui->profileBackupEnable->setEnabled(true);
|
||||
ui->profileBackupEnable->setChecked(profile.penableBackup());
|
||||
} else {
|
||||
ui->pbackupEnable->setDisabled(true);
|
||||
ui->profileBackupEnable->setChecked(false);
|
||||
ui->profileBackupEnable->setEnabled(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ui->pbackupEnable->setDisabled(true);
|
||||
} else if (!ui->backupPath->text().isEmpty() && QDir(ui->backupPath->text()).exists()) {
|
||||
ui->profileBackupEnable->setEnabled(true);
|
||||
ui->profileBackupEnable->setChecked(profile.penableBackup());
|
||||
} else {
|
||||
ui->profileBackupEnable->setChecked(false);
|
||||
ui->profileBackupEnable->setEnabled(false);
|
||||
}
|
||||
|
||||
if (Boards::isSurface()) {
|
||||
@@ -584,26 +589,33 @@ void AppPreferencesDialog::on_snapshotClipboardCKB_clicked()
|
||||
}
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::on_backupPathButton_clicked()
|
||||
void AppPreferencesDialog::onBackupPathButtonClicked()
|
||||
{
|
||||
QString fileName = QFileDialog::getExistingDirectory(this,tr("Select your Models and Settings backup folder"), g.backupDir());
|
||||
QString fileName = QFileDialog::getExistingDirectory(this,tr("Select your global backup folder"), g.backupDir());
|
||||
if (!fileName.isEmpty()) {
|
||||
g.backupDir(fileName);
|
||||
ui->backupPath->setText(fileName);
|
||||
ui->backupEnable->setEnabled(true);
|
||||
ui->profileBackupEnable->setEnabled(true);
|
||||
} else {
|
||||
ui->backupEnable->setEnabled(false);
|
||||
if (!g.currentProfile().pBackupDir().isEmpty() && QFileInfo(g.currentProfile().pBackupDir()).exists()) {
|
||||
ui->profileBackupEnable->setEnabled(true);
|
||||
} else {
|
||||
ui->profileBackupEnable->setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::on_ProfilebackupPathButton_clicked()
|
||||
void AppPreferencesDialog::onProfileBackupPathButtonClicked()
|
||||
{
|
||||
QString fileName = QFileDialog::getExistingDirectory(this,tr("Select your Models and Settings backup folder"), g.backupDir());
|
||||
QString fileName = QFileDialog::getExistingDirectory(this,tr("Select your profile backup folder"), g.backupDir());
|
||||
if (!fileName.isEmpty()) {
|
||||
ui->profilebackupPath->setText(fileName);
|
||||
ui->pbackupEnable->setEnabled(true);
|
||||
ui->profileBackupPath->setText(fileName);
|
||||
ui->profileBackupEnable->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AppPreferencesDialog::on_btn_appLogsDir_clicked()
|
||||
{
|
||||
QString fileName = QFileDialog::getExistingDirectory(this, tr("Select a folder for application logs"), ui->appLogsDir->text());
|
||||
@@ -857,3 +869,32 @@ void AppPreferencesDialog::shrink()
|
||||
{
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::onBackupPathEditingFinished()
|
||||
{
|
||||
if(!ui->backupPath->text().isEmpty() && QFileInfo(ui->backupPath->text()).exists()) {
|
||||
ui->backupEnable->setEnabled(true);
|
||||
} else {
|
||||
ui->backupEnable->setChecked(false);
|
||||
ui->backupEnable->setEnabled(false);
|
||||
}
|
||||
|
||||
onProfileBackupPathEditingFinished();
|
||||
}
|
||||
|
||||
void AppPreferencesDialog::onProfileBackupPathEditingFinished()
|
||||
{
|
||||
if (!ui->profileBackupPath->text().isEmpty()) {
|
||||
if (QDir(ui->profileBackupPath->text()).exists()) {
|
||||
ui->profileBackupEnable->setEnabled(true);
|
||||
} else {
|
||||
ui->profileBackupEnable->setChecked(false);
|
||||
ui->profileBackupEnable->setEnabled(false);
|
||||
}
|
||||
} else if (!ui->backupPath->text().isEmpty() && QDir(ui->backupPath->text()).exists()) {
|
||||
ui->profileBackupEnable->setEnabled(true);
|
||||
} else {
|
||||
ui->profileBackupEnable->setChecked(false);
|
||||
ui->profileBackupEnable->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,8 +64,8 @@ class AppPreferencesDialog : public QDialog
|
||||
void on_libraryPathButton_clicked();
|
||||
void on_snapshotPathButton_clicked();
|
||||
void on_snapshotClipboardCKB_clicked();
|
||||
void on_backupPathButton_clicked();
|
||||
void on_ProfilebackupPathButton_clicked();
|
||||
void onBackupPathButtonClicked();
|
||||
void onProfileBackupPathButtonClicked();
|
||||
void on_ge_pathButton_clicked();
|
||||
|
||||
void on_sdPathButton_clicked();
|
||||
@@ -80,6 +80,8 @@ class AppPreferencesDialog : public QDialog
|
||||
#endif
|
||||
|
||||
void on_btnRadioColor_clicked();
|
||||
void onBackupPathEditingFinished();
|
||||
void onProfileBackupPathEditingFinished();
|
||||
|
||||
private:
|
||||
void initSettings();
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "burnconfigdialog.h"
|
||||
#include "ui_burnconfigdialog.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "helpers.h"
|
||||
#include "appdata.h"
|
||||
#include "progressdialog.h"
|
||||
#include "process_flash.h"
|
||||
|
||||
#if !defined _MSC_VER && defined __GNUC__
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
burnConfigDialog::burnConfigDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::burnConfigDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowIcon(CompanionIcon("configure.png"));
|
||||
|
||||
getSettings();
|
||||
Board::Type board = getCurrentBoard();
|
||||
if (IS_STM32(board)) {
|
||||
setWindowTitle(tr("DFU-UTIL Configuration"));
|
||||
ui->label_sb1->hide();
|
||||
ui->label_sb3->hide();
|
||||
ui->samba_location->hide();
|
||||
ui->samba_port->hide();
|
||||
ui->sb_browse->hide();
|
||||
}
|
||||
else {
|
||||
setWindowTitle(tr("SAM-BA Configuration"));
|
||||
ui->label_dfu1->hide();
|
||||
ui->dfu_location->hide();
|
||||
ui->dfu_browse->hide();
|
||||
}
|
||||
ui->label_sb2->hide();
|
||||
ui->arm_mcu->hide();
|
||||
ui->label_dfu2->hide();
|
||||
ui->dfuArgs->hide();
|
||||
|
||||
QTimer::singleShot(0, this, SLOT(shrink()));
|
||||
connect(this, SIGNAL(accepted()), this, SLOT(putSettings()));
|
||||
}
|
||||
|
||||
burnConfigDialog::~burnConfigDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
||||
void burnConfigDialog::getSettings()
|
||||
{
|
||||
sambaLoc = g.sambaLocation();
|
||||
dfuLoc = g.dfuLocation();
|
||||
|
||||
#if defined WIN32 || !defined __GNUC__
|
||||
if ( sambaLoc.isEmpty())
|
||||
sambaLoc = QFileInfo("sam-ba.exe").absoluteFilePath();
|
||||
if ( dfuLoc.isEmpty())
|
||||
dfuLoc = QFileInfo("bin/dfu-util.exe").absoluteFilePath();
|
||||
#elif defined __APPLE__
|
||||
if ( sambaLoc.isEmpty())
|
||||
sambaLoc = "/usr/local/bin/sam-ba";
|
||||
if ( dfuLoc.isEmpty())
|
||||
dfuLoc = QFileInfo(QApplication::applicationDirPath() + "/../Resources/dfu-util").absoluteFilePath();
|
||||
#elif defined __FreeBSD__
|
||||
if (dfuLoc.isEmpty())
|
||||
dfuLoc = "/usr/local/bin/dfu-util";
|
||||
#else
|
||||
if ( sambaLoc.isEmpty())
|
||||
sambaLoc = "/usr/bin/sam-ba";
|
||||
if ( dfuLoc.isEmpty())
|
||||
dfuLoc = QFileInfo("/usr/bin/dfu-util").absoluteFilePath();
|
||||
#endif
|
||||
|
||||
dfuArgs = g.dfuArguments().split(" ", Qt::SkipEmptyParts);
|
||||
armMCU = g.armMcu();
|
||||
sambaPort = g.sambaPort();
|
||||
|
||||
ui->samba_location->setText(getSAMBA());
|
||||
ui->samba_port->setText(getSambaPort());
|
||||
|
||||
ui->dfu_location->setText(getDFU());
|
||||
ui->dfuArgs->setText(getDFUArgs().join(" "));
|
||||
|
||||
int idx4 = ui->arm_mcu->findText(getArmMCU());
|
||||
if(idx4>=0) ui->arm_mcu->setCurrentIndex(idx4);
|
||||
QFile file;
|
||||
}
|
||||
|
||||
void burnConfigDialog::putSettings()
|
||||
{
|
||||
g.sambaLocation( sambaLoc );
|
||||
g.sambaPort( sambaPort );
|
||||
g.armMcu( armMCU );
|
||||
g.dfuLocation( dfuLoc );
|
||||
g.dfuArguments( dfuArgs.join(" ") );
|
||||
}
|
||||
|
||||
void burnConfigDialog::on_samba_location_editingFinished()
|
||||
{
|
||||
sambaLoc = ui->samba_location->text();
|
||||
}
|
||||
|
||||
void burnConfigDialog::on_samba_port_editingFinished()
|
||||
{
|
||||
sambaPort = ui->samba_port->text();
|
||||
}
|
||||
|
||||
void burnConfigDialog::on_arm_mcu_currentIndexChanged(QString )
|
||||
{
|
||||
armMCU = ui->arm_mcu->currentText();
|
||||
}
|
||||
|
||||
void burnConfigDialog::on_sb_browse_clicked()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Select Location"),ui->samba_location->text());
|
||||
if(!fileName.isEmpty())
|
||||
{
|
||||
ui->samba_location->setText(fileName);
|
||||
sambaLoc = fileName;
|
||||
}
|
||||
}
|
||||
|
||||
void burnConfigDialog::on_dfu_browse_clicked()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Select Location"),ui->dfu_location->text());
|
||||
|
||||
if(!fileName.isEmpty())
|
||||
{
|
||||
ui->dfu_location->setText(fileName);
|
||||
dfuLoc = fileName;
|
||||
}
|
||||
}
|
||||
|
||||
void burnConfigDialog::on_dfu_location_editingFinished()
|
||||
{
|
||||
dfuLoc = ui->dfu_location->text();
|
||||
}
|
||||
|
||||
void burnConfigDialog::on_dfuArgs_editingFinished()
|
||||
{
|
||||
dfuArgs = ui->dfuArgs->text().split(" ", Qt::SkipEmptyParts);
|
||||
}
|
||||
|
||||
void burnConfigDialog::on_advCtrChkB_toggled(bool checked)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
if (checked) {
|
||||
if (IS_STM32(board)) {
|
||||
ui->label_dfu2->show();
|
||||
ui->dfuArgs->show();
|
||||
}
|
||||
else {
|
||||
ui->label_sb2->show();
|
||||
ui->arm_mcu->show();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (IS_STM32(board)) {
|
||||
ui->label_dfu2->hide();
|
||||
ui->dfuArgs->hide();
|
||||
}
|
||||
else {
|
||||
ui->label_sb2->hide();
|
||||
ui->arm_mcu->hide();
|
||||
}
|
||||
}
|
||||
QTimer::singleShot(0, this, SLOT(shrink()));
|
||||
}
|
||||
|
||||
|
||||
void burnConfigDialog::shrink()
|
||||
{
|
||||
resize(0, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _BURNCONFIGDIALOG_H_
|
||||
#define _BURNCONFIGDIALOG_H_
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#define MEM_TYPE_EEPROM 1
|
||||
#define MEM_TYPE_FLASH 2
|
||||
|
||||
#define OPR_TYPE_READ 1
|
||||
#define OPR_TYPE_WRITE 2
|
||||
|
||||
namespace Ui {
|
||||
class burnConfigDialog;
|
||||
}
|
||||
|
||||
class burnConfigDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
burnConfigDialog(QWidget *parent = 0);
|
||||
~burnConfigDialog();
|
||||
|
||||
QString getSAMBA() {return sambaLoc;}
|
||||
QString getDFU() {return dfuLoc;}
|
||||
QStringList getDFUArgs() {return dfuArgs;}
|
||||
QString getArmMCU() {return armMCU;}
|
||||
QString getSambaPort() {return sambaPort;}
|
||||
|
||||
private:
|
||||
Ui::burnConfigDialog *ui;
|
||||
|
||||
void populateProgrammers();
|
||||
|
||||
QString sambaLoc;
|
||||
QString dfuLoc;
|
||||
QString armMCU;
|
||||
QString sambaPort;
|
||||
QStringList dfuArgs;
|
||||
|
||||
private slots:
|
||||
void shrink();
|
||||
void on_samba_location_editingFinished();
|
||||
void on_samba_port_editingFinished();
|
||||
void on_arm_mcu_currentIndexChanged(QString );
|
||||
void on_sb_browse_clicked();
|
||||
void on_dfu_browse_clicked();
|
||||
void on_dfu_location_editingFinished();
|
||||
void on_dfuArgs_editingFinished();
|
||||
void on_advCtrChkB_toggled(bool checked);
|
||||
void getSettings();
|
||||
void putSettings();
|
||||
};
|
||||
|
||||
#endif // _BURNCONFIGDIALOG_H_
|
||||
@@ -1,271 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>burnConfigDialog</class>
|
||||
<widget class="QDialog" name="burnConfigDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>531</width>
|
||||
<height>422</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>531</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Programmer Configuration</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="companion.qrc">
|
||||
<normaloff>:/icon.png</normaloff>:/icon.png</iconset>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="2" column="0">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
<property name="centerButtons">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="2">
|
||||
<widget class="QComboBox" name="arm_mcu">
|
||||
<property name="toolTip">
|
||||
<string>CPU of your TX</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>CPU present on your 9x radio
|
||||
Should be m64 for stock radios
|
||||
m2560 for v4.1 boards</string>
|
||||
</property>
|
||||
<property name="insertPolicy">
|
||||
<enum>QComboBox::InsertAlphabetically</enum>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">at91sam3s4-9x</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>at91sam3s8-9xr</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLineEdit" name="dfu_location">
|
||||
<property name="toolTip">
|
||||
<string>Location of sam-ba executable</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>The location of the AVRDUDE executable.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">dfu-util</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_dfu1">
|
||||
<property name="text">
|
||||
<string>DFU-Util Location</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_sb1">
|
||||
<property name="text">
|
||||
<string>SAM-BA Location</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="samba_location">
|
||||
<property name="toolTip">
|
||||
<string>Location of sam-ba executable</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>The location of the AVRDUDE executable.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">sam-ba.exe</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_sb2">
|
||||
<property name="text">
|
||||
<string>ARM MCU</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_sb3">
|
||||
<property name="text">
|
||||
<string>Port</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLineEdit" name="samba_port">
|
||||
<property name="toolTip">
|
||||
<string>sam-ba serial port</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>The location of the AVRDUDE executable.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">\USBserial\COM23</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_dfu2">
|
||||
<property name="text">
|
||||
<string>Alternate device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QLineEdit" name="dfuArgs">
|
||||
<property name="toolTip">
|
||||
<string>Extra arguments that will be passed to AVRDUDE on every call</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Extra arguments used in AVRDUDE.
|
||||
This can be used for providing extra information to AVRDUDE.
|
||||
|
||||
Please only use this if you know what you are doing. There are no error checks and you could cripple your controller.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QPushButton" name="sb_browse">
|
||||
<property name="whatsThis">
|
||||
<string>Use this button to browse and look for the AVRDUDE executable file.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QPushButton" name="dfu_browse">
|
||||
<property name="whatsThis">
|
||||
<string>Use this button to browse and look for the AVRDUDE executable file.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QCheckBox" name="advCtrChkB">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Use advanced controls</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>samba_location</tabstop>
|
||||
<tabstop>sb_browse</tabstop>
|
||||
<tabstop>arm_mcu</tabstop>
|
||||
<tabstop>samba_port</tabstop>
|
||||
<tabstop>dfu_location</tabstop>
|
||||
<tabstop>dfu_browse</tabstop>
|
||||
<tabstop>dfuArgs</tabstop>
|
||||
<tabstop>advCtrChkB</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="companion.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>burnConfigDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>burnConfigDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -69,18 +69,6 @@
|
||||
<file>images/wizard/throttle.png</file>
|
||||
<file>images/wizard/vtail.png</file>
|
||||
<file>images/wizard/wingtype.png</file>
|
||||
<file>images/library/00001.png</file>
|
||||
<file>images/library/00002.png</file>
|
||||
<file>images/library/00003.png</file>
|
||||
<file>images/library/00004.png</file>
|
||||
<file>images/library/00005.png</file>
|
||||
<file>images/library/00006.png</file>
|
||||
<file>images/library/00007.png</file>
|
||||
<file>images/library/00008.png</file>
|
||||
<file>images/library/00009.png</file>
|
||||
<file>images/library/00010.png</file>
|
||||
<file>images/library/00011.png</file>
|
||||
<file>images/library/00012.png</file>
|
||||
<file>images/library/00013.png</file>
|
||||
<file>images/library/00014.png</file>
|
||||
<file>images/library/00015.png</file>
|
||||
@@ -89,25 +77,6 @@
|
||||
<file>images/library/00018.png</file>
|
||||
<file>images/library/00019.png</file>
|
||||
<file>images/library/00020.png</file>
|
||||
<file>images/library/00021.png</file>
|
||||
<file>images/library/00022.png</file>
|
||||
<file>images/library/00050.png</file>
|
||||
<file>images/library/00051.png</file>
|
||||
<file>images/library/00052.png</file>
|
||||
<file>images/library/00053.png</file>
|
||||
<file>images/library/00054.png</file>
|
||||
<file>images/library/00055.png</file>
|
||||
<file>images/library/00056.png</file>
|
||||
<file>images/library/00057.png</file>
|
||||
<file>images/library/00058.png</file>
|
||||
<file>images/library/00059.png</file>
|
||||
<file>images/library/00060.png</file>
|
||||
<file>images/library/00061.png</file>
|
||||
<file>images/library/00062.png</file>
|
||||
<file>images/library/00063.png</file>
|
||||
<file>images/library/00064.png</file>
|
||||
<file>images/library/00065.png</file>
|
||||
<file>images/library/00066.png</file>
|
||||
<file>images/library/00100.png</file>
|
||||
<file>images/library/00101.png</file>
|
||||
<file>images/library/00102.png</file>
|
||||
@@ -122,7 +91,6 @@
|
||||
<file>images/library/00301.png</file>
|
||||
<file>images/library/00302.png</file>
|
||||
<file>images/library/00303.png</file>
|
||||
<file>images/library/00304.png</file>
|
||||
<file>images/library/00401.png</file>
|
||||
<file>images/library/00402.png</file>
|
||||
<file>images/library/00403.png</file>
|
||||
@@ -144,8 +112,6 @@
|
||||
<file>images/library/10601.png</file>
|
||||
<file>images/library/10701.png</file>
|
||||
<file>images/library/10702.png</file>
|
||||
<file>images/library/10801.png</file>
|
||||
<file>images/library/10802.png</file>
|
||||
<file>themes/default/style.css</file>
|
||||
<file>themes/default/style-osx.css</file>
|
||||
<file>themes/default/modelprt.css</file>
|
||||
|
||||
@@ -67,18 +67,14 @@
|
||||
|
||||
#define CPN_STR_FILES QCoreApplication::translate("Companion", "files")
|
||||
#define CPN_STR_RAD_MOD_SETTINGS QCoreApplication::translate("Companion", "Radio and Models settings")
|
||||
#define HEX_FILES_FILTER "HEX " % CPN_STR_FILES % " (*.hex);;"
|
||||
#define BIN_FILES_FILTER "BIN " % CPN_STR_FILES % " (*.bin);;"
|
||||
#define DFU_FILES_FILTER "DFU " % CPN_STR_FILES % " (*.dfu);;"
|
||||
#define EEPE_FILES_FILTER "EEPE " % CPN_STR_FILES % " (*.eepe);;"
|
||||
#define UF2_FILES_FILTER "UF2 " % CPN_STR_FILES % " (*.uf2);;"
|
||||
#define ETX_FILES_FILTER "EdgeTX " % CPN_STR_FILES % " (*.etx);;"
|
||||
#define YML_FILES_FILTER "EdgeTX YAML " % CPN_STR_FILES % " (*.yml);;"
|
||||
#define EEPROM_FILES_FILTER CPN_STR_RAD_MOD_SETTINGS % " " % CPN_STR_FILES % " (*.etx *.yml);;" % ETX_FILES_FILTER % YML_FILES_FILTER
|
||||
#define FLASH_FILES_FILTER "FLASH " % CPN_STR_FILES % " (*.bin *.hex *.dfu);;" % BIN_FILES_FILTER % HEX_FILES_FILTER % DFU_FILES_FILTER
|
||||
#define EXTERNAL_EEPROM_FILES_FILTER "EEPROM " % CPN_STR_FILES % " (*.bin *.hex);;" % BIN_FILES_FILTER % HEX_FILES_FILTER
|
||||
#define ER9X_EEPROM_FILE_TYPE "ER9X_EEPROM_FILE"
|
||||
#define FIRMWARE_FILES_FILTER "Firmware " % CPN_STR_FILES % " (*.bin *.uf2);;" % BIN_FILES_FILTER % UF2_FILES_FILTER
|
||||
#define EXTERNAL_EEPROM_FILES_FILTER "EEPROM " % CPN_STR_FILES % " (*.bin);;" % BIN_FILES_FILTER
|
||||
#define EEPE_EEPROM_FILE_HEADER "EEPE EEPROM FILE"
|
||||
#define EEPE_MODEL_FILE_HEADER "EEPE MODEL FILE"
|
||||
#define SIMU_FILES_FILTER ETX_FILES_FILTER
|
||||
|
||||
#define CPN_STR_APP_SETTINGS QCoreApplication::translate("Companion", "Application Settings")
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
project(flash)
|
||||
|
||||
set(${PROJECT_NAME}_NAMES
|
||||
customizesplashdialog
|
||||
flashfirmwaredialog
|
||||
process_copy
|
||||
process_sync
|
||||
radiointerface
|
||||
splashlibrarydialog
|
||||
)
|
||||
|
||||
AddHeadersSources()
|
||||
|
||||
# these have no cpp
|
||||
set(${PROJECT_NAME}_HDRS
|
||||
${${PROJECT_NAME}_HDRS}
|
||||
splashlabel.h
|
||||
)
|
||||
|
||||
qt_wrap_cpp(${PROJECT_NAME}_SRCS
|
||||
)
|
||||
|
||||
add_library(${PROJECT_NAME}
|
||||
${${PROJECT_NAME}_HDRS}
|
||||
${${PROJECT_NAME}_SRCS}
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${CPN_COMMON_LIB}
|
||||
${RS_DFU_LIBRARIES}
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
PUBLIC
|
||||
"${CMAKE_CURRENT_LIST_DIR}"
|
||||
"${RS_DFU_INCLUDE_DIRS}"
|
||||
)
|
||||
@@ -202,12 +202,11 @@ void CustomizeSplashDialog::on_copyLeftToRightButton_clicked() {
|
||||
right.copyImage(left);
|
||||
}
|
||||
|
||||
|
||||
void CustomizeSplashDialog::on_leftLoadFwButton_clicked() {loadFirmware(left);}
|
||||
void CustomizeSplashDialog::on_rightLoadFwButton_clicked() {loadFirmware(right);}
|
||||
void CustomizeSplashDialog::loadFirmware(Side side)
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Firmware File"), g.flashDir(), FLASH_FILES_FILTER);
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Firmware File"), g.flashDir(), FIRMWARE_FILES_FILTER);
|
||||
if (!fileName.isEmpty()) {
|
||||
if (!side.displayImage( fileName, FW ))
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Can not load embedded image from firmware file %1.").arg(fileName));
|
||||
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "flashfirmwaredialog.h"
|
||||
#include "ui_flashfirmwaredialog.h"
|
||||
#include "appdata.h"
|
||||
#include "helpers.h"
|
||||
#include "radiointerface.h"
|
||||
#include "firmwareinterface.h"
|
||||
#include "progressdialog.h"
|
||||
#include "progresswidget.h"
|
||||
#include "splashlibrarydialog.h"
|
||||
#include "storage.h"
|
||||
|
||||
FlashFirmwareDialog::FlashFirmwareDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::FlashFirmwareDialog),
|
||||
fwName(g.profile[g.id()].fwName())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
if (!g.currentProfile().splashFile().isEmpty()){
|
||||
imageSource = PROFILE;
|
||||
imageFile = g.currentProfile().splashFile();
|
||||
ui->useProfileSplash->setChecked(true);
|
||||
} else {
|
||||
imageSource = FIRMWARE;
|
||||
imageFile = "";
|
||||
ui->useProfileSplash->setDisabled(true);
|
||||
}
|
||||
|
||||
ui->checkHardwareCompatibility->setChecked(g.checkHardwareCompatibility());
|
||||
ui->checkBackup->setChecked(g.backupOnFlash());
|
||||
|
||||
detectClicked(true);
|
||||
updateUI();
|
||||
|
||||
connect(ui->detectButton, &QPushButton::clicked, this, &FlashFirmwareDialog::detectClicked);
|
||||
connect(ui->loadButton, &QPushButton::clicked, this, &FlashFirmwareDialog::loadClicked);
|
||||
connect(ui->useProfileSplash, &QRadioButton::clicked, this, &FlashFirmwareDialog::useProfileSplashClicked);
|
||||
connect(ui->useFirmwareSplash, &QRadioButton::clicked, this, &FlashFirmwareDialog::useFirmwareSplashClicked);
|
||||
connect(ui->useLibrarySplash, &QRadioButton::clicked, this, &FlashFirmwareDialog::useLibrarySplashClicked);
|
||||
connect(ui->useExternalSplash, &QRadioButton::clicked, this, &FlashFirmwareDialog::useExternalSplashClicked);
|
||||
connect(ui->writeButton, &QPushButton::clicked, this, &FlashFirmwareDialog::writeButtonClicked);
|
||||
connect(ui->cancelButton, &QPushButton::clicked, [this]() { close(); } );
|
||||
}
|
||||
|
||||
FlashFirmwareDialog::~FlashFirmwareDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::updateUI()
|
||||
{
|
||||
ui->firmwareFilename->setText(fwName);
|
||||
|
||||
if (connectionMode) {
|
||||
ui->loadButton->setEnabled(true);
|
||||
ui->writeButton->setEnabled(isFileConnectionCompatible() && QFile(fwName).exists());
|
||||
} else {
|
||||
ui->loadButton->setEnabled(false);
|
||||
ui->writeButton->setEnabled(false);
|
||||
}
|
||||
|
||||
FirmwareInterface firmware(fwName);
|
||||
if (firmware.isValid()) {
|
||||
ui->firmwareInfoFrame->show();
|
||||
ui->date->setText(firmware.getDate() + " " + firmware.getTime());
|
||||
ui->version->setText(firmware.getVersion());
|
||||
ui->variant->setText(firmware.getFlavour());
|
||||
ui->date->setEnabled(true);
|
||||
ui->version->setEnabled(true);
|
||||
ui->variant->setEnabled(true);
|
||||
|
||||
if (firmware.hasSplash()) {
|
||||
ui->splashFrame->show();
|
||||
ui->splash->setFixedSize(firmware.getSplashWidth(), firmware.getSplashHeight());
|
||||
} else {
|
||||
ui->splashFrame->hide();
|
||||
}
|
||||
} else {
|
||||
imageSource = FIRMWARE;
|
||||
ui->firmwareInfoFrame->hide();
|
||||
ui->splashFrame->hide();
|
||||
}
|
||||
|
||||
QImage image;
|
||||
switch (imageSource) {
|
||||
case FIRMWARE:
|
||||
ui->useFirmwareSplash->setChecked(true);
|
||||
image = firmware.getSplash();
|
||||
break;
|
||||
case PROFILE:
|
||||
ui->useProfileSplash->setChecked(true);
|
||||
image.load(g.currentProfile().splashFile());
|
||||
break;
|
||||
case LIBRARY:
|
||||
ui->useLibrarySplash->setChecked(true);
|
||||
image.load(imageFile);
|
||||
break;
|
||||
case EXTERNAL:
|
||||
ui->useExternalSplash->setChecked(true);
|
||||
image.load(imageFile);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!image.isNull())
|
||||
ui->splash->setPixmap(makePixMap(image));
|
||||
|
||||
QTimer::singleShot(0, [=]() { adjustSize(); });
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::loadClicked()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Firmware File"),
|
||||
g.flashDir(),
|
||||
getFirmwareFilesFilter());
|
||||
if (!fileName.isEmpty()) {
|
||||
if (!firmwareFileExtensions().contains(QFileInfo(fileName).suffix().toLower())) {
|
||||
QMessageBox::critical(this, tr("Open Firmware File"),
|
||||
tr("%1 has an unsupported file extension")
|
||||
.arg(fileName));
|
||||
return;
|
||||
}
|
||||
|
||||
FirmwareInterface fw(fileName);
|
||||
|
||||
if (!fw.isValid()) {
|
||||
QMessageBox::critical(this, tr("Open Firmware File"),
|
||||
tr("%1 is not a valid firmware file")
|
||||
.arg(fileName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (connectionMode == CONNECTION_UF2) {
|
||||
const Uf2Info uf2(getUf2Info());
|
||||
if (fw.getFlavour() != uf2.board) {
|
||||
QMessageBox::critical(this, tr("Open Firmware File"),
|
||||
tr("%1 \nFirmware file is for %2 radio however connected radio is %3")
|
||||
.arg(fileName)
|
||||
.arg(fw.getFlavour())
|
||||
.arg(uf2.board));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fw.getFlavour() != getCurrentFirmware()->getFlavour()) {
|
||||
QMessageBox::critical(this, tr("Open Firmware File"),
|
||||
tr("%1 \nFirmware file is for %2 radio however profile is for %3 radio")
|
||||
.arg(fileName)
|
||||
.arg(fw.getFlavour())
|
||||
.arg(getCurrentFirmware()->getFlavour()));
|
||||
return;
|
||||
}
|
||||
|
||||
fwName = fileName;
|
||||
updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::useFirmwareSplashClicked()
|
||||
{
|
||||
FirmwareInterface firmware(fwName);
|
||||
|
||||
if (!firmware.isValid()) {
|
||||
QMessageBox::warning(this, CPN_STR_TTL_ERROR, tr( "The firmware file is not valid." ));
|
||||
} else if (!firmware.hasSplash()) {
|
||||
QMessageBox::warning(this, CPN_STR_TTL_ERROR,
|
||||
tr( "There is no start screen image in the firmware file." ));
|
||||
} else {
|
||||
imageSource = FIRMWARE;
|
||||
}
|
||||
|
||||
updateUI();
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::useProfileSplashClicked()
|
||||
{
|
||||
QString fileName = g.currentProfile().splashFile();
|
||||
|
||||
if (!fileName.isEmpty()) {
|
||||
QImage image(fileName);
|
||||
if (image.isNull()) {
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR,
|
||||
tr("Profile image %1 is invalid.").arg(fileName));
|
||||
} else {
|
||||
imageSource = PROFILE;
|
||||
}
|
||||
}
|
||||
|
||||
updateUI();
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::useExternalSplashClicked()
|
||||
{
|
||||
QString supportedImageFormats;
|
||||
|
||||
for (int formatIndex = 0; formatIndex < QImageReader::supportedImageFormats().count(); formatIndex++) {
|
||||
supportedImageFormats += QLatin1String(" *.") + QImageReader::supportedImageFormats()[formatIndex];
|
||||
}
|
||||
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open image file to use as radio start screen"),
|
||||
g.imagesDir(),
|
||||
tr("Images (%1)").arg(supportedImageFormats));
|
||||
|
||||
if (!fileName.isEmpty()){
|
||||
g.imagesDir( QFileInfo(fileName).dir().absolutePath() );
|
||||
QImage image(fileName);
|
||||
|
||||
if (image.isNull()) {
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR,
|
||||
tr("Image could not be loaded from %1")
|
||||
.arg(fileName));
|
||||
} else {
|
||||
imageSource = EXTERNAL;
|
||||
imageFile = fileName;
|
||||
}
|
||||
}
|
||||
|
||||
updateUI();
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::useLibrarySplashClicked()
|
||||
{
|
||||
QString fileName;
|
||||
SplashLibraryDialog(this, &fileName).exec();
|
||||
|
||||
if (!fileName.isEmpty()) {
|
||||
QImage image(fileName);
|
||||
|
||||
if (image.isNull()) {
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("The library image could not be loaded"));
|
||||
} else {
|
||||
imageSource = LIBRARY;
|
||||
imageFile = fileName;
|
||||
}
|
||||
}
|
||||
|
||||
updateUI();
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::writeButtonClicked()
|
||||
{
|
||||
g.flashDir(QFileInfo(fwName).dir().absolutePath());
|
||||
g.currentProfile().fwName(fwName);
|
||||
g.checkHardwareCompatibility(ui->checkHardwareCompatibility->isChecked());
|
||||
g.backupOnFlash(ui->checkBackup->isChecked());
|
||||
|
||||
if (imageSource != FIRMWARE) {
|
||||
// load the splash image
|
||||
const QPixmap pixmap = ui->splash->pixmap(Qt::ReturnByValue);
|
||||
QImage image;
|
||||
image = pixmap.toImage().scaled(ui->splash->width(), ui->splash->height());
|
||||
|
||||
if (image.isNull()) {
|
||||
QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Splash image not found"));
|
||||
return;
|
||||
}
|
||||
|
||||
// write the customized firmware
|
||||
QString tempFile;
|
||||
tempFile = generateProcessUniqueTempFileName("flash.bin");
|
||||
qDebug() << "patching" << fwName << "with custom splash screen and saving to" << tempFile;
|
||||
FirmwareInterface firmware(fwName);
|
||||
firmware.setSplash(image);
|
||||
|
||||
if (firmware.save(tempFile) <= 0) {
|
||||
QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Cannot save customised firmware"));
|
||||
return;
|
||||
}
|
||||
|
||||
startWrite(tempFile);
|
||||
} else {
|
||||
startWrite(fwName);
|
||||
}
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::startWrite(const QString &filename)
|
||||
{
|
||||
close();
|
||||
|
||||
ProgressDialog progressDialog(this, tr("Flash Firmware to Radio"),
|
||||
CompanionIcon("write_flash.png"));
|
||||
|
||||
auto progress = progressDialog.progress();
|
||||
progress->addMessage(tr("Flashing with file: %1").arg(filename));
|
||||
bool checkHw = g.checkHardwareCompatibility();
|
||||
bool backup = g.backupOnFlash();
|
||||
FirmwareInterface newfw(filename);
|
||||
|
||||
if (g.checkHardwareCompatibility() || backup) {
|
||||
readFirmware(
|
||||
[this, &newfw, progress, checkHw, backup](const QByteArray &_data) {
|
||||
FirmwareInterface currfw(_data);
|
||||
if (!currfw.isValid()) {
|
||||
QString errMsg(tr("Firmware read from radio invalid"));
|
||||
progress->addMessage(errMsg, QtFatalMsg);
|
||||
progress->setInfo(errMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (backup) {
|
||||
if (!writeFirmwareToFile(this, _data, progress)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
progress->addMessage(tr("Backup of old firmware not requested"));
|
||||
}
|
||||
|
||||
if (checkHw) {
|
||||
if (!newfw.isHardwareCompatible(currfw)) {
|
||||
QString errMsg(tr("New firmware is not compatible"));
|
||||
progress->addMessage(errMsg, QtFatalMsg);
|
||||
progress->setInfo(errMsg);
|
||||
return;
|
||||
} else {
|
||||
progress->addMessage(tr("New firmware is compatible"));
|
||||
}
|
||||
} else {
|
||||
progress->addMessage(tr("New firmware compatibity check not requested"));
|
||||
}
|
||||
|
||||
progress->addMessage(tr("Start flashing firmware"));
|
||||
writeFirmware(newfw.getFlash(), progress);
|
||||
},
|
||||
[this, progress](const QString &err) {
|
||||
progress->addMessage(tr("Could not read current firmware: %1").arg(err));
|
||||
},
|
||||
progress);
|
||||
} else {
|
||||
progress->addMessage(tr("Start flashing firmware (no backup or compatiblity check)"));
|
||||
writeFirmware(newfw.getFlash(), progress);
|
||||
}
|
||||
|
||||
progressDialog.exec();
|
||||
|
||||
if (isTempFileName(filename)) {
|
||||
qDebug() << "Removing temporary file" << filename;
|
||||
qunlink(filename);
|
||||
}
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::detectClicked(bool atLoad)
|
||||
{
|
||||
QString connectionMsg;
|
||||
|
||||
if (isUf2DeviceFound()) {
|
||||
connectionMode = CONNECTION_UF2;
|
||||
connectionMsg = tr("Radio connection mode: UF2");
|
||||
} else if (isDfuDeviceFound()) {
|
||||
connectionMode = CONNECTION_DFU;
|
||||
connectionMsg = tr("Radio connection mode: DFU");
|
||||
} else {
|
||||
connectionMode = CONNECTION_NONE;
|
||||
connectionMsg = tr("ALERT: No radio connected");
|
||||
}
|
||||
|
||||
ui->connectionMode->setText(connectionMsg);
|
||||
|
||||
if (!connectionMode) {
|
||||
QMessageBox::warning((atLoad ? (QWidget *)parent(): this), tr("Detect Radio"),
|
||||
tr("Radio could not be detected by DFU or UF2 modes") % ".\n" %
|
||||
tr("Check cable is securely connected and radio lights are illuminated") % ".\n" %
|
||||
tr("Note: USB mode is not suitable for flashing firmware."));
|
||||
}
|
||||
|
||||
if (!isFileConnectionCompatible())
|
||||
fwName.clear();
|
||||
|
||||
if (!atLoad)
|
||||
updateUI();
|
||||
}
|
||||
|
||||
bool FlashFirmwareDialog::isFileConnectionCompatible()
|
||||
{
|
||||
if (!fwName.isEmpty()) {
|
||||
const QString extn(QFileInfo(fwName).suffix().toLower());
|
||||
if ((connectionMode == CONNECTION_DFU && dfuFileExtensions().contains(extn)) ||
|
||||
(connectionMode == CONNECTION_UF2 && uf2FileExtensions().contains(extn))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -19,12 +19,9 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _FLASHFIRMWAREDIALOG_H_
|
||||
#define _FLASHFIRMWAREDIALOG_H_
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets>
|
||||
#include "eeprominterface.h"
|
||||
#include "firmwareinterface.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
@@ -33,33 +30,33 @@ namespace Ui
|
||||
|
||||
class FlashFirmwareDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FlashFirmwareDialog(QWidget *parent = 0);
|
||||
~FlashFirmwareDialog();
|
||||
public:
|
||||
FlashFirmwareDialog(QWidget *parent = 0);
|
||||
~FlashFirmwareDialog();
|
||||
|
||||
private slots:
|
||||
void on_firmwareLoad_clicked();
|
||||
void on_burnButton_clicked();
|
||||
void on_cancelButton_clicked();
|
||||
void on_useProfileSplash_clicked();
|
||||
void on_useFirmwareSplash_clicked();
|
||||
void on_useLibrarySplash_clicked();
|
||||
void on_useExternalSplash_clicked();
|
||||
void shrink();
|
||||
private slots:
|
||||
void detectClicked(bool atLoad = false);
|
||||
void loadClicked();
|
||||
void writeButtonClicked();
|
||||
void useProfileSplashClicked();
|
||||
void useFirmwareSplashClicked();
|
||||
void useLibrarySplashClicked();
|
||||
void useExternalSplashClicked();
|
||||
|
||||
protected:
|
||||
void updateUI();
|
||||
void startFlash(const QString &filename);
|
||||
protected:
|
||||
void updateUI();
|
||||
void startWrite(const QString &filename);
|
||||
|
||||
private:
|
||||
Ui::FlashFirmwareDialog *ui;
|
||||
QString fwName;
|
||||
RadioData radioData;
|
||||
enum ImageSource {FIRMWARE, PROFILE, LIBRARY, EXTERNAL};
|
||||
ImageSource imageSource;
|
||||
QString imageFile;
|
||||
private:
|
||||
enum ConnectionModes { CONNECTION_NONE, CONNECTION_UF2, CONNECTION_DFU };
|
||||
enum ImageSource {FIRMWARE, PROFILE, LIBRARY, EXTERNAL};
|
||||
|
||||
Ui::FlashFirmwareDialog *ui;
|
||||
QString fwName;
|
||||
ImageSource imageSource;
|
||||
QString imageFile;
|
||||
int connectionMode;
|
||||
bool isFileConnectionCompatible();
|
||||
};
|
||||
|
||||
#endif // _FLASHFIRMWAREDIALOG_H_
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>421</width>
|
||||
<height>375</height>
|
||||
<height>390</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -26,12 +26,45 @@
|
||||
<string>Flash Firmware</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="companion.qrc">
|
||||
<iconset resource="../companion.qrc">
|
||||
<normaloff>:/icon.png</normaloff>:/icon.png</iconset>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout2">
|
||||
<item>
|
||||
<widget class="QLabel" name="connectionMode">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Radio connection: Unknown</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="detectButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Detect the boot mode of the connected radio</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Detect</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout4">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="firmwareFilename">
|
||||
<property name="enabled">
|
||||
@@ -55,13 +88,19 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="firmwareLoad">
|
||||
<widget class="QPushButton" name="loadButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Select and load a firmware file. The file extension must be one suitable for the boot mode.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Load...</string>
|
||||
</property>
|
||||
@@ -78,10 +117,10 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="3" column="0">
|
||||
@@ -93,20 +132,26 @@
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="version">
|
||||
<property name="toolTip">
|
||||
<string>Firmware build version</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="buildLabel">
|
||||
<widget class="QLabel" name="variantLabel">
|
||||
<property name="text">
|
||||
<string>Variant</string>
|
||||
<string>Radio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="variant">
|
||||
<property name="toolTip">
|
||||
<string>Target radio for which the firmware was built</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@@ -121,6 +166,9 @@
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="date">
|
||||
<property name="toolTip">
|
||||
<string>Buid timestamp</string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@@ -138,12 +186,12 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout3">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
@@ -197,10 +245,10 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -225,30 +273,27 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Allows Companion to write to older version of the firmware</string>
|
||||
<string>Checks the new firmware matches the connected radio. If not the process will be aborted.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Check Hardware compatibility</string>
|
||||
<string>Check hardware compatibility (recommended)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="backupEEprom">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
<widget class="QCheckBox" name="checkBackup">
|
||||
<property name="toolTip">
|
||||
<string>Read the connected radio firmware and write to the backup folder.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Backup and restore Models and Settings</string>
|
||||
</property>
|
||||
<property name="tristate">
|
||||
<bool>false</bool>
|
||||
<string>Backup radio firmware before flashing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="spacer2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
@@ -263,7 +308,7 @@
|
||||
<item>
|
||||
<spacer name="spacer1">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
@@ -287,7 +332,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="burnButton">
|
||||
<widget class="QPushButton" name="writeButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
@@ -297,6 +342,9 @@
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Performing optional processes and write the loaded file to the conneced radio.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Write to TX</string>
|
||||
</property>
|
||||
@@ -307,15 +355,15 @@
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>burnButton</tabstop>
|
||||
<tabstop>writeButton</tabstop>
|
||||
<tabstop>firmwareFilename</tabstop>
|
||||
<tabstop>firmwareLoad</tabstop>
|
||||
<tabstop>loadButton</tabstop>
|
||||
<tabstop>version</tabstop>
|
||||
<tabstop>variant</tabstop>
|
||||
<tabstop>cancelButton</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="companion.qrc"/>
|
||||
<include location="../companion.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,832 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "radiointerface.h"
|
||||
|
||||
#include "appdata.h"
|
||||
#include "progresswidget.h"
|
||||
#include "storage.h"
|
||||
#include "helpers.h"
|
||||
#include "firmwareinterface.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
|
||||
#include <chrono>
|
||||
#include <stdexcept>
|
||||
|
||||
#define TR(msg) QCoreApplication::translate("RadioInterface", msg)
|
||||
|
||||
constexpr int UF2_TRANSFER_SIZE {4 * 1024};
|
||||
constexpr char UF2_FIRMWARE_FILENAME[] {"CURRENT.UF2"};
|
||||
constexpr char UF2_INFO_FILENAME[] {"INFO_UF2.TXT"};
|
||||
constexpr char UF2_INDEX_FILENAME[] {"INDEX.HTM"};
|
||||
constexpr char UF2_NEW_FIRMWARE_FILENAME[] {"firmware.uf2"};
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
FirmwareReaderWorker::FirmwareReaderWorker(QObject *parent) :
|
||||
QThread(parent)
|
||||
{
|
||||
}
|
||||
|
||||
FirmwareReaderWorker::~FirmwareReaderWorker()
|
||||
{
|
||||
//qDebug() << "FirmwareReaderWorker destructor called";
|
||||
}
|
||||
|
||||
void FirmwareReaderWorker::run()
|
||||
{
|
||||
isUf2DeviceFound() ? runUf2() : runDfu();
|
||||
}
|
||||
|
||||
void FirmwareReaderWorker::runDfu()
|
||||
{
|
||||
try {
|
||||
auto device_filter = DfuDeviceFilter::empty_filter();
|
||||
auto devices = device_filter->find_devices();
|
||||
|
||||
if (devices.empty()) {
|
||||
throw std::runtime_error(tr("No DFU devices found").toStdString());
|
||||
} else if (devices.size() > 1) {
|
||||
throw std::runtime_error(tr("More than one DFU device found").toStdString());
|
||||
}
|
||||
|
||||
emit statusChanged("Resetting state...");
|
||||
auto &device = devices[0];
|
||||
device.reset_state();
|
||||
|
||||
auto addr = device.default_start_address();
|
||||
auto ctx = device.start_upload(addr, 0);
|
||||
|
||||
size_t total_length = ctx->get_length();
|
||||
size_t xfer_size = ctx->get_transfer_size();
|
||||
size_t bytes_uploaded = 0;
|
||||
|
||||
QByteArray data;
|
||||
while (bytes_uploaded < total_length) {
|
||||
auto rest_length = uint32_t(total_length - bytes_uploaded);
|
||||
auto single_xfer_size = std::min(uint32_t(xfer_size), rest_length);
|
||||
bytes_uploaded += single_xfer_size;
|
||||
|
||||
emit progressChanged(bytes_uploaded, total_length);
|
||||
emit statusChanged(tr("Reading %1 of %2").arg(bytes_uploaded).arg(total_length));
|
||||
data.append(ctx->upload(single_xfer_size));
|
||||
}
|
||||
|
||||
qDebug() << "Reading done";
|
||||
emit statusChanged("Reading done");
|
||||
emit complete(data);
|
||||
|
||||
// TODO: handle shouldStop
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
emit error(QString("DFU failed: %1").arg(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
void FirmwareReaderWorker::runUf2()
|
||||
{
|
||||
try {
|
||||
QString path = findMassStoragePath(UF2_FIRMWARE_FILENAME);
|
||||
QStorageInfo si(path);
|
||||
QFile fw(path);
|
||||
char buf[UF2_TRANSFER_SIZE];
|
||||
const int blockstotal = (fw.size() + UF2_TRANSFER_SIZE - 1) / UF2_TRANSFER_SIZE;
|
||||
emit progressChanged(0, blockstotal);
|
||||
emit statusChanged(tr("Reading..."));
|
||||
|
||||
qDebug() << "Reading started - file:" << fw.fileName()
|
||||
<< "size:" << fw.size()
|
||||
<< "blocks:" << blockstotal;
|
||||
|
||||
QByteArray data;
|
||||
if (fw.open(QIODevice::ReadOnly)) {
|
||||
int blockcnt = 0;
|
||||
qint64 bytesread = 0;
|
||||
int read = fw.read(buf, UF2_TRANSFER_SIZE);
|
||||
if (read == 0 && fw.size() > 0) {
|
||||
throw std::runtime_error(tr("Error reading %1 (reason: no data read)")
|
||||
.arg(fw.fileName()).toStdString());
|
||||
} else if (read < 0) {
|
||||
throw std::runtime_error(tr("Error reading %1 (reason: %2)")
|
||||
.arg(fw.fileName())
|
||||
.arg(fw.errorString()).toStdString());
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
// qDebug() << "read:" << read;
|
||||
bytesread += read;
|
||||
blockcnt++;
|
||||
data.append(buf, read);
|
||||
emit progressChanged(blockcnt, blockstotal);
|
||||
emit statusChanged(tr("Read block %1 of %2").arg(blockcnt).arg(blockstotal));
|
||||
read = fw.read(buf, UF2_TRANSFER_SIZE);
|
||||
} while (read > 0);
|
||||
|
||||
if (read < 0) {
|
||||
data.clear();
|
||||
throw std::runtime_error(tr("Error reading %1 (reason: %2)")
|
||||
.arg(fw.fileName())
|
||||
.arg(fw.errorString()).toStdString());
|
||||
} else if (bytesread < fw.size()) {
|
||||
data.clear();
|
||||
throw std::runtime_error(tr("Error reading %1 (reason: read %2 of %3)")
|
||||
.arg(fw.fileName())
|
||||
.arg(bytesread)
|
||||
.arg(fw.size()).toStdString());
|
||||
}
|
||||
|
||||
} else {
|
||||
throw std::runtime_error(tr("Cannot open %1 (reason: %2)")
|
||||
.arg(fw.fileName())
|
||||
.arg(fw.errorString()).toStdString());
|
||||
}
|
||||
|
||||
fw.close();
|
||||
qDebug() << "Reading done";
|
||||
emit statusChanged("Reading done");
|
||||
emit complete(data);
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
emit error(QString("UF2 failed: %1").arg(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
FirmwareWriterWorker::FirmwareWriterWorker(const QByteArray &data, QObject *parent) :
|
||||
QThread(parent),
|
||||
firmwareData(data)
|
||||
{
|
||||
}
|
||||
|
||||
FirmwareWriterWorker::~FirmwareWriterWorker()
|
||||
{
|
||||
//qDebug() << "FirmwareWriterWorker destructor called";
|
||||
}
|
||||
|
||||
void FirmwareWriterWorker::run()
|
||||
{
|
||||
isUf2DeviceFound() ? runUf2() : runDfu();
|
||||
}
|
||||
|
||||
void FirmwareWriterWorker::runUf2()
|
||||
{
|
||||
try {
|
||||
QString path = findMassStoragePath(UF2_FIRMWARE_FILENAME, true);
|
||||
if (path.isEmpty()) {
|
||||
throw std::runtime_error(tr("Cannot find USB device containing %1")
|
||||
.arg(UF2_FIRMWARE_FILENAME).toStdString());
|
||||
}
|
||||
|
||||
QStorageInfo si(path);
|
||||
if (si.bytesAvailable() < firmwareData.size()) {
|
||||
throw std::runtime_error(tr("Insufficient free space on %1 to write new firmware")
|
||||
.arg(QDir::toNativeSeparators(path)).toStdString());
|
||||
}
|
||||
|
||||
QFile newfw(Helpers::concatPath(path, UF2_NEW_FIRMWARE_FILENAME));
|
||||
int blockstotal = (firmwareData.size() + UF2_TRANSFER_SIZE - 1) / UF2_TRANSFER_SIZE;
|
||||
emit progressChanged(0, blockstotal);
|
||||
emit statusChanged(tr("Writing..."));
|
||||
|
||||
if (firmwareData.size() == 0)
|
||||
throw std::runtime_error(tr("No data to write to new firmware file").toStdString());
|
||||
|
||||
qDebug() << "Writing started - file:"
|
||||
<< newfw.fileName()
|
||||
<< "size:" << firmwareData.size()
|
||||
<< "blocks:" << blockstotal;
|
||||
|
||||
if (newfw.open(QIODevice::ReadWrite)) {
|
||||
int blockcnt = 0;
|
||||
qint64 byteswritten = 0;
|
||||
QByteArray ba = firmwareData.mid(blockcnt * UF2_TRANSFER_SIZE, UF2_TRANSFER_SIZE);
|
||||
|
||||
do
|
||||
{
|
||||
qint64 written = newfw.write(ba, ba.size());
|
||||
if (written < 0) {
|
||||
throw std::runtime_error(tr("Error writing %1 (reason: %2)")
|
||||
.arg(QDir::toNativeSeparators(newfw.fileName()))
|
||||
.arg(newfw.errorString()).toStdString());
|
||||
} else if (written < ba.size()) {
|
||||
throw std::runtime_error(tr("Error writing block to %1 (reason: bytes written %2 of %3)")
|
||||
.arg(QDir::toNativeSeparators(newfw.fileName()))
|
||||
.arg(written)
|
||||
.arg(ba.size()).toStdString());
|
||||
}
|
||||
|
||||
newfw.flush();
|
||||
byteswritten += written;
|
||||
blockcnt++;
|
||||
emit progressChanged(blockcnt, blockstotal);
|
||||
emit statusChanged(tr("Writing block %1 of %2").arg(blockcnt).arg(blockstotal));
|
||||
|
||||
ba.clear(); // just to be on the safe side
|
||||
ba = firmwareData.mid(blockcnt * UF2_TRANSFER_SIZE, UF2_TRANSFER_SIZE);
|
||||
} while (ba.size() > 0);
|
||||
|
||||
if (byteswritten < firmwareData.size()) {
|
||||
throw std::runtime_error(tr("Error writing %1 (reason: written %2 of %3)")
|
||||
.arg(QDir::toNativeSeparators(newfw.fileName()))
|
||||
.arg(byteswritten)
|
||||
.arg(firmwareData.size()).toStdString());
|
||||
}
|
||||
|
||||
} else {
|
||||
throw std::runtime_error(tr("Cannot open %1 (reason: %2)")
|
||||
.arg(QDir::toNativeSeparators(newfw.fileName()))
|
||||
.arg(newfw.errorString()).toStdString());
|
||||
}
|
||||
|
||||
newfw.close();
|
||||
qDebug() << "Writing done";
|
||||
emit statusChanged("Writing done");
|
||||
emit complete();
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
emit error(QString("UF2 failed: %1").arg(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
void FirmwareWriterWorker::runDfu()
|
||||
{
|
||||
try {
|
||||
auto device_filter = DfuDeviceFilter::empty_filter();
|
||||
auto devices = device_filter->find_devices();
|
||||
|
||||
if (devices.empty()) {
|
||||
throw std::runtime_error(tr("No DFU devices found").toStdString());
|
||||
} else if (devices.size() > 1) {
|
||||
throw std::runtime_error(tr("More than one DFU device found").toStdString());
|
||||
}
|
||||
|
||||
emit statusChanged("Resetting state...");
|
||||
auto &device = devices[0];
|
||||
device.reset_state();
|
||||
|
||||
SliceU8 buffer_slice((const uint8_t *)firmwareData.constData(),
|
||||
firmwareData.size());
|
||||
|
||||
if (!is_uf2_payload(buffer_slice)) {
|
||||
auto addr = device.default_start_address();
|
||||
writeRegion(device, addr, buffer_slice);
|
||||
} else {
|
||||
writeUf2(device, buffer_slice);
|
||||
}
|
||||
|
||||
device.leave();
|
||||
|
||||
emit statusChanged("Flashing done");
|
||||
emit complete();
|
||||
|
||||
// TODO: handle shouldStop
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
emit error(QString("DFU failed: %1").arg(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
void FirmwareWriterWorker::writeUf2(DfuDevice &device, const SliceU8 &data)
|
||||
{
|
||||
auto range_it = UF2RangeIterator::from_slice(data);
|
||||
auto addr_range = UF2AddressRange::new_empty();
|
||||
|
||||
while (range_it->next(*addr_range)) {
|
||||
auto addr = addr_range->start_address();
|
||||
const auto &payload = addr_range->payload();
|
||||
|
||||
uint32_t reboot_address = 0;
|
||||
|
||||
if (addr_range->reboot_address(reboot_address)) {
|
||||
rebootAndRediscover(device, addr, payload, reboot_address, 30s);
|
||||
} else {
|
||||
writeRegion(device, addr, payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FirmwareWriterWorker::writeRegion(const DfuDevice &device, uint32_t addr,
|
||||
const SliceU8 &data)
|
||||
{
|
||||
auto start_address = addr;
|
||||
auto end_address = start_address + data.size() - 1;
|
||||
|
||||
auto ctx = device.start_download(start_address, end_address);
|
||||
auto erase_pages = ctx->get_erase_pages();
|
||||
auto pages = erase_pages.size();
|
||||
|
||||
for (size_t i = 0; i < pages; i++) {
|
||||
updateEraseStatus(i + 1, pages);
|
||||
ctx->page_erase(erase_pages[i]);
|
||||
}
|
||||
|
||||
size_t bytes_downloaded = 0;
|
||||
auto data_ptr = data.data();
|
||||
auto xfer_size = ctx->get_transfer_size();
|
||||
|
||||
while (bytes_downloaded < data.size()) {
|
||||
auto single_xfer_size =
|
||||
std::min(uint32_t(xfer_size), uint32_t(data.size() - bytes_downloaded));
|
||||
bytes_downloaded += single_xfer_size;
|
||||
updateDownloadStatus(bytes_downloaded, data.size());
|
||||
ctx->download(addr, SliceU8(data_ptr, single_xfer_size));
|
||||
addr += single_xfer_size;
|
||||
data_ptr += single_xfer_size;
|
||||
}
|
||||
}
|
||||
|
||||
void FirmwareWriterWorker::updateEraseStatus(size_t page, size_t pages)
|
||||
{
|
||||
emit progressChanged(page, pages);
|
||||
emit statusChanged(tr("Erasing page %1 of %2").arg(page).arg(pages));
|
||||
}
|
||||
|
||||
void FirmwareWriterWorker::updateDownloadStatus(size_t bytes, size_t total)
|
||||
{
|
||||
emit progressChanged(bytes, total);
|
||||
emit statusChanged(tr("Writing %1 of %2").arg(bytes).arg(total));
|
||||
}
|
||||
|
||||
template <typename Duration>
|
||||
void FirmwareWriterWorker::rebootAndRediscover(DfuDevice &device, uint32_t addr,
|
||||
const SliceU8 &data,
|
||||
uint32_t reboot_addr,
|
||||
Duration timeout)
|
||||
{
|
||||
emit statusChanged(tr("Rebooting into DFU..."));
|
||||
emit progressChanged(0, 2);
|
||||
|
||||
device.reboot(addr, data, reboot_addr);
|
||||
emit progressChanged(1, 2);
|
||||
|
||||
emit statusChanged(tr("Waiting for device to reconnect..."));
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
|
||||
while (std::chrono::steady_clock::now() - start < timeout) {
|
||||
if (device.rediscover()) {
|
||||
emit statusChanged(tr("Device reconnected"));
|
||||
emit progressChanged(2, 2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error(
|
||||
tr("Timeout while reconnecting to device").toStdString());
|
||||
}
|
||||
|
||||
template <typename Worker>
|
||||
void connectProgress(Worker *worker, ProgressWidget *progress)
|
||||
{
|
||||
// lock the progress dialog for as long as the thread is running
|
||||
progress->connect(worker, &QThread::started, progress,
|
||||
[progress]() { progress->lock(true); });
|
||||
|
||||
progress->connect(worker, &QThread::finished, progress,
|
||||
[progress]() { progress->lock(false); });
|
||||
|
||||
// delete worker once the thread is finished
|
||||
progress->connect(worker, &QThread::finished, worker, &QObject::deleteLater);
|
||||
|
||||
// progress and status handling
|
||||
progress->connect(worker, &Worker::progressChanged, progress,
|
||||
[progress](int val, int max) {
|
||||
if (progress->maximum() != max)
|
||||
progress->setMaximum(max);
|
||||
progress->setValue(val);
|
||||
});
|
||||
|
||||
progress->connect(worker, &Worker::statusChanged, progress,
|
||||
[progress](const QString& status) {
|
||||
progress->addMessage(status);
|
||||
progress->setInfo(status);
|
||||
});
|
||||
|
||||
progress->connect(worker, &Worker::error, progress,
|
||||
[progress](const QString& status) {
|
||||
progress->addMessage(status, QtFatalMsg);
|
||||
progress->setInfo(status);
|
||||
});
|
||||
}
|
||||
|
||||
bool readFirmware(const std::function<void(const QByteArray &)>& onComplete,
|
||||
const std::function<void(const QString &)>& onError,
|
||||
ProgressWidget *progress)
|
||||
{
|
||||
auto worker = std::make_unique<FirmwareReaderWorker>();
|
||||
connectProgress(worker.get(), progress);
|
||||
|
||||
// connect closures
|
||||
progress->connect(worker.get(), &FirmwareReaderWorker::complete, progress, onComplete);
|
||||
progress->connect(worker.get(), &FirmwareReaderWorker::error, progress, onError);
|
||||
|
||||
// now start it!
|
||||
worker.release()->start();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readFirmware(const std::function<void(const QByteArray &)>& onComplete,
|
||||
ProgressWidget *progress)
|
||||
{
|
||||
auto worker = std::make_unique<FirmwareReaderWorker>(progress);
|
||||
connectProgress(worker.get(), progress);
|
||||
|
||||
// write data to file on success
|
||||
progress->connect(worker.get(), &FirmwareReaderWorker::complete, progress, onComplete);
|
||||
|
||||
// now start it!
|
||||
worker.release()->start();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readFirmware(const QString &filename, ProgressWidget *progress)
|
||||
{
|
||||
QFile::remove(filename);
|
||||
return readFirmware(
|
||||
[filename](const QByteArray &data) {
|
||||
QFile file(filename);
|
||||
if (!file.open(QFile::WriteOnly)) {
|
||||
qDebug() << "Unable to write to " << filename;
|
||||
} else {
|
||||
file.write(data);
|
||||
file.close();
|
||||
qDebug() << "Firmware written to " << filename;
|
||||
}
|
||||
},
|
||||
progress);
|
||||
}
|
||||
|
||||
bool readFirmware(QByteArray &data, ProgressWidget *progress)
|
||||
{
|
||||
return readFirmware([&data](const QByteArray &_data) { data = _data; },
|
||||
progress);
|
||||
}
|
||||
|
||||
bool writeFirmware(const QString &filename, ProgressWidget *progress)
|
||||
{
|
||||
QFile f(filename);
|
||||
if (!f.open(QIODeviceBase::ReadOnly)) {
|
||||
QMessageBox::critical(nullptr, TR("Write Firmware"),
|
||||
TR("Cannot open file '%1': %2")
|
||||
.arg(QDir::toNativeSeparators(filename))
|
||||
.arg(f.errorString()));
|
||||
}
|
||||
|
||||
auto data = f.readAll();
|
||||
f.close();
|
||||
|
||||
return writeFirmware(data, progress);
|
||||
}
|
||||
|
||||
bool writeFirmware(const QByteArray &data, ProgressWidget *progress)
|
||||
{
|
||||
auto worker = std::make_unique<FirmwareWriterWorker>(data, progress);
|
||||
connectProgress(worker.get(), progress);
|
||||
|
||||
// now start it!
|
||||
worker.release()->start();
|
||||
return true;
|
||||
}
|
||||
|
||||
QString printDevicesInfo(const Vec<DfuDevice> &devices)
|
||||
{
|
||||
QString ret;
|
||||
for (const auto &device : devices) {
|
||||
auto dev_info = device.device_info();
|
||||
ret.append(QString("%1:%2: %3 (%4)\n").arg(QString::number(dev_info.vendor_id, 16))
|
||||
.arg(QString::number(dev_info.product_id, 16))
|
||||
.arg(dev_info.product_string.c_str())
|
||||
.arg(QString::number(device.default_start_address(), 16)));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString getDevicesInfo()
|
||||
{
|
||||
try {
|
||||
auto device_filter = DfuDeviceFilter::empty_filter();
|
||||
auto devices = device_filter->find_devices();
|
||||
if (devices.empty()) {
|
||||
return QString("No DFU devices found");
|
||||
}
|
||||
|
||||
return printDevicesInfo(devices);
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
return QString("Error: %1").arg(e.what());
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool readSettings(const QString &filename, ProgressWidget *progress)
|
||||
{
|
||||
QFile file(filename);
|
||||
if (file.exists() && !file.remove()) {
|
||||
QMessageBox::warning(nullptr, CPN_STR_TTL_ERROR,
|
||||
TR("Could not delete temporary file: %1")
|
||||
.arg(QDir::toNativeSeparators(filename)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return readSettingsSDCard(filename, progress);
|
||||
}
|
||||
|
||||
bool readSettingsSDCard(const QString &filename, ProgressWidget *progress,
|
||||
bool fromRadio)
|
||||
{
|
||||
QString radioPath;
|
||||
if (fromRadio) {
|
||||
radioPath = findMassStoragePath("RADIO", true, progress);
|
||||
qDebug() << "Searching for SD card, found" << radioPath;
|
||||
} else {
|
||||
radioPath = g.currentProfile().sdPath();
|
||||
if (!QFile::exists(radioPath % "/RADIO"))
|
||||
radioPath.clear();
|
||||
}
|
||||
|
||||
if (radioPath.isEmpty()) {
|
||||
QMessageBox::critical(progress, CPN_STR_TTL_ERROR, TR("Unable to find SD card!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
RadioData radioData;
|
||||
Storage inputStorage(radioPath);
|
||||
|
||||
if (!inputStorage.load(radioData)) {
|
||||
QString errorMsg = inputStorage.error();
|
||||
if (errorMsg.isEmpty())
|
||||
errorMsg = TR("Failed to read Models and Settings from")
|
||||
% QDir::toNativeSeparators(radioPath);
|
||||
|
||||
QMessageBox::critical(progress, CPN_STR_TTL_ERROR, errorMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
Storage outputStorage(filename);
|
||||
if (!outputStorage.write(radioData)) {
|
||||
QMessageBox::critical(progress, CPN_STR_TTL_ERROR,
|
||||
TR("Failed to write Models and Setting file") % " "
|
||||
% QDir::toNativeSeparators(filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
return QFileInfo(filename).exists();
|
||||
}
|
||||
|
||||
QString findMassStoragePath(const QString &filename, bool onlyPath, ProgressWidget *progress)
|
||||
{
|
||||
QString foundPath;
|
||||
QString foundProbefile;
|
||||
int found = 0;
|
||||
// Linux: "vfat"; macOS: "msdos" or "lifs"; Win: "FAT32"
|
||||
QRegularExpression fstypeRe("^(v?fat|msdos|lifs)",
|
||||
QRegularExpression::CaseInsensitiveOption);
|
||||
|
||||
foreach (const QStorageInfo &si, QStorageInfo::mountedVolumes()) {
|
||||
if (!si.isReady() || si.isReadOnly() || !QString(si.fileSystemType()).contains(fstypeRe))
|
||||
continue;
|
||||
|
||||
qDebug() << "device:" << si.device()
|
||||
<< "type:" << si.fileSystemType()
|
||||
<< "block size:" << si.blockSize()
|
||||
<< "capacity:" << si.bytesTotal() / 1000 / 1000 << "MB"
|
||||
<< "available:" << si.bytesFree() / 1000/ 1000 << "MB"
|
||||
<< "root path:" << si.rootPath();
|
||||
|
||||
QString temppath = si.rootPath();
|
||||
QString probefile = Helpers::concatPath(temppath, filename);
|
||||
qDebug() << "Searching for" << probefile;
|
||||
if (QFile::exists(probefile)) {
|
||||
found++;
|
||||
foundPath = temppath;
|
||||
foundProbefile = probefile;
|
||||
qDebug() << probefile << "found";
|
||||
}
|
||||
}
|
||||
|
||||
if (found == 1) {
|
||||
return onlyPath ? foundPath : foundProbefile;
|
||||
} else if (found > 1) {
|
||||
QMessageBox::critical(progress, CPN_STR_TTL_ERROR, QDir::toNativeSeparators(filename)
|
||||
% " " % TR("found in multiple locations"));
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString getFirmwareFilesFilter()
|
||||
{
|
||||
return isUf2DeviceFound() ? QString(UF2_FILES_FILTER) : QString(FIRMWARE_FILES_FILTER);
|
||||
}
|
||||
|
||||
Uf2Info getUf2Info()
|
||||
{
|
||||
Uf2Info info;
|
||||
QString path = findMassStoragePath(UF2_INFO_FILENAME);
|
||||
if (path.isEmpty())
|
||||
return info;
|
||||
|
||||
QFile file(path);
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
QMessageBox::critical(nullptr, CPN_STR_TTL_ERROR,
|
||||
TR("Error opening file %1:\n%2.")
|
||||
.arg(QDir::toNativeSeparators(path)).arg(file.errorString()));
|
||||
return info;
|
||||
}
|
||||
|
||||
QByteArray filedata;
|
||||
const char *version_label = "UF2 Bootloader";
|
||||
const char *board_label = "Board-ID:";
|
||||
const char *date_label = "Date:";
|
||||
|
||||
filedata = file.readLine();
|
||||
|
||||
do
|
||||
{
|
||||
if (filedata.startsWith(version_label))
|
||||
info.version = filedata.mid(QString(version_label).size()).trimmed();
|
||||
else if (filedata.startsWith(board_label))
|
||||
info.board = filedata.mid(QString(board_label).size()).trimmed();
|
||||
else if (filedata.startsWith(date_label))
|
||||
info.date = filedata.mid(QString(date_label).size()).trimmed();
|
||||
|
||||
filedata = file.readLine();
|
||||
|
||||
} while (!filedata.isEmpty());
|
||||
|
||||
file.close();
|
||||
|
||||
qDebug() << "UF2 information - version:" << info.version
|
||||
<< "board:" << info.board
|
||||
<< "date:" << info.date;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
bool isUf2DeviceFound()
|
||||
{
|
||||
return !findMassStoragePath("INFO_UF2.TXT", false).isEmpty();
|
||||
}
|
||||
|
||||
bool isDfuDeviceFound()
|
||||
{
|
||||
try {
|
||||
auto device_filter = DfuDeviceFilter::empty_filter();
|
||||
auto devices = device_filter->find_devices();
|
||||
if (devices.empty()) {
|
||||
return false;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isRadioConnected()
|
||||
{
|
||||
return isUf2DeviceFound() || isDfuDeviceFound();
|
||||
}
|
||||
|
||||
bool writeFirmwareToFile(QWidget *parent, const QByteArray &data, ProgressWidget *progress, bool promptForFile)
|
||||
{
|
||||
QString msg(TR("Writing radio firmware to file starting..."));
|
||||
progress->setInfo(msg);
|
||||
progress->addMessage(msg);
|
||||
|
||||
FirmwareInterface fw(data);
|
||||
if (!fw.isValid()) {
|
||||
QString errMsg(TR("Firmware is not invalid"));
|
||||
progress->addMessage(errMsg, QtFatalMsg);
|
||||
progress->setInfo(errMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
QString backupDir;
|
||||
|
||||
if (g.currentProfile().getVariantFromType() == fw.getFlavour()) {
|
||||
progress->addMessage(TR("Current profile firmware type matches radio"));
|
||||
backupDir = g.currentProfile().pBackupDir();
|
||||
}
|
||||
else {
|
||||
// try to find a profile but there could be more than one profile for same variant
|
||||
// if more than one take safer approach and use global
|
||||
progress->addMessage(TR("Searching profiles for firmware type..."));
|
||||
int cnt = 0;
|
||||
int profId = 0;
|
||||
QMap<int, QString> map;
|
||||
map = g.getActiveProfiles();
|
||||
if (map.size() > 0) {
|
||||
QMapIterator<int, QString> i(map);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (g.getProfile(i.key()).getVariantFromType() == fw.getFlavour()) {
|
||||
progress->addMessage(TR("Firmware type match found in profile %1 %2")
|
||||
.arg(QString::number(i.key()))
|
||||
.arg(i.value()));
|
||||
profId = i.key();
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
progress->addMessage(TR("%1 matches found. Using profile %2 %3")
|
||||
.arg(QString::number(cnt))
|
||||
.arg(QString::number(profId))
|
||||
.arg(g.getProfile(profId).name()));
|
||||
|
||||
if (cnt > 0)
|
||||
backupDir = g.getProfile(profId).pBackupDir();
|
||||
}
|
||||
}
|
||||
|
||||
if (backupDir.isEmpty())
|
||||
backupDir = g.backupDir();
|
||||
|
||||
progress->addMessage(TR("Backup directory: %1").arg(QDir::toNativeSeparators(backupDir)));
|
||||
|
||||
// include time in file name as there could be multiple backups in a day
|
||||
QString filePath = QString("%1/fw-%2-%3-%4.%5")
|
||||
.arg(backupDir.replace("\\", "/")) // for Windows
|
||||
.arg(fw.getFlavour())
|
||||
.arg(QDate(QDate::currentDate()).toString("yyyyMMdd"))
|
||||
.arg(QTime(QTime::currentTime()).toString("HHmmss"))
|
||||
.arg(fw.typeFileExtn());
|
||||
|
||||
if (promptForFile) {
|
||||
filePath = QFileDialog::getSaveFileName(parent, TR("Save Firmware to File"),
|
||||
filePath, getFirmwareFilesFilter());
|
||||
|
||||
if (filePath.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
} else if (backupDir.isEmpty()) {
|
||||
progress->addMessage(TR("Backup directory not configured for profile or application"),
|
||||
QtFatalMsg);
|
||||
return false;
|
||||
} else if (!QFileInfo::exists(backupDir)) {
|
||||
progress->addMessage(TR("Backup directory does not exist: %1")
|
||||
.arg(QDir::toNativeSeparators(backupDir)), QtFatalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
progress->addMessage(TR("Writing firmware to: %1").arg(QDir::toNativeSeparators(filePath)));
|
||||
|
||||
QFile f(filePath);
|
||||
if (!f.open(QIODevice::ReadWrite)) {
|
||||
progress->addMessage(TR("Error opening file for writing: %1 (reason: %2)")
|
||||
.arg(QDir::toNativeSeparators(f.fileName()))
|
||||
.arg(f.errorString()), QtFatalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f.write(data) <= 0) {
|
||||
progress->addMessage(TR("Error writing to file: %1 (reason: %2)")
|
||||
.arg(QDir::toNativeSeparators(f.fileName()))
|
||||
.arg(f.errorString()), QtFatalMsg);
|
||||
f.close();
|
||||
return false;
|
||||
} else {
|
||||
msg = TR("Writing radio firmware to file finished");
|
||||
progress->addMessage(msg);
|
||||
progress->setInfo(msg);
|
||||
}
|
||||
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
QStringList dfuFileExtensions()
|
||||
{
|
||||
return QStringList() << "bin" << "uf2";
|
||||
}
|
||||
|
||||
QStringList uf2FileExtensions()
|
||||
{
|
||||
return QStringList() << "uf2";
|
||||
}
|
||||
|
||||
QStringList firmwareFileExtensions()
|
||||
{
|
||||
return dfuFileExtensions();
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rs_dfu.h"
|
||||
|
||||
#include <QThread>
|
||||
#include <QString>
|
||||
|
||||
using SliceU8 = rust::Slice<const uint8_t>;
|
||||
using ::rust::Vec;
|
||||
|
||||
class FirmwareReaderWorker : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FirmwareReaderWorker(QObject *parent = nullptr);
|
||||
~FirmwareReaderWorker();
|
||||
|
||||
protected:
|
||||
void run() override;
|
||||
|
||||
signals:
|
||||
void progressChanged(int value, int total);
|
||||
void statusChanged(const QString &status);
|
||||
void error(const QString &error);
|
||||
void complete(const QByteArray& data);
|
||||
|
||||
private:
|
||||
void runDfu();
|
||||
void runUf2();
|
||||
};
|
||||
|
||||
class FirmwareWriterWorker : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
QByteArray firmwareData;
|
||||
|
||||
public:
|
||||
explicit FirmwareWriterWorker(const QByteArray &data, QObject *parent = nullptr);
|
||||
~FirmwareWriterWorker();
|
||||
|
||||
protected:
|
||||
void run() override;
|
||||
|
||||
signals:
|
||||
void progressChanged(int value, int total);
|
||||
void statusChanged(const QString &status);
|
||||
void error(const QString &error);
|
||||
void complete();
|
||||
|
||||
private:
|
||||
void writeUf2(DfuDevice &device, const SliceU8 &data);
|
||||
void writeRegion(const DfuDevice &device, uint32_t addr, const SliceU8 &data);
|
||||
void updateEraseStatus(size_t page, size_t pages);
|
||||
void updateDownloadStatus(size_t bytes, size_t total);
|
||||
void runDfu();
|
||||
void runUf2();
|
||||
|
||||
template <typename Duration>
|
||||
void rebootAndRediscover(DfuDevice &device, uint32_t addr,
|
||||
const SliceU8 &data, uint32_t reboot_addr,
|
||||
Duration timeout);
|
||||
};
|
||||
|
||||
|
||||
class ProgressWidget;
|
||||
|
||||
// TODO make a class
|
||||
struct Uf2Info {
|
||||
QString version;
|
||||
QString board;
|
||||
QString date;
|
||||
};
|
||||
|
||||
QString findMassStoragePath(const QString &filename, bool onlyPath = false, ProgressWidget *progress = nullptr);
|
||||
|
||||
bool readFirmware(const std::function<void(const QByteArray &)>& onComplete,
|
||||
const std::function<void(const QString &)>& onError,
|
||||
ProgressWidget *progress);
|
||||
|
||||
bool readFirmware(QByteArray &data, ProgressWidget *progress);
|
||||
bool readFirmware(const QString &filename, ProgressWidget *progress);
|
||||
|
||||
bool writeFirmware(const QByteArray &data, ProgressWidget *progress);
|
||||
bool writeFirmware(const QString &filename, ProgressWidget *progress);
|
||||
|
||||
bool readSettings(const QString &filename, ProgressWidget *progress);
|
||||
bool readSettingsSDCard(const QString &filename, ProgressWidget *progress, bool fromRadio = true);
|
||||
|
||||
bool writeSettings(const QString &filename, ProgressWidget *progress);
|
||||
|
||||
QString printDevicesInfo(const Vec<DfuDevice> &devices);
|
||||
QString getDevicesInfo();
|
||||
QString getFirmwareFilesFilter();
|
||||
Uf2Info getUf2Info();
|
||||
bool isDfuDeviceFound();
|
||||
bool isUf2DeviceFound();
|
||||
bool isRadioConnected();
|
||||
bool writeFirmwareToFile(QWidget *parent, const QByteArray &data, ProgressWidget *progress, bool promptForFile = false);
|
||||
QStringList dfuFileExtensions();
|
||||
QStringList uf2FileExtensions();
|
||||
QStringList firmwareFileExtensions();
|
||||
@@ -19,68 +19,42 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _SPLASHLABEL_H_
|
||||
#define _SPLASHLABEL_H_
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
class splashLabel : public QLabel
|
||||
class SplashLabel : public QLabel
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit splashLabel(QDialog * parent = 0) :
|
||||
QLabel(parent)
|
||||
{
|
||||
}
|
||||
explicit SplashLabel(QDialog * parent = 0) : QLabel(parent) {}
|
||||
|
||||
virtual void setId(int labelindex)
|
||||
{
|
||||
index = labelindex;
|
||||
}
|
||||
|
||||
virtual int getId()
|
||||
{
|
||||
return index;
|
||||
}
|
||||
virtual void setId(int labelindex) { index = labelindex; }
|
||||
virtual int getId() { return index; }
|
||||
|
||||
protected:
|
||||
|
||||
virtual void mousePressEvent(QMouseEvent * event)
|
||||
{
|
||||
if (event->type() == QEvent::MouseButtonDblClick) {
|
||||
emit buttonPressed(Qt::Key_Enter);
|
||||
emit clicked(Qt::Key_Enter);
|
||||
}
|
||||
else {
|
||||
emit buttonPressed(Qt::Key_Select);
|
||||
emit clicked(Qt::Key_Select);
|
||||
}
|
||||
// QWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
virtual void mouseReleaseEvent(QMouseEvent * event)
|
||||
{
|
||||
setFocus();
|
||||
// emit buttonPressed(0);
|
||||
// QWidget::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
|
||||
/*void paintEvent(QPaintEvent *)
|
||||
{
|
||||
QStyleOption opt;
|
||||
opt.init(this);
|
||||
QPainter p(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
|
||||
}
|
||||
*/
|
||||
signals:
|
||||
void buttonPressed(int button);
|
||||
void clicked(int button);
|
||||
|
||||
private:
|
||||
int index;
|
||||
};
|
||||
|
||||
#endif // _SPLASHLABEL_H_
|
||||
|
||||
@@ -37,14 +37,18 @@ SplashLibraryDialog::SplashLibraryDialog(QWidget *parent, QString * filename):
|
||||
ui->prevPage->setIcon(CompanionIcon("arrow-left.png"));
|
||||
page = 0;
|
||||
getFileList();
|
||||
if (imageList.size() > 20) {
|
||||
|
||||
if (imageList.size() > 20)
|
||||
ui->nextPage->setEnabled(true);
|
||||
}
|
||||
|
||||
setupPage(page);
|
||||
|
||||
foreach(splashLabel *sl, findChildren<splashLabel *>()) {
|
||||
connect(sl, SIGNAL(buttonPressed(int)), this, SLOT(onButtonPressed(int)));
|
||||
foreach(SplashLabel *sl, findChildren<SplashLabel *>()) {
|
||||
connect(sl, &SplashLabel::clicked, this, &SplashLibraryDialog::imageClicked);
|
||||
}
|
||||
|
||||
connect(ui->nextPage, &QPushButton::clicked, this, &SplashLibraryDialog::nextPageClicked);
|
||||
connect(ui->prevPage, &QPushButton::clicked, this, &SplashLibraryDialog::prevPageClicked);
|
||||
}
|
||||
|
||||
SplashLibraryDialog::~SplashLibraryDialog()
|
||||
@@ -54,12 +58,13 @@ SplashLibraryDialog::~SplashLibraryDialog()
|
||||
|
||||
void SplashLibraryDialog::setupPage(int page)
|
||||
{
|
||||
splashLabel * sl[] = { ui->FwImage_01, ui->FwImage_02, ui->FwImage_03, ui->FwImage_04 ,
|
||||
SplashLabel *sl[] = { ui->FwImage_01, ui->FwImage_02, ui->FwImage_03, ui->FwImage_04 ,
|
||||
ui->FwImage_05, ui->FwImage_06, ui->FwImage_07, ui->FwImage_08 ,
|
||||
ui->FwImage_09, ui->FwImage_10, ui->FwImage_11, ui->FwImage_12 ,
|
||||
ui->FwImage_13, ui->FwImage_14, ui->FwImage_15, ui->FwImage_16 ,
|
||||
ui->FwImage_17, ui->FwImage_18, ui->FwImage_19, ui->FwImage_20 };
|
||||
for(int i=0; i<20; i++) {
|
||||
|
||||
for(int i = 0; i < 20; i++) {
|
||||
if ((i + 20 * page) < imageList.size()) {
|
||||
QImage image(imageList.at(i + 20 * page));
|
||||
if (!image.isNull()) {
|
||||
@@ -67,15 +72,13 @@ void SplashLibraryDialog::setupPage(int page)
|
||||
sl[i]->setEnabled(true);
|
||||
sl[i]->setId((i + 20 * page));
|
||||
sl[i]->setStyleSheet("border:1px solid; border-color:#999999;");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
sl[i]->clear();
|
||||
sl[i]->setDisabled(true);
|
||||
sl[i]->setStyleSheet("border:1px;");
|
||||
sl[i]->setId(-1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
sl[i]->clear();
|
||||
sl[i]->setDisabled(true);
|
||||
sl[i]->setStyleSheet("border:1px;");
|
||||
@@ -89,14 +92,18 @@ void SplashLibraryDialog::getFileList()
|
||||
{
|
||||
imageList.clear();
|
||||
if (g.embedSplashes()) {
|
||||
QDir myRes(":/images/library");
|
||||
const QString imgLocn(":/images/library");
|
||||
QDir myRes(imgLocn);
|
||||
QStringList tmp = myRes.entryList();
|
||||
|
||||
for (int i = 0; i < tmp.size(); i++) {
|
||||
QFileInfo fileInfo(tmp.at(i));
|
||||
imageList.append(":/images/library/" + fileInfo.fileName());
|
||||
imageList.append(imgLocn + "/" + fileInfo.fileName());
|
||||
}
|
||||
}
|
||||
|
||||
QString libraryPath = g.libDir();
|
||||
|
||||
if (!libraryPath.isEmpty()) {
|
||||
if (QDir(libraryPath).exists()) {
|
||||
QStringList supportedImageFormats;
|
||||
@@ -112,59 +119,60 @@ void SplashLibraryDialog::getFileList()
|
||||
QImage image(filename);
|
||||
if (!image.isNull()) {
|
||||
imageList.append(filename);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
QMessageBox::warning(this, CPN_STR_TTL_WARNING, tr("Invalid image in library %1").arg(filename));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (imageList.size() == 0) {
|
||||
QMessageBox::information(this, CPN_STR_TTL_INFO, tr("No valid image found in library, check your settings"));
|
||||
QTimer::singleShot(0, this, SLOT(dclose()));
|
||||
QTimer::singleShot(0, [=]() { close(); });
|
||||
}
|
||||
else {
|
||||
imageList.sort();
|
||||
}
|
||||
}
|
||||
|
||||
void SplashLibraryDialog::dclose()
|
||||
void SplashLibraryDialog::imageClicked(int button)
|
||||
{
|
||||
close();
|
||||
}
|
||||
SplashLabel * myLabel = qobject_cast<SplashLabel *>(sender());
|
||||
|
||||
void SplashLibraryDialog::onButtonPressed(int button)
|
||||
{
|
||||
splashLabel * myLabel = qobject_cast<splashLabel *>(sender());
|
||||
|
||||
foreach(splashLabel *sl, findChildren<splashLabel *>()) {
|
||||
foreach(SplashLabel *sl, findChildren<SplashLabel *>()) {
|
||||
if (sl->isEnabled()) {
|
||||
sl->setStyleSheet("border:1px solid; border-color:#999999;");
|
||||
}
|
||||
}
|
||||
|
||||
if (button == Qt::Key_Enter) {
|
||||
int id = myLabel->getId();
|
||||
splashFileName->clear();
|
||||
splashFileName->append(imageList.at(id));
|
||||
close();
|
||||
}
|
||||
|
||||
myLabel->setStyleSheet("border:1px solid; border-color:#00ffff");
|
||||
}
|
||||
|
||||
void SplashLibraryDialog::on_nextPage_clicked() {
|
||||
void SplashLibraryDialog::nextPageClicked() {
|
||||
page++;
|
||||
|
||||
if (page >= (imageList.size() / 20)) {
|
||||
ui->nextPage->setDisabled(true);
|
||||
}
|
||||
|
||||
ui->prevPage->setEnabled(true);
|
||||
setupPage(page);
|
||||
}
|
||||
|
||||
void SplashLibraryDialog::on_prevPage_clicked() {
|
||||
void SplashLibraryDialog::prevPageClicked() {
|
||||
page--;
|
||||
|
||||
if (page == 0) {
|
||||
ui->prevPage->setDisabled(true);
|
||||
}
|
||||
|
||||
if (imageList.size() > 20) {
|
||||
ui->nextPage->setEnabled(true);
|
||||
}
|
||||
@@ -19,37 +19,34 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _SPLASHLIBRARYDIALOG_H_
|
||||
#define _SPLASHLIBRARYDIALOG_H_
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets>
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class SplashLibraryDialog;
|
||||
class SplashLibraryDialog;
|
||||
}
|
||||
|
||||
class SplashLibraryDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SplashLibraryDialog(QWidget *parent = 0, QString * fileName=NULL);
|
||||
public:
|
||||
explicit SplashLibraryDialog(QWidget *parent = 0, QString *fileName = nullptr);
|
||||
~SplashLibraryDialog();
|
||||
|
||||
private slots:
|
||||
void dclose();
|
||||
void onButtonPressed(int button);
|
||||
void on_nextPage_clicked();
|
||||
void on_prevPage_clicked();
|
||||
|
||||
private:
|
||||
void getFileList();
|
||||
void setupPage(int page);
|
||||
private slots:
|
||||
void imageClicked(int button);
|
||||
void nextPageClicked();
|
||||
void prevPageClicked();
|
||||
|
||||
private:
|
||||
Ui::SplashLibraryDialog *ui;
|
||||
QString * splashFileName;
|
||||
QString *splashFileName;
|
||||
QString libraryPath;
|
||||
QStringList imageList;
|
||||
int page;
|
||||
};
|
||||
|
||||
#endif // _SPLASHLIBRARYDIALOG_H_
|
||||
void getFileList();
|
||||
void setupPage(int page);
|
||||
};
|
||||
@@ -57,10 +57,10 @@
|
||||
<item row="0" column="2">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetNoConstraint</enum>
|
||||
<enum>QLayout::SizeConstraint::SetNoConstraint</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="splashLabel" name="FwImage_01">
|
||||
<widget class="SplashLabel" name="FwImage_01">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -86,10 +86,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -106,7 +106,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="splashLabel" name="FwImage_02">
|
||||
<widget class="SplashLabel" name="FwImage_02">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -132,10 +132,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -149,7 +149,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="splashLabel" name="FwImage_04">
|
||||
<widget class="SplashLabel" name="FwImage_04">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -175,10 +175,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -192,7 +192,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="splashLabel" name="FwImage_05">
|
||||
<widget class="SplashLabel" name="FwImage_05">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -218,10 +218,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -235,7 +235,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="splashLabel" name="FwImage_06">
|
||||
<widget class="SplashLabel" name="FwImage_06">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -255,10 +255,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -272,7 +272,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="splashLabel" name="FwImage_07">
|
||||
<widget class="SplashLabel" name="FwImage_07">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -292,10 +292,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -309,7 +309,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="splashLabel" name="FwImage_08">
|
||||
<widget class="SplashLabel" name="FwImage_08">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -329,10 +329,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -346,7 +346,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="splashLabel" name="FwImage_09">
|
||||
<widget class="SplashLabel" name="FwImage_09">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -372,10 +372,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -389,7 +389,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="splashLabel" name="FwImage_10">
|
||||
<widget class="SplashLabel" name="FwImage_10">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -409,10 +409,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -426,7 +426,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="splashLabel" name="FwImage_11">
|
||||
<widget class="SplashLabel" name="FwImage_11">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -446,10 +446,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -463,7 +463,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="splashLabel" name="FwImage_12">
|
||||
<widget class="SplashLabel" name="FwImage_12">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -483,10 +483,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -500,7 +500,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="splashLabel" name="FwImage_13">
|
||||
<widget class="SplashLabel" name="FwImage_13">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -526,10 +526,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -543,7 +543,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="splashLabel" name="FwImage_14">
|
||||
<widget class="SplashLabel" name="FwImage_14">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -563,10 +563,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -580,7 +580,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="splashLabel" name="FwImage_15">
|
||||
<widget class="SplashLabel" name="FwImage_15">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -600,10 +600,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -617,7 +617,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="splashLabel" name="FwImage_16">
|
||||
<widget class="SplashLabel" name="FwImage_16">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -637,10 +637,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -654,7 +654,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="splashLabel" name="FwImage_17">
|
||||
<widget class="SplashLabel" name="FwImage_17">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -680,10 +680,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -697,7 +697,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="splashLabel" name="FwImage_18">
|
||||
<widget class="SplashLabel" name="FwImage_18">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -717,10 +717,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -734,7 +734,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="splashLabel" name="FwImage_19">
|
||||
<widget class="SplashLabel" name="FwImage_19">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -754,10 +754,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -771,7 +771,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="splashLabel" name="FwImage_20">
|
||||
<widget class="SplashLabel" name="FwImage_20">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -791,10 +791,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -808,7 +808,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="splashLabel" name="FwImage_03">
|
||||
<widget class="SplashLabel" name="FwImage_03">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -834,10 +834,10 @@
|
||||
<string notr="true">border:1px;</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
<enum>QFrame::Shape::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
@@ -889,7 +889,7 @@
|
||||
<item row="0" column="1">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
@@ -902,7 +902,7 @@
|
||||
<item row="0" column="3">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
@@ -916,13 +916,13 @@
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>splashLabel</class>
|
||||
<class>SplashLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header location="global">splashlabel.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="companion.qrc"/>
|
||||
<include location="../companion.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,339 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "flashfirmwaredialog.h"
|
||||
#include "ui_flashfirmwaredialog.h"
|
||||
#include "appdata.h"
|
||||
#include "helpers.h"
|
||||
#include "progressdialog.h"
|
||||
#include "radiointerface.h"
|
||||
#include "progresswidget.h"
|
||||
#include "splashlibrarydialog.h"
|
||||
#include "storage.h"
|
||||
|
||||
#if defined _MSC_VER || !defined __GNUC__
|
||||
#include <windows.h>
|
||||
#define sleep(x) Sleep(x*1000)
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
FlashFirmwareDialog::FlashFirmwareDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::FlashFirmwareDialog),
|
||||
fwName(g.profile[g.id()].fwName())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
if (!g.profile[g.id()].splashFile().isEmpty()){
|
||||
imageSource = PROFILE;
|
||||
imageFile = g.profile[g.id()].splashFile();
|
||||
ui->useProfileSplash->setChecked(true);
|
||||
}
|
||||
else {
|
||||
imageSource = FIRMWARE;
|
||||
imageFile = "";
|
||||
ui->useProfileSplash->setDisabled(true);
|
||||
}
|
||||
|
||||
if (IS_STM32(getCurrentBoard())) {
|
||||
// No backup on Taranis ... could be done if in massstorage
|
||||
ui->backupEEprom->hide();
|
||||
ui->backupEEprom->setCheckState(Qt::Unchecked);
|
||||
}
|
||||
else {
|
||||
ui->backupEEprom->setCheckState(g.backupOnFlash() ? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
|
||||
QString backupPath = g.profile[g.id()].pBackupDir();
|
||||
if (backupPath.isEmpty()) {
|
||||
backupPath=g.backupDir();
|
||||
}
|
||||
if (backupPath.isEmpty() || !QDir(backupPath).exists()) {
|
||||
ui->backupEEprom->setEnabled(false);
|
||||
}
|
||||
|
||||
ui->checkHardwareCompatibility->setChecked(g.checkHardwareCompatibility());
|
||||
|
||||
updateUI();
|
||||
|
||||
resize(0, 0); // TODO needed?
|
||||
}
|
||||
|
||||
FlashFirmwareDialog::~FlashFirmwareDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::updateUI()
|
||||
{
|
||||
ui->firmwareFilename->setText(fwName);
|
||||
ui->burnButton->setEnabled(QFile(fwName).exists());
|
||||
|
||||
FirmwareInterface firmware(fwName);
|
||||
if (firmware.isValid()) {
|
||||
ui->firmwareInfoFrame->show();
|
||||
ui->date->setText(firmware.getDate() + " " + firmware.getTime());
|
||||
ui->version->setText(firmware.getVersion());
|
||||
ui->variant->setText(firmware.getEEpromId());
|
||||
ui->date->setEnabled(true);
|
||||
ui->version->setEnabled(true);
|
||||
ui->variant->setEnabled(true);
|
||||
if (firmware.hasSplash()) {
|
||||
ui->splashFrame->show();
|
||||
ui->splash->setFixedSize(firmware.getSplashWidth(), firmware.getSplashHeight());
|
||||
}
|
||||
else {
|
||||
ui->splashFrame->hide();
|
||||
}
|
||||
}
|
||||
else {
|
||||
imageSource = FIRMWARE;
|
||||
ui->firmwareInfoFrame->hide();
|
||||
ui->splashFrame->hide();
|
||||
}
|
||||
|
||||
QImage image;
|
||||
switch (imageSource) {
|
||||
case FIRMWARE:
|
||||
ui->useFirmwareSplash->setChecked(true);
|
||||
image = firmware.getSplash();
|
||||
break;
|
||||
case PROFILE:
|
||||
ui->useProfileSplash->setChecked(true);
|
||||
image.load(g.profile[g.id()].splashFile());
|
||||
break;
|
||||
case LIBRARY:
|
||||
ui->useLibrarySplash->setChecked(true);
|
||||
image.load(imageFile);
|
||||
break;
|
||||
case EXTERNAL:
|
||||
ui->useExternalSplash->setChecked(true);
|
||||
image.load(imageFile);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!image.isNull()) {
|
||||
ui->splash->setPixmap(makePixMap(image));
|
||||
}
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::on_firmwareLoad_clicked()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Firmware File"), g.flashDir(), FLASH_FILES_FILTER);
|
||||
if (!fileName.isEmpty()) {
|
||||
fwName = fileName;
|
||||
if (!fwName.isEmpty() && !fwName.endsWith(".dfu") && !FirmwareInterface(fwName).isValid()) {
|
||||
QMessageBox::warning(this, CPN_STR_TTL_WARNING, tr("%1 may not be a valid firmware file").arg(fwName));
|
||||
}
|
||||
updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::on_useFirmwareSplash_clicked()
|
||||
{
|
||||
FirmwareInterface firmware(fwName);
|
||||
if (!firmware.isValid()) {
|
||||
QMessageBox::warning(this, CPN_STR_TTL_ERROR, tr( "The firmware file is not valid." ));
|
||||
}
|
||||
else if (!firmware.hasSplash()) {
|
||||
QMessageBox::warning(this, CPN_STR_TTL_ERROR, tr( "There is no start screen image in the firmware file." ));
|
||||
}
|
||||
else {
|
||||
imageSource = FIRMWARE;
|
||||
}
|
||||
updateUI();
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::on_useProfileSplash_clicked()
|
||||
{
|
||||
QString fileName = g.profile[g.id()].splashFile();
|
||||
if (!fileName.isEmpty()) {
|
||||
QImage image(fileName);
|
||||
if (image.isNull()) {
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Profile image %1 is invalid.").arg(fileName));
|
||||
}
|
||||
else {
|
||||
imageSource = PROFILE;
|
||||
}
|
||||
}
|
||||
updateUI();
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::on_useExternalSplash_clicked()
|
||||
{
|
||||
QString supportedImageFormats;
|
||||
for (int formatIndex = 0; formatIndex < QImageReader::supportedImageFormats().count(); formatIndex++) {
|
||||
supportedImageFormats += QLatin1String(" *.") + QImageReader::supportedImageFormats()[formatIndex];
|
||||
}
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open image file to use as radio start screen"), g.imagesDir(), tr("Images (%1)").arg(supportedImageFormats));
|
||||
if (!fileName.isEmpty()){
|
||||
g.imagesDir( QFileInfo(fileName).dir().absolutePath() );
|
||||
QImage image(fileName);
|
||||
if (image.isNull()) {
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("Image could not be loaded from %1").arg(fileName));
|
||||
}
|
||||
else{
|
||||
imageSource = EXTERNAL;
|
||||
imageFile = fileName;
|
||||
}
|
||||
}
|
||||
updateUI();
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::on_useLibrarySplash_clicked()
|
||||
{
|
||||
QString fileName;
|
||||
auto ld = new SplashLibraryDialog(this, &fileName);
|
||||
ld->exec();
|
||||
if (!fileName.isEmpty()) {
|
||||
QImage image(fileName);
|
||||
if (image.isNull()) {
|
||||
QMessageBox::critical(this, CPN_STR_TTL_ERROR, tr("The library image could not be loaded"));
|
||||
}
|
||||
else {
|
||||
imageSource = LIBRARY;
|
||||
imageFile = fileName;
|
||||
}
|
||||
}
|
||||
updateUI();
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::on_burnButton_clicked()
|
||||
{
|
||||
g.flashDir(QFileInfo(fwName).dir().absolutePath());
|
||||
g.profile[g.id()].fwName(fwName);
|
||||
g.checkHardwareCompatibility(ui->checkHardwareCompatibility->isChecked());
|
||||
g.backupOnFlash(ui->backupEEprom->isChecked());
|
||||
|
||||
qDebug() << "FlashFirmwareDialog: flashing" << fwName;
|
||||
|
||||
if (imageSource != FIRMWARE) {
|
||||
// load the splash image
|
||||
const QPixmap pixmap = ui->splash->pixmap(Qt::ReturnByValue);
|
||||
QImage image;
|
||||
image = pixmap.toImage().scaled(ui->splash->width(), ui->splash->height());
|
||||
if (image.isNull()) {
|
||||
QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Splash image not found"));
|
||||
return;
|
||||
}
|
||||
// write the customized firmware
|
||||
QString tempFile;
|
||||
if (getStorageType(fwName) == STORAGE_TYPE_HEX)
|
||||
tempFile = generateProcessUniqueTempFileName("flash.hex");
|
||||
else
|
||||
tempFile = generateProcessUniqueTempFileName("flash.bin");
|
||||
qDebug() << "FlashFirmwareDialog: patching" << fwName << "with custom splash screen and saving to" << tempFile;
|
||||
FirmwareInterface firmware(fwName);
|
||||
firmware.setSplash(image);
|
||||
if (firmware.save(tempFile) <= 0) {
|
||||
QMessageBox::critical(this, CPN_STR_TTL_WARNING, tr("Cannot save customized firmware"));
|
||||
return;
|
||||
}
|
||||
startFlash(tempFile);
|
||||
}
|
||||
else {
|
||||
startFlash(fwName);
|
||||
}
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::on_cancelButton_clicked()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::shrink()
|
||||
{
|
||||
resize(0, 0);
|
||||
}
|
||||
|
||||
void FlashFirmwareDialog::startFlash(const QString &filename)
|
||||
{
|
||||
// bool backup = g.backupOnFlash();
|
||||
|
||||
close();
|
||||
|
||||
ProgressDialog progressDialog(this, tr("Write Firmware to Radio"), CompanionIcon("write_flash.png"));
|
||||
|
||||
// check hardware compatibility if requested
|
||||
bool checkPassed = true;
|
||||
if (g.checkHardwareCompatibility()) {
|
||||
QString tempFirmware = generateProcessUniqueTempFileName("flash-check.bin");
|
||||
if (!readFirmware(tempFirmware, progressDialog.progress())) {
|
||||
QMessageBox::warning(this, tr("Firmware check failed"), tr("Could not check firmware from radio"));
|
||||
checkPassed = false;
|
||||
}
|
||||
FirmwareInterface previousFirmware(tempFirmware);
|
||||
qunlink(tempFirmware);
|
||||
FirmwareInterface newFirmware(filename);
|
||||
qDebug() << "startFlash: checking firmware compatibility between " << tempFirmware << "and" << filename;
|
||||
if (!newFirmware.isHardwareCompatible(previousFirmware)) {
|
||||
QMessageBox::warning(this, tr("Firmware check failed"), tr("New firmware is not compatible with the one currently installed!"));
|
||||
if (isTempFileName(filename)) {
|
||||
qDebug() << "startFlash: removing temporary file" << filename;
|
||||
qunlink(filename);
|
||||
}
|
||||
checkPassed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkPassed) {
|
||||
// backup if requested
|
||||
// bool result = true;
|
||||
// QString backupFilename;
|
||||
// QString backupPath;
|
||||
// if (backup) {
|
||||
// backupPath = g.profile[g.id()].pBackupDir();
|
||||
// if (backupPath.isEmpty()) {
|
||||
// backupPath=g.backupDir();
|
||||
// }
|
||||
// backupFilename = backupPath + "/backup-" + QDateTime().currentDateTime().toString("yyyy-MM-dd-HHmmss") + ".bin";
|
||||
// result = readSettings(backupFilename, progressDialog.progress());
|
||||
// sleep(2);
|
||||
// }
|
||||
|
||||
// flash
|
||||
//result = (result && writeFirmware(filename, progressDialog.progress()));
|
||||
writeFirmware(filename, progressDialog.progress());
|
||||
|
||||
// restore if backup requested
|
||||
// if (backup && result) {
|
||||
// sleep(2);
|
||||
// QString restoreFilename = generateProcessUniqueTempFileName("restore.bin");
|
||||
// if (!convertEEprom(backupFilename, restoreFilename, filename)) {
|
||||
// QMessageBox::warning(this, tr("Conversion failed"), tr("Cannot convert Models and Settings for use with this firmware, original data will be used"));
|
||||
// restoreFilename = backupFilename;
|
||||
// }
|
||||
// if (!writeSettings(restoreFilename, progressDialog.progress())) {
|
||||
// QMessageBox::warning(this, tr("Restore failed"), tr("Could not restore Models and Settings to Radio. The models and settings data file can be found at: %1").arg(backupFilename));
|
||||
// }
|
||||
// }
|
||||
|
||||
progressDialog.progress()->setInfo(tr("Flashing done"));
|
||||
}
|
||||
|
||||
progressDialog.exec();
|
||||
|
||||
if (isTempFileName(filename)) {
|
||||
qDebug() << "startFlash: removing temporary file" << filename;
|
||||
qunlink(filename);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "fusesdialog.h"
|
||||
#include "ui_fusesdialog.h"
|
||||
#include "helpers.h"
|
||||
#include "progressdialog.h"
|
||||
#include "radiointerface.h"
|
||||
|
||||
FusesDialog::FusesDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::FusesDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowIcon(CompanionIcon("fuses.png"));
|
||||
}
|
||||
|
||||
FusesDialog::~FusesDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void FusesDialog::on_resetFuses_EEprotect_clicked()
|
||||
{
|
||||
ProgressDialog progressDialog(this, tr("Reset Radio Fuses"), CompanionIcon("fuses.png"), true);
|
||||
return resetAvrdudeFuses(true, progressDialog.progress());
|
||||
}
|
||||
|
||||
void FusesDialog::on_resetFuses_EEdelete_clicked()
|
||||
{
|
||||
ProgressDialog progressDialog(this, tr("Reset Radio Fuses"), CompanionIcon("fuses.png"), true);
|
||||
return resetAvrdudeFuses(false, progressDialog.progress());
|
||||
}
|
||||
|
||||
void FusesDialog::on_readFuses_clicked()
|
||||
{
|
||||
ProgressDialog progressDialog(this, tr("Read Fuses from Radio"), CompanionIcon("fuses.png"), true);
|
||||
return readAvrdudeFuses(progressDialog.progress());
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _FUSESDIALOG_H_
|
||||
#define _FUSESDIALOG_H_
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class FusesDialog;
|
||||
}
|
||||
|
||||
class FusesDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FusesDialog(QWidget *parent = 0);
|
||||
~FusesDialog();
|
||||
|
||||
private slots:
|
||||
void on_readFuses_clicked();
|
||||
void on_resetFuses_EEdelete_clicked();
|
||||
void on_resetFuses_EEprotect_clicked();
|
||||
|
||||
private:
|
||||
Ui::FusesDialog *ui;
|
||||
|
||||
};
|
||||
|
||||
#endif // _FUSESDIALOG_H_
|
||||
@@ -1,118 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FusesDialog</class>
|
||||
<widget class="QDialog" name="FusesDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>374</width>
|
||||
<height>207</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Fuses</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="readFuses">
|
||||
<property name="whatsThis">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Reads the current fuses in the AVR controller.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Proper states for </span><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">AtMega 64 </span><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">:</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">EEPROM erase fuse not set: 0E, 81, FF</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">EEPROM erase fuse set: 0E, 89, FF</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Proper states for AtMega 2560 :</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">EEPROM erase fuse not set: D7, 11, FC</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">EEPROM erase fuse set: D7, 19, FC</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Read Fuses</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QPushButton" name="resetFuses_EEprotect">
|
||||
<property name="whatsThis">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:600; text-decoration: underline;">Reset Fuses</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Fuses in the AVR tell it how to behave. Pressing this button sets the fuses to the default parameters needed in the FW. These parameters are different for stock and 4.1 MB, please verify you selected the appropriate processor type in preferences.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">This button also sets the &quot;EEPROM protect&quot; Fuse.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">This prevents erasing of the EEPROM when the flash memory is written.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:600; text-decoration: underline;">WARNING</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Setting fuses can lead to problems and even a total lockout from your controller. Do this only if you know what you are doing.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">When in doubt consult either the project's page or the 9xforum (http://9xforums.com/forum/)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">If you do get locked out - google lookup for &quot;dealing with Fuse Bricks&quot;.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset Fuses
|
||||
EEPROM - PROTECT</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="resetFuses_EEdelete">
|
||||
<property name="whatsThis">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:600; text-decoration: underline;">Reset Fuses</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Fuses in the AVR tell it how to behave. Pressing this button sets the fuses to the default parameters needed in the </span><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">FW. These parameters are different for stock and 4.1 MB, please verify you selected the appropriate processor type in preferences.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">This button also clears the &quot;EEPROM protect&quot; Fuse.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">This causes erasing of the EEPROM when the flash memory is written.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:600; text-decoration: underline;">WARNING</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Setting fuses can lead to problems and even a total lockout from your controller. Do this only if you know what you are doing.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2'; font-size:8pt;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">When in doubt consult either the project's page or the 9xforum (http://9xforums.com/forum/)</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">If you do get locked out - google lookup for &quot;dealing with Fuse Bricks&quot;.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset Fuses
|
||||
EEPROM - DELETE</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;">
|
||||
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; text-decoration: underline;">WARNING</span></p>
|
||||
<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; text-decoration: underline;"></p>
|
||||
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Changing the fuses can mess up your radio.</p>
|
||||
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Proceed only if you know what you are doing.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="companion.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -232,23 +232,6 @@ static bool caseInsensitiveLessThan(const QString &s1, const QString &s2)
|
||||
return s1.toLower() < s2.toLower();
|
||||
}
|
||||
|
||||
bool displayT16ImportWarning()
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle(QObject::tr("WARNING"));
|
||||
msgBox.setText(QObject::tr("<p>Importing JumperTX data into OpenTX 2.3 is <b>not supported and dangerous.</b></p> \
|
||||
<p>It is unfortunately not possible for us to differentiate JumperTX data from legitimate FrSky X10 data, but <b>You should only continue here if the file you opened comes from a real FrSky X10.</b></p> \
|
||||
<p>Do you really want to continue?</p>"));
|
||||
msgBox.setIcon(QMessageBox::Warning);
|
||||
msgBox.addButton(QMessageBox::No);
|
||||
msgBox.addButton(QMessageBox::Yes);
|
||||
msgBox.setDefaultButton(QMessageBox::No);
|
||||
|
||||
if (msgBox.exec() == QMessageBox::No)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Helpers::populateFileComboBox(QComboBox * b, const QSet<QString> & set, const QString & current)
|
||||
{
|
||||
b->clear();
|
||||
@@ -347,6 +330,26 @@ int Helpers::getFirstPosValueIndex(QComboBox * cbo)
|
||||
return -1;
|
||||
}
|
||||
|
||||
QString Helpers::concatPath(QString & str1, QString & str2, bool onlyonesep)
|
||||
{
|
||||
return (str1 % ((!str1.endsWith("/") || !onlyonesep) ? "/" : "") % str2);
|
||||
}
|
||||
|
||||
QString Helpers::concatPath(const QString & str1, const QString & str2, bool onlyonesep)
|
||||
{
|
||||
return (str1 % ((!str1.endsWith("/") || !onlyonesep) ? "/" : "") % str2);
|
||||
}
|
||||
|
||||
QString Helpers::concatPath(const QString & str1, QString & str2, bool onlyonesep)
|
||||
{
|
||||
return (str1 % ((!str1.endsWith("/") || !onlyonesep) ? "/" : "") % str2);
|
||||
}
|
||||
|
||||
QString Helpers::concatPath(QString & str1, const QString & str2, bool onlyonesep)
|
||||
{
|
||||
return (str1 % ((!str1.endsWith("/") || !onlyonesep) ? "/" : "") % str2);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Flag when simulator is running
|
||||
static bool simulatorRunning = false;
|
||||
|
||||
@@ -56,8 +56,6 @@ extern const QColor colors[CPN_MAX_CURVES];
|
||||
#define TRIM_MODE_NONE 0x1F // 0b11111
|
||||
#define TRIM_MODE_3POS (2 * CPN_MAX_FLIGHT_MODES)
|
||||
|
||||
bool displayT16ImportWarning();
|
||||
|
||||
class CompanionIcon: public QIcon {
|
||||
public:
|
||||
CompanionIcon(const QString &baseimage);
|
||||
@@ -119,6 +117,10 @@ namespace Helpers
|
||||
unsigned int getBitmappedValue(const unsigned int & field, const unsigned int index = 0, const unsigned int numbits = 1, const unsigned int offset = 0);
|
||||
void setBitmappedValue(unsigned int & field, unsigned int value, unsigned int index = 0, unsigned int numbits = 1, unsigned int offset = 0);
|
||||
int getFirstPosValueIndex(QComboBox * cbo);
|
||||
QString concatPath(QString & str1, QString & str2, bool onlyonesep = true);
|
||||
QString concatPath(const QString & str1, const QString & str2, bool onlyonesep = true);
|
||||
QString concatPath(const QString & str1, QString & str2, bool onlyonesep = true);
|
||||
QString concatPath(QString & str1, const QString & str2, bool onlyonesep = true);
|
||||
|
||||
} // namespace Helpers
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 353 B |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 425 B |
|
Before Width: | Height: | Size: 341 B |
|
Before Width: | Height: | Size: 325 B |
|
Before Width: | Height: | Size: 603 B |
|
Before Width: | Height: | Size: 634 B |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 451 B |
|
Before Width: | Height: | Size: 764 B |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 368 B |
|
Before Width: | Height: | Size: 865 B |
|
Before Width: | Height: | Size: 725 B |
|
Before Width: | Height: | Size: 881 B |
@@ -21,7 +21,6 @@
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "mdichild.h"
|
||||
#include "burnconfigdialog.h"
|
||||
#include "comparedialog.h"
|
||||
#include "logsdialog.h"
|
||||
#include "apppreferencesdialog.h"
|
||||
@@ -34,7 +33,6 @@
|
||||
#include "warnings.h"
|
||||
#include "helpers.h"
|
||||
#include "appdata.h"
|
||||
#include "radionotfound.h"
|
||||
#include "process_sync.h"
|
||||
#include "radiointerface.h"
|
||||
#include "progressdialog.h"
|
||||
@@ -483,7 +481,7 @@ void MainWindow::sdsync(bool postUpdate)
|
||||
if (syncOpts.folderA.isEmpty())
|
||||
syncOpts.folderA = g.profile[g.id()].sdPath();
|
||||
if (syncOpts.folderB.isEmpty())
|
||||
syncOpts.folderB = findMassstoragePath("SOUNDS", true);
|
||||
syncOpts.folderB = findMassStoragePath("SOUNDS", true);
|
||||
|
||||
if (syncOpts.folderA.isEmpty())
|
||||
errorMsgs << tr("No local SD structure path configured!");
|
||||
@@ -556,11 +554,14 @@ void MainWindow::readSettings()
|
||||
bool MainWindow::readFirmwareFromRadio(const QString & filename)
|
||||
{
|
||||
ProgressDialog progressDialog(this, tr("Read Firmware from Radio"), CompanionIcon("read_flash.png"));
|
||||
bool result = readFirmware(filename, progressDialog.progress());
|
||||
if (!result && !progressDialog.isEmpty()) {
|
||||
progressDialog.open();
|
||||
|
||||
if (readFirmware(filename, progressDialog.progress())) {
|
||||
progressDialog.exec();
|
||||
return true;
|
||||
}
|
||||
return result;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MainWindow::readSettingsFromRadio(const QString & filename)
|
||||
@@ -587,40 +588,38 @@ void MainWindow::writeFlash(QString fileToFlash)
|
||||
{
|
||||
FlashFirmwareDialog * cd = new FlashFirmwareDialog(this);
|
||||
cd->exec();
|
||||
cd->deleteLater();
|
||||
}
|
||||
|
||||
void MainWindow::readBackup()
|
||||
{
|
||||
if (IS_FAMILY_HORUS_OR_T16(getCurrentBoard())) {
|
||||
QMessageBox::information(this, CPN_STR_APP_NAME, tr("This function is not yet implemented"));
|
||||
return;
|
||||
// TODO implementation
|
||||
}
|
||||
QString fileName = QFileDialog::getSaveFileName(this, tr("Save Radio Backup to File"), g.eepromDir(), EXTERNAL_EEPROM_FILES_FILTER);
|
||||
if (!fileName.isEmpty()) {
|
||||
if (!readSettingsFromRadio(fileName))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::readFlash()
|
||||
{
|
||||
QString fileName = QFileDialog::getSaveFileName(this,tr("Read Radio Firmware to File"), g.flashDir(), FLASH_FILES_FILTER);
|
||||
if (!fileName.isEmpty()) {
|
||||
readFirmwareFromRadio(fileName);
|
||||
if (!isRadioConnected()) {
|
||||
QMessageBox::critical(this, tr("Detect Radio"),
|
||||
tr("Radio could not be detected by DFU or UF2 modes") % ".\n" %
|
||||
tr("Check cable is securely connected and radio lights are illuminated") % ".\n" %
|
||||
tr("Note: USB mode is not suitable for flashing firmware."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::burnConfig()
|
||||
{
|
||||
burnConfigDialog *bcd = new burnConfigDialog(this);
|
||||
bcd->exec();
|
||||
delete bcd;
|
||||
}
|
||||
ProgressDialog progressDialog(this, tr("Read Firmware From Radio"),
|
||||
CompanionIcon("read_flash.png"));
|
||||
|
||||
void MainWindow::burnList()
|
||||
{
|
||||
burnConfigDialog bcd(this);
|
||||
auto progress = progressDialog.progress();
|
||||
|
||||
readFirmware(
|
||||
[this, progress](const QByteArray &_data) {
|
||||
writeFirmwareToFile(this, _data, progress, true);
|
||||
},
|
||||
[this](const QString &err) {
|
||||
qDebug() << tr("Could not read radio firmware: %1").arg(err);
|
||||
},
|
||||
progress);
|
||||
|
||||
progressDialog.exec();
|
||||
}
|
||||
|
||||
void MainWindow::compare()
|
||||
@@ -824,7 +823,6 @@ void MainWindow::retranslateUi(bool showMsg)
|
||||
trAct(exportAppSettingsAct, tr("Export Settings..."), tr("Save all the current %1 and Simulator settings (including radio profiles) to a file.").arg(CPN_STR_APP_NAME));
|
||||
trAct(importAppSettingsAct, tr("Import Settings..."), tr("Load %1 and Simulator settings from a prevously exported settings file.").arg(CPN_STR_APP_NAME));
|
||||
|
||||
trAct(burnConfigAct, tr("Configure Radio Communications..."), tr("Configure Companion for communicating with the Radio"));
|
||||
trAct(editSplashAct, tr("Edit Radio Splash Image..."), tr("Edit the splash image of your Radio"));
|
||||
trAct(readFlashAct, tr("Read Firmware from Radio"), tr("Read firmware from Radio"));
|
||||
trAct(writeFlashAct, tr("Write Firmware to Radio"), tr("Write firmware to Radio"));
|
||||
@@ -832,6 +830,7 @@ void MainWindow::retranslateUi(bool showMsg)
|
||||
trAct(readSettingsAct, tr("Read Models and Settings from Radio"), tr("Read Models and Settings from Radio"));
|
||||
trAct(writeBUToRadioAct, tr("Write Backup to Radio"), tr("Write Backup from file to Radio"));
|
||||
trAct(readBUToFileAct, tr("Backup Radio to File"), tr("Save a complete backup file of all settings and model data in the Radio"));
|
||||
trAct(radioGetDevicesAct, tr("Connected Radios"), tr("Get a list of connected radios"));
|
||||
|
||||
trAct(compareAct, tr("Compare Models"), tr("Compare models"));
|
||||
trAct(updatesAct, tr("Update components..."), tr("Download and update EdgeTX components and supporting resources"));
|
||||
@@ -897,7 +896,7 @@ void MainWindow::createActions()
|
||||
editAppSettingsAct = addAct("apppreferences.png", SLOT(editAppSettings()), QKeySequence::Preferences);
|
||||
exportAppSettingsAct = addAct("saveas.png", SLOT(exportAppSettings()));
|
||||
importAppSettingsAct = addAct("open.png", SLOT(importAppSettings()));
|
||||
burnConfigAct = addAct("configure.png", SLOT(burnConfig()));
|
||||
radioGetDevicesAct = addAct("configure.png", SLOT(radioGetDevices()));
|
||||
|
||||
compareAct = addAct("compare.png", SLOT(compare()), tr("Ctrl+Alt+R"));
|
||||
updatesAct = addAct("download.png", SLOT(updates()), tr("Ctrl+Alt+D"));
|
||||
@@ -910,7 +909,6 @@ void MainWindow::createActions()
|
||||
sdsyncAct = addAct("sdsync.png", SLOT(sdsync()));
|
||||
logsAct = addAct("logs.png", SLOT(logFile()), tr("Ctrl+Alt+L"));
|
||||
|
||||
burnListAct = addAct("list.png", SLOT(burnList()));
|
||||
readFlashAct = addAct("read_flash.png", SLOT(readFlash()));
|
||||
writeFlashAct = addAct("write_flash.png", SLOT(writeFlash()));
|
||||
writeSettingsAct = addAct("write_eeprom.png", SLOT(writeSettings()));
|
||||
@@ -1003,8 +1001,8 @@ void MainWindow::createMenus()
|
||||
radioMenu->addAction(writeFlashAct);
|
||||
radioMenu->addAction(readFlashAct);
|
||||
radioMenu->addSeparator();
|
||||
radioMenu->addAction(burnConfigAct);
|
||||
radioMenu->addAction(editSplashAct);
|
||||
radioMenu->addAction(radioGetDevicesAct);
|
||||
|
||||
settingsMenu = menuBar()->addMenu("");
|
||||
settingsMenu->addAction(editAppSettingsAct);
|
||||
@@ -1090,7 +1088,6 @@ void MainWindow::createToolBars()
|
||||
radioToolBar->addAction(writeFlashAct);
|
||||
radioToolBar->addAction(readFlashAct);
|
||||
radioToolBar->addSeparator();
|
||||
radioToolBar->addAction(burnConfigAct);
|
||||
|
||||
settingsToolBar = addToolBar("");
|
||||
settingsToolBar->setObjectName("Settings");
|
||||
@@ -1577,3 +1574,8 @@ void MainWindow::viewToolsToolbar()
|
||||
const QSignalBlocker blocker(toolsToolBar);
|
||||
toolsToolBar->setVisible(viewToolsToolbarAct->isChecked());
|
||||
}
|
||||
|
||||
void MainWindow::radioGetDevices()
|
||||
{
|
||||
QMessageBox::information(this, tr("Connected Radios"), getDevicesInfo());
|
||||
}
|
||||
|
||||
@@ -94,8 +94,6 @@ class MainWindow : public QMainWindow
|
||||
void readFlash();
|
||||
void writeBackup();
|
||||
void readBackup();
|
||||
void burnConfig();
|
||||
void burnList();
|
||||
void sdsync(bool postUpdate = false);
|
||||
void changelog();
|
||||
void customizeSplash();
|
||||
@@ -127,6 +125,8 @@ class MainWindow : public QMainWindow
|
||||
void viewSettingsToolbar();
|
||||
void viewToolsToolbar();
|
||||
|
||||
void radioGetDevices();
|
||||
|
||||
private:
|
||||
QAction * addAct(const QString & icon, const char * slot = NULL, const QKeySequence & shortcut = 0, QObject * slotObj = NULL, const char * signal = NULL);
|
||||
QAction * addActToGroup(QActionGroup * aGroup, const QString & sName, const QString & lName, const char * propName = 0,
|
||||
@@ -209,8 +209,7 @@ class MainWindow : public QMainWindow
|
||||
QAction *editSplashAct;
|
||||
QAction *writeSettingsAct;
|
||||
QAction *readSettingsAct;
|
||||
QAction *burnConfigAct;
|
||||
QAction *burnListAct;
|
||||
QAction *radioGetDevicesAct;
|
||||
QAction *writeFlashAct;
|
||||
QAction *readFlashAct;
|
||||
QAction *writeBUToRadioAct;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "ui_mdichild.h"
|
||||
#include "modeledit/modeledit.h"
|
||||
#include "generaledit/generaledit.h"
|
||||
#include "burnconfigdialog.h"
|
||||
#include "printdialog.h"
|
||||
#include "helpers.h"
|
||||
#include "appdata.h"
|
||||
@@ -1434,11 +1433,6 @@ bool MdiChild::convertStorage(Board::Type from, Board::Type to, bool newFile)
|
||||
QMessageBox::StandardButtons btns;
|
||||
QMessageBox::StandardButton dfltBtn;
|
||||
|
||||
if (from == Board::BOARD_X10 && to == Board::BOARD_JUMPER_T16) {
|
||||
if (displayT16ImportWarning() == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
QString q = tr("<p><b>Currently selected radio type (%1) is not compatible with file %3 (from %2), models and settings need to be converted.</b></p>").arg(Boards::getBoardName(to)).arg(Boards::getBoardName(from)).arg(userFriendlyCurrentFile());
|
||||
if (newFile) {
|
||||
q.append(tr("Do you wish to continue with the conversion?"));
|
||||
@@ -1526,7 +1520,7 @@ void MdiChild::writeSettings(StatusDialog * status, bool toRadio) // write to T
|
||||
QString radioPath;
|
||||
|
||||
if (toRadio) {
|
||||
radioPath = findMassstoragePath("RADIO", true);
|
||||
radioPath = findMassStoragePath("RADIO", true);
|
||||
qDebug() << "Searching for SD card, found" << radioPath;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -1,336 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "process_flash.h"
|
||||
#include "progresswidget.h"
|
||||
#include "eeprominterface.h"
|
||||
#include <QFile>
|
||||
#include <QMessageBox>
|
||||
#include <QProcess>
|
||||
#include <QTimer>
|
||||
#include <QEventLoop>
|
||||
|
||||
#if defined _MSC_VER || !defined __GNUC__
|
||||
#include <Windows.h>
|
||||
#include <WinBase.h>
|
||||
#include <tlhelp32.h>
|
||||
#define sleep(x) Sleep(x*1000)
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
FlashProcess::FlashProcess(const QString & cmd, const QStringList & args, ProgressWidget * progress):
|
||||
progress(progress),
|
||||
cmd(cmd),
|
||||
args(args),
|
||||
process(new QProcess(this)),
|
||||
hasErrors(false),
|
||||
lfuse(0),
|
||||
hfuse(0),
|
||||
efuse(0),
|
||||
flashPhase(READING)
|
||||
#if !__GNUC__
|
||||
, killTimer(nullptr)
|
||||
#endif
|
||||
{
|
||||
connect(process, SIGNAL(started()),this, SLOT(onStarted()));
|
||||
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadyReadStandardOutput()));
|
||||
connect(process, SIGNAL(readyReadStandardError()), this, SLOT(onReadyReadStandardError()));
|
||||
connect(process, SIGNAL(finished(int)), this, SLOT(onFinished(int)));
|
||||
}
|
||||
|
||||
FlashProcess::~FlashProcess()
|
||||
{
|
||||
#if !__GNUC__
|
||||
delete killTimer;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FlashProcess::run()
|
||||
{
|
||||
if (!QFile::exists(cmd)) {
|
||||
QMessageBox::critical(nullptr, CPN_STR_APP_NAME, tr("Executable %1 not found").arg(cmd));
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !__GNUC__
|
||||
if (cmd.toLower().contains("sam-ba")) {
|
||||
killTimer = new QTimer(this);
|
||||
connect(killTimer, SIGNAL(timeout()), this, SLOT(onKillTimerElapsed()));
|
||||
killTimer->start(2000);
|
||||
}
|
||||
#endif
|
||||
|
||||
QEventLoop loop;
|
||||
connect(this, SIGNAL(finished()), &loop, SLOT(quit()));
|
||||
process->start(cmd, args);
|
||||
loop.exec();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FlashProcess::onStarted()
|
||||
{
|
||||
progress->lock(true);
|
||||
progress->addText(cmd + " " + args.join(" "));
|
||||
progress->addSeparator();
|
||||
}
|
||||
|
||||
#if !__GNUC__
|
||||
bool killProcessByName(const char *szProcessToKill)
|
||||
{
|
||||
QString processToKill{szProcessToKill};
|
||||
HANDLE hProcessSnap;
|
||||
HANDLE hProcess;
|
||||
PROCESSENTRY32 pe32;
|
||||
|
||||
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // Takes a snapshot of all the processes
|
||||
|
||||
if (hProcessSnap == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pe32.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
if (!Process32First(hProcessSnap, &pe32)) {
|
||||
CloseHandle(hProcessSnap);
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
QString exeFile{pe32.szExeFile};
|
||||
|
||||
if (exeFile == processToKill) { // checks if process at current position has the name of to be killed app
|
||||
hProcess = OpenProcess(PROCESS_TERMINATE,0, pe32.th32ProcessID); // gets handle to process
|
||||
TerminateProcess(hProcess, 0); // Terminate process by handle
|
||||
CloseHandle(hProcess); // close the handle
|
||||
}
|
||||
} while (Process32Next(hProcessSnap, &pe32)); // gets next member of snapshot
|
||||
|
||||
CloseHandle(hProcessSnap); // closes the snapshot handle
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void FlashProcess::onKillTimerElapsed()
|
||||
{
|
||||
#if !__GNUC__
|
||||
// trick to accelerate SAM-BA startup
|
||||
killProcessByName("tasklist.exe");
|
||||
#endif
|
||||
}
|
||||
|
||||
void FlashProcess::analyseStandardOutput(const QString & text)
|
||||
{
|
||||
currStdoutLine.append(text);
|
||||
|
||||
if (currStdoutLine.contains("size = ")) {
|
||||
int pos = currStdoutLine.lastIndexOf("size = ");
|
||||
QString temp = currStdoutLine.mid(pos+7);
|
||||
pos = temp.lastIndexOf("\n");
|
||||
int size = temp.left(pos).toInt();
|
||||
progress->setMaximum(size / 2048);
|
||||
}
|
||||
|
||||
if (currStdoutLine.contains("\n")) {
|
||||
int nlPos = currStdoutLine.lastIndexOf("\n");
|
||||
currStdoutLine = currStdoutLine.mid(nlPos+1);
|
||||
}
|
||||
|
||||
if (!currStdoutLine.isEmpty()) {
|
||||
if (currStdoutLine.at(0) == QChar('.')) {
|
||||
int pos = currStdoutLine.lastIndexOf(".");
|
||||
progress->setValue(pos);
|
||||
}
|
||||
else if (currStdoutLine.startsWith("Starting upload: [")) {
|
||||
int pos = (currStdoutLine.lastIndexOf("#") - 19) * 100 / 256;
|
||||
progress->setValue(pos);
|
||||
}
|
||||
}
|
||||
|
||||
if (text.contains("Complete ")) {
|
||||
#if !__GNUC__
|
||||
delete killTimer;
|
||||
killTimer = nullptr;
|
||||
#endif
|
||||
int start = text.indexOf("Complete ");
|
||||
int end = text.indexOf("%");
|
||||
if (start > 0) {
|
||||
start += 9;
|
||||
int value = text.mid(start, end - start).toInt();
|
||||
progress->setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (text.contains("Upload\t[") || text.contains("Download\t[")) {
|
||||
int end = text.indexOf("%");
|
||||
if (end > 0) {
|
||||
int value = text.mid(end - 3, 3).toInt();
|
||||
progress->setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (text.contains(":010000")) {
|
||||
// contains fuse info
|
||||
QStringList stl = text.split(":01000000");
|
||||
foreach (QString t, stl) {
|
||||
bool ok = false;
|
||||
if (!lfuse) lfuse = t.left(2).toInt(&ok, 16);
|
||||
if (!hfuse && !ok) hfuse = t.left(2).toInt(&ok, 16);
|
||||
if (!efuse && !ok) efuse = t.left(2).toInt(&ok, 16);
|
||||
}
|
||||
}
|
||||
|
||||
if (text.contains("-E-")) {
|
||||
hasErrors = true;
|
||||
}
|
||||
|
||||
if (text.contains("Cannot open device")) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
void FlashProcess::analyseStandardError(const QString &text)
|
||||
{
|
||||
currStderrLine.append(text);
|
||||
if (currStderrLine.contains("#")) {
|
||||
QString avrflashPhase = currStderrLine.left(1).toLower();
|
||||
if (avrflashPhase == "w") {
|
||||
flashPhase = WRITING;
|
||||
progress->setInfo(tr("Writing..."));
|
||||
progress->setValue(2 * currStderrLine.count("#"));
|
||||
}
|
||||
else if (avrflashPhase == "r") {
|
||||
if (flashPhase == READING) {
|
||||
progress->setInfo(tr("Reading..."));
|
||||
}
|
||||
else {
|
||||
flashPhase = VERIFYING;
|
||||
progress->setInfo(tr("Verifying..."));
|
||||
}
|
||||
progress->setValue(2 * currStderrLine.count("#"));
|
||||
}
|
||||
}
|
||||
|
||||
if (currStderrLine.contains("\n")) {
|
||||
int nlPos = currStderrLine.lastIndexOf("\n");
|
||||
currStderrLine = currStderrLine.mid(nlPos+1);
|
||||
}
|
||||
|
||||
if ((text.contains("-E-") && !text.contains("-E- No receive file name")) ||
|
||||
text.contains("No DFU capable USB device found")) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
void FlashProcess::onReadyReadStandardOutput()
|
||||
{
|
||||
QString text = QString(process->readAllStandardOutput());
|
||||
progress->addText(text);
|
||||
analyseStandardOutput(text);
|
||||
}
|
||||
|
||||
void FlashProcess::onReadyReadStandardError()
|
||||
{
|
||||
QString text = QString(process->readAllStandardError());
|
||||
progress->addText(text);
|
||||
analyseStandardError(text);
|
||||
}
|
||||
|
||||
void FlashProcess::errorWizard()
|
||||
{
|
||||
QString output = progress->getText();
|
||||
|
||||
if (output.contains("avrdude: Expected signature for")) { // wrong signature
|
||||
int pos = output.indexOf("avrdude: Device signature = ");
|
||||
bool fwexist = false;
|
||||
QString DeviceStr = tr("unknown");
|
||||
QString FwStr = "";
|
||||
|
||||
if (pos > 0) {
|
||||
QString DeviceId = output.mid(pos+28, 8);
|
||||
if (DeviceId=="0x1e9602") {
|
||||
DeviceStr = "Atmega 64";
|
||||
FwStr="\n" + tr("ie: OpenTX for 9X board or OpenTX for 9XR board");
|
||||
fwexist = true;
|
||||
}
|
||||
else if (DeviceId=="0x1e9702") {
|
||||
DeviceStr = "Atmega 128";
|
||||
FwStr="\n" + tr("ie: OpenTX for M128 / 9X board or OpenTX for 9XR board with M128 chip");
|
||||
fwexist = true;
|
||||
}
|
||||
else if (DeviceId=="0x1e9703") {
|
||||
DeviceStr = "Atmega 1280";
|
||||
}
|
||||
else if (DeviceId=="0x1e9704") {
|
||||
DeviceStr = "Atmega 1281";
|
||||
}
|
||||
else if (DeviceId=="0x1e9801") {
|
||||
DeviceStr = "Atmega 2560";
|
||||
FwStr="\n" + tr("ie: OpenTX for Gruvin9X board");
|
||||
fwexist = true;
|
||||
}
|
||||
else if (DeviceId=="0x1e9802") {
|
||||
DeviceStr = "Atmega 2561";
|
||||
}
|
||||
}
|
||||
if (!fwexist) {
|
||||
QMessageBox::warning(nullptr, "Companion - Tip of the day", tr("Your radio uses a %1 CPU!!!\n\nPlease check advanced burn options to set the correct cpu type.").arg(DeviceStr));
|
||||
}
|
||||
else {
|
||||
Firmware *firmware = getCurrentFirmware();
|
||||
QMessageBox::warning(nullptr, "Companion - Tip of the day", tr("Your radio uses a %1 CPU!!!\n\nPlease select an appropriate firmware type to program it.").arg(DeviceStr)+FwStr+tr("\nYou are currently using:\n %1").arg(firmware->getName()));
|
||||
}
|
||||
}
|
||||
else if (output.contains("No DFU capable USB device found")){
|
||||
QMessageBox::warning(nullptr, "Companion - Tip of the day", tr("Your radio does not seem connected to USB or the driver is not initialized!!!."));
|
||||
}
|
||||
}
|
||||
|
||||
void FlashProcess::onFinished(int code=0)
|
||||
{
|
||||
progress->addSeparator();
|
||||
if (code==1 && cmd.toLower().contains("sam-ba")) {
|
||||
code = 0;
|
||||
}
|
||||
if (code) {
|
||||
progress->setInfo(tr("Flashing done (exit code = %1)").arg(code));
|
||||
if (cmd.toLower().contains("avrdude") || cmd.toLower().contains("dfu")) {
|
||||
errorWizard();
|
||||
}
|
||||
}
|
||||
else if (hasErrors) {
|
||||
progress->setInfo(tr("Flashing done with errors"));
|
||||
}
|
||||
if (lfuse || hfuse || efuse) {
|
||||
addReadFuses();
|
||||
}
|
||||
progress->setValue(progress->maximum());
|
||||
progress->lock(false);
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void FlashProcess::addReadFuses()
|
||||
{
|
||||
progress->addSeparator();
|
||||
progress->addText(tr("FUSES: Low=%1 High=%2 Ext=%3").arg(lfuse, 2, 16, QChar('0')).arg(hfuse, 2, 16, QChar('0')).arg(efuse, 2, 16, QChar('0')));
|
||||
progress->addSeparator();
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _PROCESS_FLASH_H_
|
||||
#define _PROCESS_FLASH_H_
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class ProgressWidget;
|
||||
class QProcess;
|
||||
class QTimer;
|
||||
|
||||
class FlashProcess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FlashProcess(const QString &cmd, const QStringList &args, ProgressWidget *progress);
|
||||
~FlashProcess();
|
||||
bool run();
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
protected slots:
|
||||
void onStarted();
|
||||
void onReadyReadStandardOutput();
|
||||
void onReadyReadStandardError();
|
||||
void onFinished(int);
|
||||
void onKillTimerElapsed();
|
||||
|
||||
protected:
|
||||
void analyseStandardOutput(const QString &text);
|
||||
void analyseStandardError(const QString &text);
|
||||
void errorWizard();
|
||||
void addReadFuses();
|
||||
ProgressWidget * progress;
|
||||
const QString cmd;
|
||||
const QStringList args;
|
||||
QProcess * process;
|
||||
bool hasErrors;
|
||||
QString currStdoutLine;
|
||||
QString currStderrLine;
|
||||
unsigned int lfuse;
|
||||
unsigned int hfuse;
|
||||
unsigned int efuse;
|
||||
enum FlashPhase { READING, WRITING, VERIFYING };
|
||||
FlashPhase flashPhase;
|
||||
#if !__GNUC__
|
||||
QTimer *killTimer;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // _PROCESS_FLASH_H_
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
project(progress)
|
||||
|
||||
set(${PROJECT_NAME}_NAMES
|
||||
progressdialog
|
||||
progresswidget
|
||||
)
|
||||
|
||||
AddHeadersSources()
|
||||
|
||||
qt_wrap_cpp(${PROJECT_NAME}_SRCS
|
||||
)
|
||||
|
||||
add_library(${PROJECT_NAME}
|
||||
${${PROJECT_NAME}_HDRS}
|
||||
${${PROJECT_NAME}_SRCS}
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${CPN_COMMON_LIB}
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
"${CMAKE_SOURCE_DIR}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
PUBLIC
|
||||
"${CMAKE_CURRENT_LIST_DIR}"
|
||||
)
|
||||
@@ -26,10 +26,10 @@
|
||||
#include <QTimer>
|
||||
|
||||
ProgressDialog::ProgressDialog(QWidget *parent, const QString &title, const QIcon &icon, bool forceOpen):
|
||||
QDialog(parent),
|
||||
ui(new Ui::ProgressDialog),
|
||||
locked(false),
|
||||
keepOpen(false)
|
||||
QDialog(parent),
|
||||
ui(new Ui::ProgressDialog),
|
||||
locked(false),
|
||||
keepOpen(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(title);
|
||||
@@ -39,6 +39,7 @@ keepOpen(false)
|
||||
ui->outputProgress->forceOpen();
|
||||
}
|
||||
resize(0, 0);
|
||||
connect(ui->outputProgress, &ProgressWidget::locked, this, &ProgressDialog::on_outputProgress_locked);
|
||||
show();
|
||||
}
|
||||
|
||||
@@ -64,7 +65,7 @@ void ProgressDialog::on_closeButton_clicked()
|
||||
|
||||
void ProgressDialog::on_outputProgress_detailsToggled()
|
||||
{
|
||||
QTimer::singleShot(0, this, SLOT(shrink()));
|
||||
QTimer::singleShot(0, [=]() { adjustSize(); });
|
||||
}
|
||||
|
||||
void ProgressDialog::on_outputProgress_locked(bool lock)
|
||||
@@ -73,11 +74,6 @@ void ProgressDialog::on_outputProgress_locked(bool lock)
|
||||
locked = lock;
|
||||
}
|
||||
|
||||
void ProgressDialog::shrink()
|
||||
{
|
||||
resize(0, 0);
|
||||
}
|
||||
|
||||
bool ProgressDialog::isEmpty() const
|
||||
{
|
||||
return ui->outputProgress->isEmpty();
|
||||
@@ -50,7 +50,6 @@ class ProgressDialog : public QDialog
|
||||
void on_outputProgress_detailsToggled();
|
||||
void on_outputProgress_locked(bool);
|
||||
void on_outputProgress_keepOpen(bool);
|
||||
void shrink();
|
||||
|
||||
private:
|
||||
Ui::ProgressDialog *ui;
|
||||
@@ -52,7 +52,6 @@ ProgressWidget::ProgressWidget(QWidget *parent) :
|
||||
newFont.setPointSize(9);
|
||||
#endif
|
||||
ui->textEdit->setFont(newFont);
|
||||
|
||||
}
|
||||
|
||||
ProgressWidget::~ProgressWidget()
|
||||
@@ -1,326 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "radiointerface.h"
|
||||
#include "appdata.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "process_flash.h"
|
||||
#include "radionotfound.h"
|
||||
#include "burnconfigdialog.h"
|
||||
#include "helpers.h"
|
||||
#include "process_copy.h"
|
||||
#include "storage.h"
|
||||
#include "progresswidget.h"
|
||||
|
||||
QString getRadioInterfaceCmd()
|
||||
{
|
||||
burnConfigDialog bcd;
|
||||
Board::Type board = getCurrentBoard();
|
||||
if (IS_STM32(board)) {
|
||||
return bcd.getDFU();
|
||||
}
|
||||
else
|
||||
return bcd.getSAMBA();
|
||||
}
|
||||
|
||||
QStringList getDfuArgs(const QString & cmd, const QString & filename)
|
||||
{
|
||||
QStringList args;
|
||||
burnConfigDialog bcd;
|
||||
args << bcd.getDFUArgs();
|
||||
if (!filename.endsWith(".dfu"))
|
||||
args << "--dfuse-address" << "0x08000000";
|
||||
if (cmd == "-U")
|
||||
args.last().append(":" % QString::number(Boards::getFlashSize(getCurrentBoard())));
|
||||
args << "--device" << "0483:df11";
|
||||
args << cmd % filename;
|
||||
return args;
|
||||
}
|
||||
|
||||
QStringList getSambaArgs(const QString & tcl)
|
||||
{
|
||||
QStringList result;
|
||||
|
||||
QString tclFilename = generateProcessUniqueTempFileName("temp.tcl");
|
||||
if (QFile::exists(tclFilename)) {
|
||||
qunlink(tclFilename);
|
||||
}
|
||||
QFile tclFile(tclFilename);
|
||||
if (!tclFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QMessageBox::warning(NULL, CPN_STR_TTL_ERROR,
|
||||
QCoreApplication::translate("RadioInterface", "Cannot write file %1:\n%2.").arg(tclFilename).arg(tclFile.errorString()));
|
||||
return result;
|
||||
}
|
||||
|
||||
QTextStream outputStream(&tclFile);
|
||||
outputStream << tcl;
|
||||
|
||||
burnConfigDialog bcd;
|
||||
result << bcd.getSambaPort() << bcd.getArmMCU() << tclFilename ;
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList getReadEEpromCmd(const QString & filename)
|
||||
{
|
||||
QStringList result;
|
||||
if (!IS_STM32(getCurrentBoard())) {
|
||||
result = getSambaArgs(QString("SERIALFLASH::Init 0\n") + "receive_file {SerialFlash AT25} \"" + filename + "\" 0x0 0x80000 0\n");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList getWriteEEpromCmd(const QString & filename)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
if (IS_STM32(board)) {
|
||||
// impossible
|
||||
return QStringList();
|
||||
}
|
||||
else {
|
||||
return getSambaArgs(QString("SERIALFLASH::Init 0\n") + "send_file {SerialFlash AT25} \"" + filename + "\" 0x0 0\n");
|
||||
}
|
||||
}
|
||||
|
||||
QStringList getWriteFirmwareArgs(const QString & filename)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
if (IS_STM32(board)) {
|
||||
return getDfuArgs("-D", filename);
|
||||
}
|
||||
else {
|
||||
return getSambaArgs(QString("send_file {Flash} \"") + filename + "\" 0x400000 0\n" + "FLASH::ScriptGPNMV 2\n");
|
||||
}
|
||||
}
|
||||
|
||||
QStringList getReadFirmwareArgs(const QString & filename)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
if (IS_STM32(board)) {
|
||||
return getDfuArgs("-U", filename);
|
||||
}
|
||||
else {
|
||||
return getSambaArgs(QString("receive_file {Flash} \"") + filename + "\" 0x400000 0x80000 0\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool readFirmware(const QString & filename, ProgressWidget * progress)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
QFile file(filename);
|
||||
if (file.exists() && !file.remove()) {
|
||||
QMessageBox::warning(NULL, CPN_STR_TTL_ERROR,
|
||||
QCoreApplication::translate("RadioInterface", "Could not delete temporary file: %1").arg(filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
QString path = findMassstoragePath("FIRMWARE.BIN");
|
||||
if (!path.isEmpty()) {
|
||||
qDebug() << "readFirmware: reading" << path << "into" << filename;
|
||||
CopyProcess copyProcess(path, filename, progress);
|
||||
result = copyProcess.run();
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
qDebug() << "readFirmware: reading" << filename << "with" << getRadioInterfaceCmd() << getReadFirmwareArgs(filename);
|
||||
FlashProcess flashProcess(getRadioInterfaceCmd(), getReadFirmwareArgs(filename), progress);
|
||||
result = flashProcess.run();
|
||||
}
|
||||
|
||||
if (!QFileInfo(filename).exists()) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool writeFirmware(const QString & filename, ProgressWidget * progress)
|
||||
{
|
||||
QString path = findMassstoragePath("FIRMWARE.BIN");
|
||||
if (!path.isEmpty()) {
|
||||
qDebug() << "writeFirmware: writing" << path << "from" << filename;
|
||||
CopyProcess copyProcess(filename, path, progress);
|
||||
return copyProcess.run();
|
||||
}
|
||||
|
||||
qDebug() << "writeFirmware: writing" << filename << "with" << getRadioInterfaceCmd() << getWriteFirmwareArgs(filename);
|
||||
FlashProcess flashProcess(getRadioInterfaceCmd(), getWriteFirmwareArgs(filename), progress);
|
||||
return flashProcess.run();
|
||||
}
|
||||
|
||||
bool readSettings(const QString & filename, ProgressWidget * progress)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
|
||||
QFile file(filename);
|
||||
if (file.exists() && !file.remove()) {
|
||||
QMessageBox::warning(NULL, CPN_STR_TTL_ERROR,
|
||||
QCoreApplication::translate("RadioInterface", "Could not delete temporary file: %1").arg(filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Boards::getCapability(board, Board::HasSDCard))
|
||||
return readSettingsSDCard(filename, progress);
|
||||
else
|
||||
return readSettingsEeprom(filename, progress);
|
||||
}
|
||||
|
||||
bool readSettingsSDCard(const QString & filename, ProgressWidget * progress, bool fromRadio)
|
||||
{
|
||||
QString radioPath;
|
||||
|
||||
if (fromRadio) {
|
||||
radioPath = findMassstoragePath("RADIO", true, progress);
|
||||
qDebug() << "Searching for SD card, found" << radioPath;
|
||||
}
|
||||
else {
|
||||
radioPath = g.currentProfile().sdPath();
|
||||
if (!QFile::exists(radioPath % "/RADIO"))
|
||||
radioPath.clear();
|
||||
}
|
||||
|
||||
if (radioPath.isEmpty()) {
|
||||
QMessageBox::critical(progress, CPN_STR_TTL_ERROR,
|
||||
QCoreApplication::translate("RadioInterface", "Unable to find SD card!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
RadioData radioData;
|
||||
Storage inputStorage(radioPath);
|
||||
if (!inputStorage.load(radioData)) {
|
||||
QString errorMsg = inputStorage.error();
|
||||
if (errorMsg.isEmpty()) {
|
||||
errorMsg = QCoreApplication::translate("RadioInterface", "Failed to read Models and Settings from") % radioPath;
|
||||
}
|
||||
QMessageBox::critical(progress, CPN_STR_TTL_ERROR, errorMsg);
|
||||
return false;
|
||||
}
|
||||
Storage outputStorage(filename);
|
||||
if (!outputStorage.write(radioData)) {
|
||||
QMessageBox::critical(progress, CPN_STR_TTL_ERROR, QCoreApplication::translate("RadioInterface", "Failed to write Models and Setting file") % " " % filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getCurrentBoard() == Board::BOARD_JUMPER_T16 && inputStorage.getBoard() == Board::BOARD_X10) {
|
||||
if (displayT16ImportWarning() == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return QFileInfo(filename).exists();
|
||||
}
|
||||
|
||||
|
||||
bool readSettingsEeprom(const QString & filename, ProgressWidget * progress)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
|
||||
QString path = findMassstoragePath("EEPROM.BIN");
|
||||
if (path.isEmpty()) {
|
||||
// On previous OpenTX we called the EEPROM file "TARANIS.BIN" :(
|
||||
path = findMassstoragePath("TARANIS.BIN");
|
||||
}
|
||||
if (path.isEmpty()) {
|
||||
// Mike's bootloader calls the EEPROM file "ERSKY9X.BIN" :(
|
||||
path = findMassstoragePath("ERSKY9X.BIN");
|
||||
}
|
||||
if (path.isEmpty()) {
|
||||
RadioNotFoundDialog dialog(progress);
|
||||
dialog.exec();
|
||||
return false;
|
||||
}
|
||||
CopyProcess copyProcess(path, filename, progress);
|
||||
if (!copyProcess.run()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!IS_STM32(board)) {
|
||||
FlashProcess flashProcess(getRadioInterfaceCmd(), getReadEEpromCmd(filename), progress);
|
||||
if (!flashProcess.run()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return QFileInfo(filename).exists();
|
||||
}
|
||||
|
||||
bool writeSettings(const QString & filename, ProgressWidget * progress)
|
||||
{
|
||||
Board::Type board = getCurrentBoard();
|
||||
|
||||
QString path = findMassstoragePath("EEPROM.BIN");
|
||||
if (path.isEmpty()) {
|
||||
// On previous OpenTX we called the EEPROM file "TARANIS.BIN" :(
|
||||
path = findMassstoragePath("TARANIS.BIN");
|
||||
}
|
||||
if (path.isEmpty()) {
|
||||
// Mike's bootloader calls the EEPROM file "ERSKY9X.BIN" :(
|
||||
path = findMassstoragePath("ERSKY9X.BIN");
|
||||
}
|
||||
if (!path.isEmpty()) {
|
||||
CopyProcess copyProcess(filename, path, progress);
|
||||
return copyProcess.run();
|
||||
}
|
||||
|
||||
if (!IS_TARANIS(board)) {
|
||||
FlashProcess flashProcess(getRadioInterfaceCmd(), getWriteEEpromCmd(filename), progress);
|
||||
return flashProcess.run();
|
||||
}
|
||||
|
||||
RadioNotFoundDialog dialog(progress);
|
||||
dialog.exec();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QString findMassstoragePath(const QString & filename, bool onlyPath, ProgressWidget *progress)
|
||||
{
|
||||
QString foundPath;
|
||||
QString foundProbefile;
|
||||
int found = 0;
|
||||
|
||||
QRegularExpression fstypeRe("^(v?fat|msdos|lifs)", QRegularExpression::CaseInsensitiveOption); // Linux: "vfat"; macOS: "msdos" or "lifs"; Win: "FAT32"
|
||||
|
||||
foreach(const QStorageInfo & si, QStorageInfo::mountedVolumes()) {
|
||||
//qDebug() << si.rootPath() << si.name() << si.device() << si.displayName() << si.fileSystemType() << si.isReady() << si.bytesTotal() << si.blockSize();
|
||||
if (!si.isReady() || si.isReadOnly() || !QString(si.fileSystemType()).contains(fstypeRe))
|
||||
continue;
|
||||
|
||||
QString temppath = si.rootPath();
|
||||
QString probefile = temppath % "/" % filename;
|
||||
qDebug() << "Searching for" << probefile;
|
||||
|
||||
if (QFile::exists(probefile)) {
|
||||
found++;
|
||||
foundPath = temppath;
|
||||
foundProbefile = probefile;
|
||||
qDebug() << probefile << "found";
|
||||
}
|
||||
}
|
||||
|
||||
if (found == 1)
|
||||
return onlyPath ? foundPath : foundProbefile;
|
||||
else if (found > 1) {
|
||||
QMessageBox::critical(progress, CPN_STR_TTL_ERROR, filename % " " % QCoreApplication::translate("RadioInterface", "found in multiple locations"));
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class ProgressWidget;
|
||||
|
||||
QString getRadioInterfaceCmd();
|
||||
|
||||
QString findMassstoragePath(const QString &filename, bool onlyPath = false, ProgressWidget *progress = nullptr);
|
||||
|
||||
QStringList getSambaArgs(const QString &tcl);
|
||||
QStringList getDfuArgs(const QString &cmd, const QString &filename);
|
||||
|
||||
QStringList getReadEEpromCmd(const QString &filename);
|
||||
QStringList getWriteEEpromCmd(const QString &filename);
|
||||
QStringList getReadFirmwareArgs(const QString &filename);
|
||||
QStringList getWriteFirmwareArgs(const QString &filename);
|
||||
|
||||
bool readFirmware(const QString &filename, ProgressWidget *progress);
|
||||
bool writeFirmware(const QString &filename, ProgressWidget *progress);
|
||||
bool readSettings(const QString &filename, ProgressWidget *progress);
|
||||
bool readSettingsSDCard(const QString &filename, ProgressWidget *progress, bool fromRadio = true);
|
||||
bool readSettingsEeprom(const QString &filename, ProgressWidget *progress);
|
||||
bool writeSettings(const QString &filename, ProgressWidget *progress);
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "radionotfound.h"
|
||||
#include "ui_radionotfound.h"
|
||||
|
||||
RadioNotFoundDialog::RadioNotFoundDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::RadioNotFoundDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
RadioNotFoundDialog::~RadioNotFoundDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void RadioNotFoundDialog::on_OK_clicked()
|
||||
{
|
||||
accept();
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _RADIONOTFOUND_H_
|
||||
#define _RADIONOTFOUND_H_
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class RadioNotFoundDialog;
|
||||
}
|
||||
|
||||
class RadioNotFoundDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RadioNotFoundDialog(QWidget *parent = 0);
|
||||
~RadioNotFoundDialog();
|
||||
private:
|
||||
Ui::RadioNotFoundDialog *ui;
|
||||
private slots:
|
||||
void on_OK_clicked();
|
||||
};
|
||||
|
||||
#endif // _RADIONOTFOUND_H_
|
||||
@@ -1,117 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>RadioNotFoundDialog</class>
|
||||
<widget class="QDialog" name="RadioNotFoundDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>367</width>
|
||||
<height>350</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>367</width>
|
||||
<height>350</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>367</width>
|
||||
<height>350</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>No Radio Found</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>No Radio was found!</p><p>Make sure that you hold the lower trim buttons towards the center while you turn it on.</p><p>Then connect the USB wire.</p><p><span style=" font-family:'arial,sans-serif'; font-size:13px; font-style:italic; color:#222222; background-color:#ffffff;">Note: if you have a Taranis that has not had the firmware upgraded to 2.0 then this version of Companion will not work.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Box</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="companion.qrc">:/images/taranison.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="OK">
|
||||
<property name="text">
|
||||
<string>OK</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="companion.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
const unsigned char gr9x_splash[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x08, 0x04, 0x04, 0x84, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x04, 0x04, 0x88, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0xfc, 0x04, 0x04, 0x00, 0xe0, 0x50, 0x50, 0x60, 0x00, 0xfe, 0x00, 0xe0, 0x50, 0x50, 0x60, 0x00, 0xf0, 0x10, 0x10, 0xe0, 0x10, 0x10, 0xe0, 0x00, 0xe0, 0x50, 0x50, 0x60, 0x00, 0xfc, 0x10, 0x00, 0xf0, 0x20, 0x10, 0x00, 0x10, 0xe0, 0x00, 0xe0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x24, 0xc4, 0x00, 0xe0, 0x50, 0x50, 0x60, 0x00, 0xf0, 0x20, 0x10, 0x00, 0xf4, 0x00, 0xe0, 0x50, 0x50, 0x60, 0x00, 0x30, 0x50, 0x90, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xbf, 0x80, 0x80, 0x80, 0xbf, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x30, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x88, 0x09, 0x09, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x81, 0xf0, 0x18, 0x19, 0xf0, 0x80, 0x01, 0x00, 0x00, 0x01, 0x01, 0x21, 0x20, 0x20, 0x21, 0x20, 0x21, 0x20, 0x20, 0x20, 0x20, 0x24, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0xe1, 0x21, 0x21, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x20, 0x21, 0x20, 0x20, 0x20, 0x21, 0x20, 0x20, 0x21, 0x21, 0x21, 0x20, 0x81, 0xc1, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xf8, 0xfe, 0xff, 0xff, 0xff, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x37, 0x47, 0x87, 0x87, 0x87, 0x97, 0x97, 0x07, 0x5f, 0xdf, 0xdf, 0xdf, 0xde, 0xd8, 0x80, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0f, 0x00, 0x80, 0x40, 0x3f, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x58, 0x48, 0x4c, 0x4c, 0x47, 0x47, 0x44, 0x46, 0x42, 0x43, 0xff, 0x00, 0x00, 0xff, 0x43, 0x42, 0x46, 0x44, 0x47, 0x47, 0x4c, 0x4c, 0x48, 0x58, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xb0, 0x18, 0x0c, 0x04, 0x06, 0x87, 0x8f, 0xbf, 0xee, 0xfe, 0xf6, 0x7e, 0x3c, 0x1c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x1f, 0x39, 0x60, 0x80, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x8e, 0xce, 0xee, 0xfc, 0xf9, 0x73, 0x27, 0x0f, 0x1f, 0x3f, 0x7e, 0xfc, 0xf9, 0xf1, 0xf1, 0xf9, 0xfc, 0x3e, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x7f, 0x00, 0x00, 0x7f, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0x40, 0xc0, 0xc0, 0x80, 0x88, 0x10, 0x10, 0x1d, 0x17, 0x11, 0x11, 0x13, 0x13, 0x13, 0x13, 0x11, 0x17, 0x1d, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0f, 0x07, 0x07, 0x03, 0x03, 0x01, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0x7c, 0x3e, 0x1f, 0x0f, 0x07, 0x07, 0x0f, 0x1f, 0x3f, 0x7e, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x20, 0xe0, 0x20, 0x20, 0x00, 0xe0, 0x00, 0x80, 0x40, 0x20, 0x00, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0xc1, 0x40, 0x40, 0xfc, 0x3f, 0x7b, 0xb1, 0xe0, 0xae, 0xa8, 0xea, 0xee, 0xa1, 0x7b, 0x7f, 0xfc, 0x40, 0x40, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xf8, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0e, 0x0f, 0x0f, 0x0f, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0f, 0x0f, 0x0f, 0x0e, 0x0c, 0x00, 0x08, 0x09, 0x09, 0x09, 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x02, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x38, 0x38, 0xff, 0x95, 0x80, 0xb2, 0x82, 0xfa, 0xaa, 0xfa, 0x82, 0xf2, 0x90, 0x95, 0xff, 0x38, 0x38, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0xb0, 0x74, 0xf6, 0x77, 0x77, 0xf7, 0x77, 0xf7, 0x77, 0xf7, 0x77, 0xf7, 0x74, 0xf6, 0x77, 0xf7, 0x77, 0xf6, 0x34, 0xb0, 0x10, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x28, 0x2c, 0x24, 0x2f, 0x3f, 0x36, 0x07, 0x36, 0x1f, 0x0e, 0x1f, 0x36, 0x07, 0x36, 0x3f, 0x2f, 0x24, 0x2c, 0x28, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc1, 0xc0, 0x41, 0x41, 0x40, 0xc1, 0xc0, 0x41, 0x40, 0x41, 0xc0, 0xc1, 0x40, 0xc1, 0xc1, 0xc1, 0xc0, 0x41, 0xc0, 0xc1, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7f, 0x11, 0x11, 0x0e, 0x00, 0x0e, 0x11, 0x11, 0x0e, 0x00, 0x07, 0x18, 0x0c, 0x03, 0x0e, 0x18, 0x07, 0x00, 0x0e, 0x15, 0x15, 0x16, 0x00, 0x1f, 0x02, 0x01, 0x0e, 0x15, 0x15, 0x16, 0x00, 0x0e, 0x11, 0x11, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x11, 0x11, 0x0e, 0x00, 0x01, 0x4e, 0x30, 0x0e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x11, 0x11, 0x0e, 0x00, 0x7f, 0x11, 0x11, 0x0e, 0x00, 0x0e, 0x15, 0x15, 0x16, 0x00, 0x1f, 0x01, 0x01, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x13, 0x15, 0x19, 0x00, 0x0e, 0x11, 0x11, 0x0e, 0x00, 0x0f, 0x10, 0x10, 0x1f, 0x00, 0x1f, 0x02, 0x01, 0x0e, 0x11, 0x11, 0x00, 0x0e, 0x15, 0x15, 0x16, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x2f, 0x2f, 0x2b, 0x32, 0x3f, 0x20, 0x3b, 0x3b, 0x3c, 0x3f, 0x20, 0x2f, 0x2f, 0x3f, 0x26, 0x2b, 0x2c, 0x3f, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char gr9xv4_splash[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x08, 0x04, 0x04, 0x84, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x04, 0x04, 0x88, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0xfc, 0x04, 0x04, 0x00, 0xe0, 0x50, 0x50, 0x60, 0x00, 0xfe, 0x00, 0xe0, 0x50, 0x50, 0x60, 0x00, 0xf0, 0x10, 0x10, 0xe0, 0x10, 0x10, 0xe0, 0x00, 0xe0, 0x50, 0x50, 0x60, 0x00, 0xfc, 0x10, 0x00, 0xf0, 0x20, 0x10, 0x00, 0x10, 0xe0, 0x00, 0xe0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x24, 0xc4, 0x00, 0xe0, 0x50, 0x50, 0x60, 0x00, 0xf0, 0x20, 0x10, 0x00, 0xf4, 0x00, 0xe0, 0x50, 0x50, 0x60, 0x00, 0x30, 0x50, 0x90, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xbf, 0x80, 0x80, 0x80, 0xbf, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x30, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x88, 0x09, 0x09, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x81, 0xf0, 0x18, 0x19, 0xf0, 0x80, 0x01, 0x00, 0x00, 0x01, 0x01, 0x21, 0x20, 0x20, 0x21, 0x20, 0x21, 0x20, 0x20, 0x20, 0x20, 0x24, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0xe1, 0x21, 0x21, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x20, 0x21, 0x20, 0x20, 0x20, 0x21, 0x20, 0x20, 0x21, 0x21, 0x21, 0x20, 0x81, 0xc1, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xf8, 0xfe, 0xff, 0xff, 0xff, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x37, 0x47, 0x87, 0x87, 0x87, 0x97, 0x97, 0x07, 0x5f, 0xdf, 0xdf, 0xdf, 0xde, 0xd8, 0x80, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0f, 0x00, 0x80, 0x40, 0x3f, 0x80, 0xc0, 0xe0, 0xe0, 0xe0, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x58, 0x48, 0x4c, 0x4c, 0x47, 0x47, 0x44, 0x46, 0x42, 0x43, 0xff, 0x00, 0x00, 0xff, 0x43, 0x42, 0x46, 0x44, 0x47, 0x47, 0x4c, 0x4c, 0x48, 0x58, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xb0, 0x18, 0x0c, 0x04, 0x06, 0x87, 0x8f, 0xbf, 0xee, 0xfe, 0xf6, 0x7e, 0x3c, 0x1c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x1f, 0x39, 0x60, 0x80, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x8e, 0xce, 0xee, 0xfc, 0xf9, 0x73, 0x27, 0x0f, 0x1f, 0x3f, 0x7e, 0xfc, 0xf9, 0xf1, 0xf1, 0xf9, 0xfc, 0x3e, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x7f, 0x00, 0x00, 0x7f, 0x40, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0x40, 0xc0, 0xc0, 0x80, 0x88, 0x10, 0x10, 0x1d, 0x17, 0x11, 0x11, 0x13, 0x13, 0x13, 0x13, 0x11, 0x17, 0x1d, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0f, 0x07, 0x07, 0x03, 0x03, 0x01, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0x7c, 0x3e, 0x1f, 0x0f, 0x07, 0x07, 0x0f, 0x1f, 0x3f, 0x7e, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x7c, 0xf8, 0x80, 0x80, 0xf8, 0x7c, 0x0c, 0x00, 0xe0, 0xf0, 0xdc, 0xce, 0xc3, 0xff, 0xff, 0xc0, 0xc0, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0xc1, 0x40, 0x40, 0xfc, 0x3f, 0x7b, 0xb1, 0xe0, 0xae, 0xa8, 0xea, 0xee, 0xa1, 0x7b, 0x7f, 0xfc, 0x40, 0x40, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xff, 0xff, 0x00, 0x00, 0xfe, 0xf8, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0e, 0x0f, 0x0f, 0x0f, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0f, 0x0f, 0x0f, 0x0e, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x0f, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x38, 0x38, 0xff, 0x95, 0x80, 0xb2, 0x82, 0xfa, 0xaa, 0xfa, 0x82, 0xf2, 0x90, 0x95, 0xff, 0x38, 0x38, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0xb0, 0x74, 0xf6, 0x77, 0x77, 0xf7, 0x77, 0xf7, 0x77, 0xf7, 0x77, 0xf7, 0x74, 0xf6, 0x77, 0xf7, 0x77, 0xf6, 0x34, 0xb0, 0x10, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x28, 0x2c, 0x24, 0x2f, 0x3f, 0x36, 0x07, 0x36, 0x1f, 0x0e, 0x1f, 0x36, 0x07, 0x36, 0x3f, 0x2f, 0x24, 0x2c, 0x28, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc1, 0xc0, 0x41, 0x41, 0x40, 0xc1, 0xc0, 0x41, 0x40, 0x41, 0xc0, 0xc1, 0x40, 0xc1, 0xc1, 0xc1, 0xc0, 0x41, 0xc0, 0xc1, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7f, 0x11, 0x11, 0x0e, 0x00, 0x0e, 0x11, 0x11, 0x0e, 0x00, 0x07, 0x18, 0x0c, 0x03, 0x0e, 0x18, 0x07, 0x00, 0x0e, 0x15, 0x15, 0x16, 0x00, 0x1f, 0x02, 0x01, 0x0e, 0x15, 0x15, 0x16, 0x00, 0x0e, 0x11, 0x11, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x11, 0x11, 0x0e, 0x00, 0x01, 0x4e, 0x30, 0x0e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x11, 0x11, 0x0e, 0x00, 0x7f, 0x11, 0x11, 0x0e, 0x00, 0x0e, 0x15, 0x15, 0x16, 0x00, 0x1f, 0x01, 0x01, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x13, 0x15, 0x19, 0x00, 0x0e, 0x11, 0x11, 0x0e, 0x00, 0x0f, 0x10, 0x10, 0x1f, 0x00, 0x1f, 0x02, 0x01, 0x0e, 0x11, 0x11, 0x00, 0x0e, 0x15, 0x15, 0x16, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x2f, 0x2f, 0x2b, 0x32, 0x3f, 0x20, 0x3b, 0x3b, 0x3c, 0x3f, 0x20, 0x2f, 0x2f, 0x3f, 0x26, 0x2b, 0x2c, 0x3f, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char er9x_splash[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xe0, 0xf0, 0xf8, 0xf8, 0xfc, 0xfc, 0xfc, 0xf8, 0xf8, 0xf8, 0xf0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xe0, 0xc0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xc0, 0xf8, 0xff, 0xff, 0x9f, 0x87, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x03, 0x83, 0x80, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0xc3, 0xe3, 0x73, 0x3f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x3f, 0x1f, 0x1f, 0x0f, 0x07, 0x83, 0xc3, 0xe1, 0xe1, 0xe0, 0xe0, 0xc0, 0x00, 0x0e, 0x1f, 0x3f, 0x7f, 0x7f, 0xff, 0xf3, 0xe0, 0xe0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf0, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x3f, 0x0f, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00,
|
||||
0x00, 0x80, 0xf0, 0xfe, 0xff, 0xff, 0xc7, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0x01, 0xc1, 0xf0, 0xfe, 0xff, 0x3f, 0x0f, 0x07, 0x0f, 0x0d, 0x0d, 0x0d, 0x1d, 0x19, 0x19, 0x19, 0x19, 0x31, 0x31, 0x31, 0x31, 0x71, 0x61, 0x61, 0x61, 0xe1, 0xc1, 0xc1, 0xc1, 0x81, 0x00, 0x00, 0x00, 0x80, 0xe0, 0xf8, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x2f, 0x17, 0x0f, 0x03, 0x81, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x07, 0x07, 0x0e, 0x1e, 0x1c, 0x38, 0x70, 0xe0, 0xf0, 0xf8, 0xfe, 0xff, 0xff, 0x7f, 0x1f, 0x0f, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xf8, 0xfc, 0xfc, 0xfe, 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0xf8, 0xfe, 0xff, 0xff, 0x7f, 0x1f, 0x0f, 0x1f, 0x3d, 0x7c, 0xf8, 0xf8, 0xf0, 0xe0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x07, 0x07, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xf0, 0x78, 0xde, 0x27, 0x13, 0x09, 0x0e, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x0f, 0x7f, 0xff, 0xfc, 0x78, 0x78, 0xf8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf0, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0x38, 0x1e, 0x0f, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x0e, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x00, 0x0f, 0x0f, 0x00, 0x0f, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xf8, 0xbf, 0xff, 0xff, 0xff, 0x1f, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xfc, 0xff, 0x7f, 0x78, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x1c, 0x07, 0x0e, 0x0f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char opentx_splash[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x08,0x04,0x04,0x84,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0xc4,0x04,0x04,0x88,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xbf,0x80,0x80,0x80,0xbf,0x80,0x80,0x80,0x80,0x00,0x00,0x30,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x88,0x09,0x09,0x08,0xf0,0x00,0x00,0x00,0x01,0x01,0x01,0x7f,0x01,0x01,0x01,0x01,0x00,0x00,0x7f,0x49,0x49,0x49,0x49,0x41,0x41,0x40,0x00,0x7f,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x7f,0x49,0x49,0x49,0x49,0x41,0x41,0x40,0x00,0x7f,0x01,0x06,0x0c,0x10,0x10,0x0c,0x06,0x01,0x7f,0x00,0x00,0x7f,0x49,0x49,0x49,0x49,0x41,0x41,0x40,0x01,0x01,0x01,0x7f,0x01,0x01,0x01,0x01,0x00,0x00,0x7f,0x09,0x09,0x09,0x09,0x19,0x29,0x4e,0x00,0x01,0x03,0x06,0x0c,0x78,0x0c,0x06,0x03,0x01,0x00,0x00,
|
||||
0x00,0x00,0xf8,0xfe,0xff,0xff,0xff,0x0f,0x07,0x07,0x07,0x07,0x07,0x07,0x37,0x47,0x87,0x87,0x87,0x97,0x97,0x07,0x5f,0xdf,0xdf,0xdf,0xde,0xd8,0x80,0x10,0x10,0x10,0x10,0x10,0x0f,0x00,0x80,0x40,0x3f,0x80,0xc0,0xe0,0xe0,0xe0,0x60,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0xd0,0x90,0x90,0x90,0x90,0x90,0x00,0x00,0x00,0xf0,0x90,0x90,0x90,0x90,0x10,0x10,0x00,0x00,0xf0,0x90,0x90,0x90,0x90,0x90,0x90,0xe0,0x00,0x00,0xf0,0x00,0x00,0x00,0xf0,0x90,0x90,0x90,0x90,0x10,0x10,0x00,0x60,0xd0,0x90,0x90,0x90,0x90,0x90,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x01,0x07,0x07,0x0f,0x0f,0x0f,0x0e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x0e,0x0e,0x0e,0x0e,0x0e,0x8e,0xce,0xee,0xfc,0xf9,0x73,0x27,0x0f,0x1f,0x3f,0x7e,0xfc,0xf9,0xf1,0xf1,0xf9,0xfc,0x3e,0x1f,0x0f,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x06,0x04,0x04,0x04,0x04,0x04,0x03,0x00,0x00,0x07,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,0x07,0x00,0x00,0x00,0x00,0x01,0x02,0x04,0x00,0x00,0x07,0x00,0x00,0x00,0x07,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x02,0x06,0x04,0x04,0x04,0x04,0x04,0x03,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1e,0x1e,0x1e,0x0e,0x0e,0x0f,0x07,0x07,0x03,0x03,0x01,0x80,0xc0,0xe0,0xf0,0xf8,0x7c,0x3e,0x1f,0x0f,0x07,0x07,0x0f,0x1f,0x3f,0x7e,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x4a,0x4a,0x4a,0x4a,0x4a,0x7c,0x00,0x02,0x06,0x0c,0x70,0x08,0x04,0x02,0x02,0x00,0x00,0x00,0x00,0x1c,0x22,0x41,0x41,0x49,0x49,0x49,0x3a,0x18,0x00,0x00,0x7e,0x12,0x12,0x12,0x12,0x32,0x4c,0x00,0x00,0x3e,0x40,0x40,0x40,0x40,0x40,0x3e,0x00,0x02,0x0c,0x18,0x60,0x60,0x30,0x0c,0x02,0x00,0x7e,0x00,0x00,0x7e,0x02,0x0c,0x18,0x30,0x40,0x7e,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0xe0,0x10,0x10,0x10,0xe0,0x00,0x00,0xc0,0x80,0x40,0x80,0x00,0x00,0x80,0x40,0x40,0x80,0x00,0x00,0xcc,0x8e,0x4f,0x8f,0x0f,0x07,0x03,0x01,0x00,0x00,0x00,0x60,0x90,0x90,0x10,0x00,0x00,0x00,0x80,0x41,0x43,0x87,0x0f,0x0f,0xcf,0x0e,0x0c,0xc0,0x00,0x00,0xc0,0x80,0x40,0xc0,0x00,0x00,0x80,0x40,0x40,0x40,0x00,0x00,0x80,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x07,0x08,0x08,0x08,0x07,0x00,0x00,0x3f,0x04,0x08,0x07,0x00,0x00,0x07,0x09,0xc9,0x49,0x40,0x40,0x8f,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x09,0x06,0x00,0x00,0x07,0x08,0x08,0x07,0x00,0x00,0x07,0x08,0x04,0x0f,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x40,0x07,0x08,0x08,0x08,0x00,0x00,0x07,0x09,0x09,0x09,0x00,0x00,0x00,0xc8,0x00,0x00,0x08,0xc0,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x20,0x00,0x00,0x20,0x00,0x00,0x00,0x3f,0x04,0x04,0x04,0x03,0x00,0x00,0x1e,0x21,0x21,0x1e,0x00,0x07,0x38,0x0e,0x0e,0x38,0x07,0x00,0x1e,0x25,0x25,0x26,0x00,0x00,0x3f,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x3f,0x00,0x00,0x3f,0x02,0x01,0x3e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x3c,0x03,0x00,0x00,0x00,0x1e,0x21,0x21,0x1e,0x00,0x00,0x1f,0x20,0x10,0x3f,0x00,0x3f,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x02,0x02,0x02,0x3f,0x00,0x00,0x19,0x25,0x15,0x1e,0x20,0x00,0x3f,0x02,0x01,0x3e,0x00,0x1e,0x21,0x12,0x3f,0x00,0x00,0x22,0x25,0x29,0x11,0x00,
|
||||
};
|
||||
|
||||
const unsigned char opentxtaranis_splash[] = {
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0x7f,0x3f,0x3f,0x7f,0x1f,0x3f,0x3f,0x1f,0x1f,0x0f,0x0f,0x1f,0x1f,0x07,0x0f,0x0f,0x07,0x0f,0x0f,0x07,0x07,0x03,0x07,0x07,0x03,0x03,0x03,0x07,0x07,0x03,0x07,0x03,0x83,0x07,0x83,0x03,0x03,0x03,0x03,0x83,0x03,0x03,0x03,0x83,0x83,0x07,0x83,0x03,0x07,0x03,0x07,0x03,0x03,0x03,0x03,0x07,0x07,0x03,0x07,0x07,0x07,0x0f,0x0f,0x07,0x1f,0x07,0x0f,0x0f,0x1f,0x0f,0x0f,0x1f,0x1f,0x3f,0x3f,0x1f,0x7f,0x3f,0x3f,0x7f,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x03,0x03,0xff,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x83,0x83,0x83,0xc3,0x83,0x83,0x83,0xc3,0xc3,0xc3,0xc3,0x83,0x83,0xc3,0x83,0x83,0x03,0x83,0x87,0x03,0x07,0x03,0x07,0x03,0x07,0x03,0x03,0x07,0x07,0x0f,0x07,0x07,0x1f,0x0f,0x07,0x0f,0x0f,0x2f,0x1f,0x1f,0x3f,0x7f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x43,0x03,0x83,0x83,0x83,0xc3,0x83,0x83,0x83,0xc3,0x83,0x83,0x83,0xc3,0x83,0x83,0x83,0xc3,0x83,0x83,0x83,0xc3,0x83,0x83,0x83,0xc3,0x83,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x03,0x03,0xff,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x0b,0x07,0x03,0x07,0x0f,0x07,0x1f,0x0f,0x1f,0x1f,0x1f,0x3f,0xbf,0xbf,0x7f,0x7f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0x03,0xff,0xff,0xff,0xff,0xfb,0x07,0xf7,0xf7,0xff,0x0f,0xcf,0xdf,0xdf,0x3f,0xdf,0xbf,0xbf,0x7f,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0xff,0xff,0xff,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xfb,0xff,0xff,0xf3,0xf3,0xf3,0xfb,0xf3,0xd3,0xe3,0xe3,0xc3,0x83,0x83,0xc3,0x83,0x03,0x83,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x07,0x0b,0x03,0x07,0x3f,0x0f,0x0f,0x1f,0xff,0x3f,0x3f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x7f,0x7f,0xff,0x5f,0x1f,0x1f,0x3f,0x17,0x07,0x07,0x0f,0x07,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x83,0x43,0x83,0x83,0xe3,0xe3,0xe3,0xc3,0xe3,0xeb,0xf3,0xf3,0xfb,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x4f,0x09,0x7b,0x87,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x38,0x74,0xf8,0xfc,0xfc,0xfc,0xfe,0xff,0xfe,0xff,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff,0xfe,0xfc,0xfc,0xfc,0xfe,0xf0,0x38,0x74,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x4f,0x09,0x7b,0x87,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x0f,0x1f,0x0f,0x1f,0x17,0x0e,0x07,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x00,0xc0,0xc0,0x80,0xe0,0xc8,0xef,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x07,0x07,0x07,0x0f,0x07,0x07,0x07,0x0f,0x07,0x07,0x07,0x0f,0x07,0x07,0x07,0x0f,0x07,0x07,0x07,0x0f,0x07,0x0f,0x0f,0xff,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xf8,0xf8,0xf0,0xd0,0xd0,0xe0,0xe0,0xa0,0x80,0x80,0xc0,0x80,0x00,0x80,0x00,0x01,0x01,0x01,0x00,0x05,0x03,0x01,0x03,0x03,0x07,0x0f,0x07,0x0f,0x0f,0x0f,0x1f,0x5f,0x5f,0x3f,0x3f,0xff,0xff,0xff,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xfe,0xfe,0xff,0x01,0xfb,0xf9,0xfb,0x07,0xfb,0xf7,0xf7,0x0f,0xef,0xff,0xef,0x1f,0x5f,0xdf,0x7f,0xbf,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfe,0xfc,0xfe,0xf8,0xfc,0xfc,0xf8,0xe0,0xe8,0xf0,0xf0,0xc0,0xc0,0xc0,0xe0,0xc0,0x40,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x01,0x07,0x03,0x03,0x07,0x02,0x03,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x80,0x00,0xa0,0xc0,0x80,0xc0,0xc0,0xe0,0xf0,0xe0,0xf8,0xf0,0xf0,0xf8,0xfe,0xfa,0xfc,0xfc,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xfe,0xff,0xfa,0xf4,0xfc,0xf8,0xf8,0xe0,0xe0,0xf0,0xc0,0xe0,0xe0,0xc0,0x80,0x80,0x80,0xc0,0x00,0x00,0x80,0x80,0x00,0x01,0x80,0x00,0x01,0x03,0x03,0x01,0x07,0x03,0x07,0x03,0x07,0x03,0x07,0x07,0x0f,0x07,0x0f,0x07,0x07,0x07,0x07,0x0f,0x07,0x07,0x07,0x0f,0x0f,0x07,0x0f,0x07,0x07,0x03,0x07,0x07,0x07,0x03,0x07,0x03,0x01,0x03,0x03,0x01,0x00,0x01,0x80,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0xc0,0xc0,0xe0,0xe0,0xc0,0xf8,0xe0,0xe0,0xf0,0xfa,0xf4,0xfc,0xf8,0xfe,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xfc,0xfc,0xfe,0xfc,0xfc,0xfc,0xfe,0xfc,0xfc,0xfc,0xfe,0xfc,0xfc,0xfc,0xfe,0xfc,0xfc,0xfc,0xfe,0xfe,0xfe,0xfc,0xfe,0xff,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x0f,0x0f,0x0f,0x1f,0x0f,0x0f,0x0f,0x1f,0x0f,0x0f,0x0f,0x1f,0x0f,0x0f,0x0f,0x1f,0x0f,0x0f,0x0f,0x1f,0x0f,0x0f,0x0f,0x1f,0x0f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xfe,0xfc,0xfe,0xf4,0xfc,0xfc,0xf8,0xe8,0xe8,0xf0,0xf0,0xc0,0xc0,0xc0,0xe0,0x00,0x80,0xc0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x7f,0x7f,0x7f,0x80,0x3f,0xff,0xbf,0xc0,0xcf,0xcf,0xef,0xf0,0xef,0xf7,0xf7,0xf8,0xff,0xff,0xfb,0xfc,0xfe,0xfc,0xfe,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0x7f,0x7f,0x1f,0x3f,0x1f,0x3f,0x1f,0x0f,0x1f,0x0f,0x03,0x0b,0x07,0x07,0x01,0x01,0x01,0x03,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0xc0,0xc0,0xe0,0x00,0xc0,0xc0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x02,0x01,0x01,0x03,0x03,0x03,0x07,0x07,0x17,0x0f,0x0f,0x1f,0x3f,0x3f,0x1f,0xff,0x7f,0x3f,0x7f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x0f,0x1f,0xff,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xee,0xff,0x1f,0xee,0xee,0xfe,0x1f,0xee,0xee,0xff,0x1e,0xee,0xef,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xef,0xfe,0x1e,0xee,0xee,0xff,0x1e,0xee,0xee,0xfe,0x1f,0xef,0xee,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xee,0xee,0xfe,0x1f,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xee,0xee,0xfe,0x1f,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xef,0xef,0xff,0x1f,0xee,0xef,0xfe,0x1f,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xee,0xee,0xfe,0x1e,0xfe,0x0e,0x1e,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xe0,0xff,0xff,0xe7,0xe7,0xf7,0xf8,0xf7,0xfb,0xfb,0xfc,0xff,0xff,0xfd,0xfe,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0x1f,0x5f,0x3f,0x3f,0x0f,0x0f,0x0f,0x1f,0x03,0x07,0x0f,0x07,0x07,0x03,0x01,0x03,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x80,0x80,0xc0,0xc0,0xf0,0xf0,0xe0,0xf4,0xf4,0xf8,0xf8,0xfc,0xff,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xff,0xf8,0xfe,0xf8,0xfc,0xe8,0xe8,0xf0,0xf0,0xa0,0xc0,0xe0,0xc0,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x03,0x01,0x01,0x03,0x0f,0x0b,0x07,0x07,0x1f,0x1f,0x1f,0x0f,0x5f,0x1f,0x3f,0x3f,0xff,0x7f,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
|
||||
};
|
||||
|
||||
const unsigned char ersky9x_splash[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xE0,0xE0,0xF0,0xF8,0xF8,0xFC,0xFC,0xFC,0xF8,0xF8,0xF8,0xF0,0x40,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xC0,0xE0,0xE0,0xE0,0xF0,0xF0,0xF0,0xE0,0xC0,0x00,
|
||||
0x00,0x00,0x00,0x00,0xC0,0xF8,0xFF,0xFF,0x9F,0x87,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x03,0x83,0x80,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0x83,0xC3,0xE3,0x73,0x3F,0x1F,0x00,0x00,0x00,0x00,0x80,0xE0,0xF0,0xF8,0xFC,0xFE,0xFF,0xFF,0xFF,0xFF,0x7F,0x3F,0x1F,0x1F,0x0F,0x07,0x83,0xC3,0xE1,0xE1,0xE0,0xE0,0xC0,0x00,0x0E,0x1F,0x3F,0x7F,0x7F,0xFF,0xF3,0xE0,0xE0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xF0,0xFC,0xFE,0xFF,0xFF,0xFF,0xFF,0x7F,0x3F,0x0F,0x03,0x01,0x01,0x01,0x00,0x00,
|
||||
0x00,0x80,0xF0,0xFE,0xFF,0xFF,0xC7,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0x01,0xC1,0xF0,0xFE,0xFF,0x3F,0x0F,0x07,0x0F,0x0D,0x0D,0x0D,0x1D,0x19,0x19,0x19,0x19,0x31,0x31,0x31,0x31,0x71,0x61,0x61,0x61,0xE1,0xC1,0xC1,0xC1,0x81,0x00,0x00,0x00,0x80,0xE0,0xF8,0xFC,0xFF,0xFF,0xFF,0xFF,0x2F,0x17,0x0F,0x03,0x81,0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x03,0x07,0x07,0x0E,0x1E,0x1C,0x38,0x70,0xE0,0xF0,0xF8,0xFE,0xFF,0xFF,0x7F,0x1F,0x0F,0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x7E,0xE7,0xC3,0xC3,0xC3,0xC3,0xC7,0x8E,0x0C,0x00,0x00,0xFF,0xFF,0xC0,0xE0,0xF0,0x38,0x1C,0x0E,0x07,0x03,0x00,0x00,0x3F,0x7F,0xE0,0xC0,0x80,0x80,0xC0,0xE0,0x7F,0x3F,0x00,0x00,0x00,0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xF8,0xFC,0xFC,0xFE,0xFF,0x7F,0x3F,0x1F,0x0F,0x07,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xE0,0xF8,0xFE,0xFF,0xFF,0x7F,0x1F,0x0F,0x1F,0x3D,0x7C,0xF8,0xF8,0xF0,0xE0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x1C,0x38,0x30,0x30,0x30,0x30,0x39,0x1F,0x0F,0x00,0x00,0x3F,0x3F,0x00,0x01,0x03,0x07,0x0E,0x1C,0x38,0x30,0x00,0x00,0x00,0x00,0x00,0x01,0x3F,0x3F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x03,0x07,0x07,0x07,0x03,0x01,0x00,0x00,0x00,0xE0,0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xF0,0x78,0xDE,0x27,0x13,0x09,0x0E,0x07,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x0F,0x7F,0xFF,0xFC,0x78,0x78,0xF8,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xF0,0xFE,0xFF,0xFF,0xFF,0xFF,0x3F,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xE0,0x38,0x1E,0x0F,0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x01,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0E,0x02,0x02,0x02,0x02,0x02,0x03,0x03,0x00,0x0F,0x0F,0x00,0x0F,0x0F,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x0F,0x0F,0x08,0x08,0x08,0x08,0x08,0x0F,0x0F,0x00,0x00,0x00,0x00,0x0F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xF8,0xBF,0xFF,0xFF,0xFF,0x1F,0x7F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFC,0xFF,0x7F,0x78,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x1C,0x07,0x0E,0x0F,0x07,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
};
|
||||
@@ -335,7 +335,6 @@ void Profile::resetFwVariables()
|
||||
CompStoreObj::resetProperty(this, name);
|
||||
}
|
||||
|
||||
|
||||
// ** ComponentAssetData class********************
|
||||
|
||||
ComponentAssetData::ComponentAssetData() : CompStoreObj(), index(-1)
|
||||
@@ -727,6 +726,14 @@ void AppData::convertSettings(QSettings & settings)
|
||||
}
|
||||
}
|
||||
|
||||
if (savedMajMin < 0x300) {
|
||||
// 3.0 CloudBuild copy filter changed to cater for uf2
|
||||
qInfo().noquote() << "Deleting CloudBuild settings to force refresh";
|
||||
static const QString path = QStringLiteral("Components/component6");
|
||||
if (settings.contains(path))
|
||||
settings.remove(path);
|
||||
}
|
||||
|
||||
if (removeUnused)
|
||||
clearUnusedSettings(settings);
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
#define APP_COMPANION QStringLiteral("EdgeTX Companion")
|
||||
#define APP_SIMULATOR QStringLiteral("EdgeTX Simulator")
|
||||
|
||||
//! Default location for EdgeTX-related user documents (settigns, logs, etc)
|
||||
//! Default location for EdgeTX-related user documents (settings, logs, etc)
|
||||
#define CPN_DOCUMENTS_LOCATION QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) % "/" % COMPANY
|
||||
//! Location for settings backup files. TODO: make option or remember last location.
|
||||
#define CPN_SETTINGS_BACKUP_DIR CPN_DOCUMENTS_LOCATION % "/backup"
|
||||
@@ -97,10 +97,10 @@
|
||||
T m_name; // Member variable.
|
||||
\endcode
|
||||
|
||||
If you only use this macro (w/out a \p PROPERTY*() macro) then you need to provide the getter, setter, and reset functions yourself. The initializer functoin is optional.
|
||||
If you only use this macro (w/out a \p PROPERTY*() macro) then you need to provide the getter, setter, and reset functions yourself. The initializer function is optional.
|
||||
Those function names must match the expected signatures as defined in the \e Q_PROPERTY() macro.
|
||||
|
||||
\param TYPE The data type (T).
|
||||
\param TYPE The data type (T).
|
||||
\param NAME Name of the property.
|
||||
\param KEY Settings key name, a const string. Can be the same as \a NAME.
|
||||
\param DFLT Default value, must be compatible with \a TYPE.
|
||||
@@ -185,7 +185,7 @@
|
||||
|
||||
|
||||
/*!
|
||||
\brief CompStoreObj manages staic meta data on member properties (extending Qt's own property system) and provides utility functions for subclasses.
|
||||
\brief CompStoreObj manages static meta data on member properties (extending Qt's own property system) and provides utility functions for subclasses.
|
||||
|
||||
The extension is essentially used to provide some "integration" with \e QSettings by providing storage path/key mappings to properties.
|
||||
It also adds ability to access property default values, auto-initialization from saved settings (with fallback to default), and provides change notification signals.
|
||||
@@ -467,6 +467,7 @@ class Profile: public CompStoreObj
|
||||
Q_OBJECT
|
||||
public:
|
||||
Profile & operator=(const Profile & rhs);
|
||||
QString getVariantFromType() const { return fwType().section("-", 1, 1); }
|
||||
|
||||
public slots:
|
||||
bool existsOnDisk();
|
||||
@@ -756,18 +757,7 @@ class AppData: public CompStoreObj
|
||||
PROPERTYQBA (mdiWinGeo)
|
||||
PROPERTYQBA (mdiWinState)
|
||||
PROPERTYQBA (compareWinGeo)
|
||||
|
||||
PROPERTYSTR3(armMcu, "arm_mcu", QStringLiteral("at91sam3s4-9x"))
|
||||
PROPERTYSTR2(avrArguments, "avr_arguments")
|
||||
PROPERTYSTR2(avrPort, "avr_port")
|
||||
PROPERTYSTR2(avrdudeLocation, "avrdudeLocation")
|
||||
PROPERTYSTR3(dfuArguments, "dfu_arguments", QStringLiteral("-a 0"))
|
||||
PROPERTYSTR2(dfuLocation, "dfu_location")
|
||||
PROPERTYSTR2(sambaLocation, "samba_location")
|
||||
PROPERTYSTR3(sambaPort, "samba_port", QStringLiteral("\\USBserial\\COM23"))
|
||||
|
||||
PROPERTYSTR2(libDir, "libraryPath")
|
||||
|
||||
PROPERTYSTR3(backupDir, "backupPath", CPN_DOCUMENTS_LOCATION % "/backups")
|
||||
PROPERTYSTR3(eepromDir, "lastDir", CPN_DOCUMENTS_LOCATION % "/eeproms")
|
||||
PROPERTYSTR3(flashDir, "lastFlashDir", CPN_DOCUMENTS_LOCATION % "/flash")
|
||||
@@ -789,13 +779,10 @@ class AppData: public CompStoreObj
|
||||
|
||||
PROPERTYSTR (locale)
|
||||
PROPERTYSTR (gePath)
|
||||
PROPERTYSTRD(mcu, QStringLiteral("m64"))
|
||||
PROPERTYSTRD(programmer, QStringLiteral("usbasp"))
|
||||
|
||||
PROPERTY(NewModelAction, newModelAction, MODEL_ACT_WIZARD)
|
||||
|
||||
PROPERTY4(int, embedSplashes, "embedded_splashes", 0)
|
||||
PROPERTY4(int, fwServerFails, "fwserver", 0)
|
||||
PROPERTY4(int, iconSize, "icon_size", 2)
|
||||
PROPERTY4(int, historySize, "history_size", 10)
|
||||
PROPERTY (int, generalEditTab, 0)
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
|
||||
#include "hexinterface.h"
|
||||
#include "splash.h"
|
||||
#include "firmwareinterface.h"
|
||||
#include "helpers.h"
|
||||
#include "storage.h"
|
||||
@@ -85,14 +84,18 @@ public:
|
||||
{
|
||||
while(pos<size)
|
||||
*buf++ = getNext();
|
||||
|
||||
return pos == size;
|
||||
}
|
||||
|
||||
uint8_t getWidth() const { return width; }
|
||||
uint8_t getRows() const { return rows; }
|
||||
uint8_t getRawRows() const { return rawRows; }
|
||||
|
||||
void goToNextRow()
|
||||
{
|
||||
size_t offset = pos%width;
|
||||
|
||||
if(offset)
|
||||
skip(width - pos%width);
|
||||
}
|
||||
@@ -158,40 +161,40 @@ private:
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
FirmwareInterface::FirmwareInterface(const QString & filename, QDialog* parentDialog):
|
||||
parentDialog(parentDialog),
|
||||
flash(FSIZE_MAX, 0),
|
||||
flashSize(0),
|
||||
eepromVersion(0),
|
||||
eepromVariant(0),
|
||||
splashOffset(0),
|
||||
splashSize(0),
|
||||
splashWidth(0),
|
||||
splashHeight(0),
|
||||
isValidFlag(false)
|
||||
FirmwareInterface::FirmwareInterface(const QString &filename, QDialog *parent) :
|
||||
parentDialog(parent)
|
||||
{
|
||||
if (!filename.isEmpty()) {
|
||||
QFile file(filename);
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { // reading HEX TEXT file
|
||||
QTextStream inputStream(&file);
|
||||
flashSize = HexInterface(inputStream).load((uint8_t *)flash.data(), FSIZE_MAX);
|
||||
file.close();
|
||||
if (flashSize == 0) {
|
||||
file.open(QIODevice::ReadOnly);
|
||||
flashSize = file.read((char *)flash.data(), FSIZE_MAX);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filename.isEmpty()) return;
|
||||
|
||||
QFile file(filename);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
initFlash(file.readAll());
|
||||
file.close();
|
||||
}
|
||||
|
||||
FirmwareInterface::FirmwareInterface(const QByteArray &flashData, QDialog *parent) :
|
||||
parentDialog(parent)
|
||||
{
|
||||
initFlash(flashData);
|
||||
}
|
||||
|
||||
void FirmwareInterface::initFlash(const QByteArray& flashData)
|
||||
{
|
||||
flash = flashData;
|
||||
flashSize = flashData.size();
|
||||
|
||||
if (flashSize > 0) {
|
||||
flavour = seekLabel(FW_MARK);
|
||||
type = (flash.startsWith("UF2\n") ? FIRMWARE_TYPE_UF2 : FIRMWARE_TYPE_BIN);
|
||||
flavour = seekLabel(FW_MARK).remove("edgetx-");
|
||||
version = seekLabel(VERS_MARK);
|
||||
|
||||
if (version.startsWith("opentx-")) {
|
||||
// old version format
|
||||
int index = version.lastIndexOf('-');
|
||||
flavour = version.mid(0, index);
|
||||
version = version.mid(index + 1);
|
||||
}
|
||||
|
||||
date = seekLabel(DATE_MARK);
|
||||
time = seekLabel(TIME_MARK);
|
||||
eepromId = seekLabel(EEPR_MARK);
|
||||
@@ -200,8 +203,7 @@ FirmwareInterface::FirmwareInterface(const QString & filename, QDialog* parentDi
|
||||
QStringList list = eepromId.split('-');
|
||||
eepromVersion = list[0].toInt();
|
||||
eepromVariant = list[1].toInt();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
eepromVersion = eepromId.toInt();
|
||||
}
|
||||
|
||||
@@ -215,16 +217,20 @@ QString FirmwareInterface::seekString(const QString & string)
|
||||
QString result = "";
|
||||
|
||||
int start = flash.indexOf(string.toUtf8());
|
||||
|
||||
if (start > 0) {
|
||||
start += string.length();
|
||||
int end = -1;
|
||||
for (int i=start; i<start+50; i++) {
|
||||
|
||||
for (int i = start; i < start + 50; i++) {
|
||||
char c = flash.at(i);
|
||||
|
||||
if (c == '\0' || c == '\036') {
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (end > 0) {
|
||||
result = flash.mid(start, (end - start)).trimmed();
|
||||
}
|
||||
@@ -236,51 +242,44 @@ QString FirmwareInterface::seekString(const QString & string)
|
||||
QString FirmwareInterface::seekLabel(const QString & label)
|
||||
{
|
||||
QString result = seekString(label + "\037\033:");
|
||||
|
||||
if (result.isEmpty()) {
|
||||
result = seekString(label + "\037\075:"); // This is for Horus
|
||||
}
|
||||
|
||||
if (!result.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
return seekString(label + ":");
|
||||
}
|
||||
|
||||
QString FirmwareInterface::getFlavour() const
|
||||
{
|
||||
if (flavour == "opentx-taranis-x9e")
|
||||
return "opentx-x9e";
|
||||
else if (flavour == "opentx-x9dp" || flavour == "opentx-taranis-plus")
|
||||
return "opentx-x9d+";
|
||||
else if (flavour == "opentx-taranis")
|
||||
return "opentx-x9d";
|
||||
else if (flavour == "opentx-horus")
|
||||
return "opentx-x12s";
|
||||
else
|
||||
return flavour;
|
||||
return seekString(label + ":");
|
||||
}
|
||||
|
||||
bool FirmwareInterface::isHardwareCompatible(const FirmwareInterface &previousFirmware) const
|
||||
{
|
||||
QString newFlavour = getFlavour();
|
||||
|
||||
if (newFlavour.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QString previousFlavour = previousFirmware.getFlavour();
|
||||
|
||||
if (previousFlavour.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (newFlavour == previousFlavour);
|
||||
}
|
||||
|
||||
bool FirmwareInterface::seekSplash(QByteArray splash)
|
||||
{
|
||||
int start = flash.indexOf(splash);
|
||||
if (start>0) {
|
||||
|
||||
if (start > 0) {
|
||||
splashOffset = start;
|
||||
splashSize = splash.size();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -288,20 +287,23 @@ bool FirmwareInterface::seekSplash(QByteArray splash)
|
||||
bool FirmwareInterface::seekSplash(QByteArray sps, QByteArray spe, int size)
|
||||
{
|
||||
int start = 0;
|
||||
while (start>=0) {
|
||||
|
||||
while (start >= 0) {
|
||||
start = flash.indexOf(sps, start+1);
|
||||
|
||||
if (start>0) {
|
||||
int end = start + sps.size() + size;
|
||||
|
||||
if (end == flash.indexOf(spe, end)) {
|
||||
splashOffset = start + sps.size();
|
||||
splashSize = end - start - sps.size();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
qDebug() << flash.indexOf(spe, start) << end << sps.size() << spe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -317,30 +319,7 @@ void FirmwareInterface::seekSplash()
|
||||
splashOffset = 0;
|
||||
splashWidth = SPLASH_WIDTH;
|
||||
splashHeight = SPLASH_HEIGHT;
|
||||
splash_format = QImage::Format_Mono;
|
||||
|
||||
if (seekSplash(QByteArray((const char *)gr9x_splash, sizeof(gr9x_splash))) || seekSplash(QByteArray((const char *)gr9xv4_splash, sizeof(gr9xv4_splash)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (seekSplash(QByteArray((const char *)er9x_splash, sizeof(er9x_splash)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (seekSplash(QByteArray((const char *)opentx_splash, sizeof(opentx_splash)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (seekSplash(QByteArray((const char *)opentxtaranis_splash, sizeof(opentxtaranis_splash)))) {
|
||||
splashWidth = SPLASHX9D_WIDTH;
|
||||
splashHeight = SPLASHX9D_HEIGHT;
|
||||
splash_format = QImage::Format_Indexed8;
|
||||
return;
|
||||
}
|
||||
|
||||
if (seekSplash(QByteArray((const char *)ersky9x_splash, sizeof(ersky9x_splash)))) {
|
||||
return;
|
||||
}
|
||||
splashFormat = QImage::Format_Mono;
|
||||
|
||||
if (seekSplash(QByteArray(ETX_SPS_9X, ETX_SPS_SIZE), QByteArray(ETX_SPE, ETX_SPE_SIZE), 1024)) {
|
||||
return;
|
||||
@@ -349,18 +328,9 @@ void FirmwareInterface::seekSplash()
|
||||
if (seekSplash(QByteArray(ETX_SPS_TARANIS, ETX_SPS_SIZE), QByteArray(ETX_SPE, ETX_SPE_SIZE), RLE_SPLASH_MAX_SIZE)) {
|
||||
splashWidth = SPLASHX9D_WIDTH;
|
||||
splashHeight = SPLASHX9D_HEIGHT;
|
||||
splash_format = QImage::Format_Indexed8;
|
||||
splashFormat = QImage::Format_Indexed8;
|
||||
return;
|
||||
}
|
||||
|
||||
if (seekSplash(QByteArray(ERSKY9X_SPS, sizeof(ERSKY9X_SPS)), QByteArray(ERSKY9X_SPE, sizeof(ERSKY9X_SPE)), 1030)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (seekSplash(QByteArray(ERSPLASH_MARKER, sizeof(ERSPLASH_MARKER)))) {
|
||||
splashOffset += sizeof(ERSPLASH_MARKER);
|
||||
splashSize = sizeof(er9x_splash);
|
||||
}
|
||||
}
|
||||
|
||||
bool FirmwareInterface::setSplash(const QImage & newsplash)
|
||||
@@ -372,36 +342,38 @@ bool FirmwareInterface::setSplash(const QImage & newsplash)
|
||||
uint8_t b[SPLASH_SIZE_MAX] = {0};
|
||||
QColor color;
|
||||
QByteArray splash;
|
||||
if (splash_format == QImage::Format_Indexed8) {
|
||||
for (unsigned int y=0; y<splashHeight; y++) {
|
||||
unsigned int idx = (y/2)*splashWidth;
|
||||
for (unsigned int x=0; x<splashWidth; x++, idx++) {
|
||||
|
||||
if (splashFormat == QImage::Format_Indexed8) {
|
||||
for (unsigned int y = 0; y < splashHeight; y++) {
|
||||
unsigned int idx = (y / 2) * splashWidth;
|
||||
for (unsigned int x = 0; x < splashWidth; x++, idx++) {
|
||||
QRgb gray = qGray(newsplash.pixel(x, y));
|
||||
uint8_t z = ((255-gray)*15)/255;
|
||||
uint8_t z = ((255 - gray) * 15) / 255;
|
||||
if (y & 1) z <<= 4;
|
||||
b[idx] |= z;
|
||||
}
|
||||
}
|
||||
if(splashWidth == SPLASHX9D_WIDTH && splashHeight == SPLASHX9D_HEIGHT)
|
||||
|
||||
if (splashWidth == SPLASHX9D_WIDTH && splashHeight == SPLASHX9D_HEIGHT)
|
||||
{
|
||||
splashSize = RleBitmap::encode(b, SPLASH_SIZE_MAX);
|
||||
if(splashSize > RLE_SPLASH_MAX_SIZE){
|
||||
if(parentDialog)
|
||||
if (splashSize > RLE_SPLASH_MAX_SIZE){
|
||||
if (parentDialog)
|
||||
QMessageBox::critical(parentDialog, CPN_STR_TTL_ERROR, QObject::tr("Compressed image size exceeds reserved space."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
QColor black = QColor(0,0,0);
|
||||
QImage blackNwhite = newsplash.convertToFormat(QImage::Format_MonoLSB);
|
||||
for (uint y=0; y<splashHeight; y++) {
|
||||
for (uint x=0; x<splashWidth; x++) {
|
||||
color = QColor(blackNwhite.pixel(x,y));
|
||||
b[splashWidth*(y/8) + x] |= ((color==black ? 1: 0)<<(y % 8));
|
||||
for (uint y = 0; y < splashHeight; y++) {
|
||||
for (uint x = 0; x < splashWidth; x++) {
|
||||
color = QColor(blackNwhite.pixel(x, y));
|
||||
b[splashWidth * (y / 8) + x] |= ((color == black ? 1 : 0) << (y % 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
splash.clear();
|
||||
splash.append((char *)b, splashSize);
|
||||
flash.replace(splashOffset, splashSize, splash);
|
||||
@@ -420,27 +392,29 @@ uint FirmwareInterface::getSplashHeight()
|
||||
|
||||
QImage::Format FirmwareInterface::getSplashFormat()
|
||||
{
|
||||
return splash_format;
|
||||
return splashFormat;
|
||||
}
|
||||
|
||||
|
||||
QImage FirmwareInterface::getSplash()
|
||||
{
|
||||
if (splashOffset == 0 || splashSize == 0) {
|
||||
return QImage(); // empty image
|
||||
}
|
||||
|
||||
if (splash_format == QImage::Format_Indexed8) {
|
||||
if (splashFormat == QImage::Format_Indexed8) {
|
||||
QImage image(splashWidth, splashHeight, QImage::Format_RGB888);
|
||||
|
||||
if(splashWidth == SPLASHX9D_WIDTH && splashHeight == SPLASHX9D_HEIGHT)
|
||||
{
|
||||
std::vector<uint8_t> data;
|
||||
data.resize(splashWidth * splashHeight);
|
||||
RleBitmap img((uint8_t*)flash.data() + splashOffset - 2, 0);
|
||||
img.to(&data[0], data.size());
|
||||
|
||||
if (splashOffset > 0) {
|
||||
for (unsigned int y=0; y<splashHeight; y++) {
|
||||
unsigned int idx = (y/2)*splashWidth;
|
||||
|
||||
for (unsigned int x=0; x<splashWidth; x++, idx++) {
|
||||
uint8_t byte = data[idx];
|
||||
unsigned int z = (y & 1) ? (byte >> 4) : (byte & 0x0F);
|
||||
@@ -454,6 +428,7 @@ QImage FirmwareInterface::getSplash()
|
||||
if (splashOffset > 0) {
|
||||
for (unsigned int y=0; y<splashHeight; y++) {
|
||||
unsigned int idx = (y/2)*splashWidth;
|
||||
|
||||
for (unsigned int x=0; x<splashWidth; x++, idx++) {
|
||||
uint8_t byte = flash.at(splashOffset+idx);
|
||||
unsigned int z = (y & 1) ? (byte >> 4) : (byte & 0x0F);
|
||||
@@ -498,24 +473,12 @@ unsigned int FirmwareInterface::save(const QString & filename)
|
||||
memcpy(binflash, flash.constData(), flashSize);
|
||||
QFile file(filename);
|
||||
|
||||
int fileType = getStorageType(filename);
|
||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
|
||||
free(binflash);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fileType == STORAGE_TYPE_HEX) {
|
||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text)) { //reading HEX TEXT file
|
||||
free(binflash);
|
||||
return -1;
|
||||
}
|
||||
QTextStream outputStream(&file);
|
||||
HexInterface hex=HexInterface(outputStream);
|
||||
hex.save(binflash, flashSize);
|
||||
}
|
||||
else {
|
||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) { //reading HEX TEXT file
|
||||
free(binflash);
|
||||
return -1;
|
||||
}
|
||||
file.write((char*)binflash, flashSize);
|
||||
}
|
||||
file.write((char*)binflash, flashSize);
|
||||
|
||||
file.close();
|
||||
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _FIRMWAREINTERFACE_H_
|
||||
#define _FIRMWAREINTERFACE_H_
|
||||
#pragma once
|
||||
|
||||
#include <QtCore>
|
||||
#include <QString>
|
||||
@@ -46,11 +45,19 @@ class FirmwareInterface
|
||||
Q_DECLARE_TR_FUNCTIONS("FirmwareInterface")
|
||||
|
||||
public:
|
||||
FirmwareInterface(const QString & filename, QDialog* parentDialog = nullptr);
|
||||
enum FirmwareType{
|
||||
FIRMWARE_TYPE_BIN,
|
||||
FIRMWARE_TYPE_UF2
|
||||
};
|
||||
|
||||
explicit FirmwareInterface(const QString &filename, QDialog* parent = nullptr);
|
||||
explicit FirmwareInterface(const QByteArray &flashData, QDialog* parent = nullptr);
|
||||
|
||||
inline QString getDate() { return date; }
|
||||
inline QString getTime() { return time; }
|
||||
int getSize() { return flashSize; }
|
||||
QString getFlavour() const;
|
||||
inline const QByteArray& getFlash() { return flash; }
|
||||
inline int getSize() { return flashSize; }
|
||||
inline QString getFlavour() const { return flavour; }
|
||||
bool isHardwareCompatible(const FirmwareInterface &previousFirmware) const;
|
||||
inline QString getVersion() { return version; }
|
||||
inline int getEEpromVersion() { return eepromVersion; }
|
||||
@@ -64,31 +71,34 @@ class FirmwareInterface
|
||||
QImage::Format getSplashFormat();
|
||||
unsigned int save(const QString & fileName);
|
||||
bool isValid();
|
||||
FirmwareType getType() { return type; }
|
||||
const QString typeFileExtn() const { return (type == FIRMWARE_TYPE_UF2 ? "uf2" : "bin"); }
|
||||
|
||||
private:
|
||||
QDialog* parentDialog;
|
||||
QByteArray flash;
|
||||
uint flashSize;
|
||||
QString seekString(const QString & string);
|
||||
QString seekLabel(const QString & label);
|
||||
void seekSplash();
|
||||
bool seekSplash(QByteArray sps, QByteArray spe, int size);
|
||||
bool seekSplash(QByteArray splash);
|
||||
uint flashSize = 0;
|
||||
QString filename;
|
||||
QString date;
|
||||
QString time;
|
||||
QString flavour;
|
||||
QString version;
|
||||
QString eepromId;
|
||||
int eepromVersion;
|
||||
int eepromVariant;
|
||||
int eepromVersion = 0;
|
||||
int eepromVariant = 0;
|
||||
QByteArray splash;
|
||||
uint splashOffset;
|
||||
uint splashSize;
|
||||
uint splashWidth;
|
||||
uint splashHeight;
|
||||
QImage::Format splash_format;
|
||||
bool isValidFlag;
|
||||
};
|
||||
uint splashOffset = 0;
|
||||
uint splashSize = 0;
|
||||
uint splashWidth = 0;
|
||||
uint splashHeight = 0;
|
||||
QImage::Format splashFormat;
|
||||
bool isValidFlag = false;
|
||||
FirmwareType type;
|
||||
|
||||
#endif // _FIRMWAREINTERFACE_H_
|
||||
void initFlash(const QByteArray& flashData);
|
||||
QString seekString(const QString & string);
|
||||
QString seekLabel(const QString & label);
|
||||
void seekSplash();
|
||||
bool seekSplash(QByteArray sps, QByteArray spe, int size);
|
||||
bool seekSplash(QByteArray splash);
|
||||
};
|
||||
|
||||
@@ -32173,9 +32173,8 @@ QCPPolarAxisRadial::SelectablePart QCPPolarAxisRadial::getPartAt(const QPointF &
|
||||
return spTickLabels;
|
||||
else if (mAxisPainter->labelSelectionBox().contains(pos.toPoint()))
|
||||
return spAxisLabel;
|
||||
else
|
||||
return spNone;
|
||||
*/
|
||||
else */
|
||||
return spNone;
|
||||
}
|
||||
|
||||
/* inherits documentation from base class */
|
||||
@@ -32994,8 +32993,10 @@ QCPPolarAxisAngular::SelectablePart QCPPolarAxisAngular::getPartAt(const QPointF
|
||||
return spTickLabels;
|
||||
else if (mAxisPainter->labelSelectionBox().contains(pos.toPoint()))
|
||||
return spAxisLabel;
|
||||
else */
|
||||
else
|
||||
return spNone;
|
||||
*/
|
||||
return spNone; // until TODO fix
|
||||
}
|
||||
|
||||
/* inherits documentation from base class */
|
||||
|
||||
@@ -50,6 +50,7 @@ add_library(${PROJECT_NAME}
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${CPN_COMMON_LIB}
|
||||
${RS_DFU_LIBRARIES}
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
@@ -58,4 +59,5 @@ target_include_directories(${PROJECT_NAME}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
PUBLIC
|
||||
"${CMAKE_CURRENT_LIST_DIR}"
|
||||
"${RS_DFU_INCLUDE_DIRS}"
|
||||
)
|
||||
|
||||
@@ -24,11 +24,14 @@
|
||||
#include "appdata.h"
|
||||
#include "eeprominterface.h"
|
||||
#include "flashfirmwaredialog.h"
|
||||
#include "firmwareinterface.h"
|
||||
#include "radiointerface.h"
|
||||
|
||||
// these must match text strings in server response
|
||||
constexpr char CLOUD_BUILD_WAITING[] {"WAITING_FOR_BUILD"};
|
||||
constexpr char CLOUD_BUILD_IN_PROGRESS[] {"BUILD_IN_PROGRESS"};
|
||||
constexpr char CLOUD_BUILD_SUCCESS[] {"BUILD_SUCCESS"};
|
||||
constexpr char CLOUD_BUILD_ERROR[] {"BUILD_ERROR"};
|
||||
|
||||
UpdateCloudBuild::UpdateCloudBuild(QWidget * parent) :
|
||||
UpdateInterface(parent, CID_CloudBuild, tr("CloudBuild"), Repo::REPO_TYPE_BUILD,
|
||||
@@ -75,6 +78,8 @@ int UpdateCloudBuild::cloudStatusToInt(const QString status)
|
||||
return STATUS_IN_PROGRESS;
|
||||
else if (status == QString(CLOUD_BUILD_SUCCESS))
|
||||
return STATUS_SUCCESS;
|
||||
else if (status == QString(CLOUD_BUILD_ERROR))
|
||||
return STATUS_ERROR;
|
||||
else
|
||||
return STATUS_UNKNOWN;
|
||||
}
|
||||
@@ -95,7 +100,7 @@ void UpdateCloudBuild::assetSettingsInit()
|
||||
cad.filter("%FWFLAVOUR%");
|
||||
cad.destSubDir("FIRMWARE");
|
||||
cad.copyFilterType(UpdateParameters::UFT_Pattern);
|
||||
cad.copyFilter("^%FWFLAVOUR%-%LANGUAGE%.*-%RELEASE%\\.bin$");
|
||||
cad.copyFilter("^%FWFLAVOUR%-%LANGUAGE%.*-%RELEASE%\\.(bin|uf2)$");
|
||||
cad.maxExpected(1);
|
||||
|
||||
qDebug() << "Asset settings initialised";
|
||||
@@ -210,6 +215,22 @@ int UpdateCloudBuild::asyncInstall()
|
||||
|
||||
int ret = QMessageBox::question(status()->progress(), CPN_STR_APP_NAME, tr("Write the updated firmware to the radio now ?"), QMessageBox::Yes | QMessageBox::No);
|
||||
if (ret == QMessageBox::Yes) {
|
||||
QString extn(QFileInfo(destPath).suffix().toLower());
|
||||
QString bootmodes;
|
||||
if (dfuFileExtensions().contains(extn))
|
||||
bootmodes.append("DFU");
|
||||
|
||||
if (uf2FileExtensions().contains(extn)) {
|
||||
if (!bootmodes.isEmpty()) {
|
||||
bootmodes.append(tr(" or "));
|
||||
}
|
||||
bootmodes.append("UF2");
|
||||
}
|
||||
|
||||
QMessageBox::warning(status()->progress(), tr("Write Firmware to Radio"),
|
||||
tr("Before continuing, ensure the radio is connected and booted in %1 mode(s)")
|
||||
.arg(bootmodes));
|
||||
|
||||
FlashFirmwareDialog *dlg = new FlashFirmwareDialog(this);
|
||||
dlg->exec();
|
||||
dlg->deleteLater();
|
||||
@@ -398,6 +419,44 @@ void UpdateCloudBuild::cleanup()
|
||||
m_eventLoop.quit();
|
||||
}
|
||||
|
||||
bool UpdateCloudBuild::downloadFlaggedAsset(const int row)
|
||||
{
|
||||
if (!UpdateInterface::downloadFlaggedAsset(row))
|
||||
return false;
|
||||
|
||||
// rename downloaded firmware file based on the file contents
|
||||
// flashing processes use the file extension to decide on
|
||||
// the flashing mode i.e. DFU or UF2
|
||||
QString path = QString("%1/A%2/%3").arg(downloadDir()).arg(repo()->assets()->id()).arg(repo()->assets()->downloadName());
|
||||
status()->reportProgress(tr("Renaming: %1").arg(path), QtDebugMsg);
|
||||
|
||||
FirmwareInterface firmware(path);
|
||||
if (firmware.isValid()) {
|
||||
QFileInfo fi(path);
|
||||
QString newfname = QString("%1/%2.%3").arg(fi.absoluteDir().path()).arg(fi.completeBaseName()).arg(firmware.typeFileExtn());
|
||||
|
||||
if (QFileInfo::exists(newfname) && !QFile(newfname).remove()) {
|
||||
status()->reportProgress(tr("Unable to delete: %1").arg(newfname), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile fw(path);
|
||||
if (!fw.rename(newfname)) {
|
||||
status()->reportProgress(tr("Unable to rename %1 to %2").arg(fw.fileName()).arg(newfname), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo newfi(fw);
|
||||
repo()->assets()->setDownloadName(newfi.fileName());
|
||||
status()->reportProgress(tr("Renamed: %1").arg(newfi.fileName()), QtInfoMsg);
|
||||
} else {
|
||||
status()->reportProgress(tr("%1 is not a valid firmware file").arg(path), QtCriticalMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UpdateCloudBuild::getStatus()
|
||||
{
|
||||
m_jobStatus = STATUS_UNKNOWN;
|
||||
@@ -438,8 +497,9 @@ bool UpdateCloudBuild::objectExists(const QJsonObject & parent, const QString ch
|
||||
|
||||
bool UpdateCloudBuild::setAssetDownload()
|
||||
{
|
||||
// this format MUST align with the asset copy filter
|
||||
QString name = QString("%1-%2%3-%4.bin").arg(m_radio).arg(params()->language.toLower()).arg(m_buildFlags/* has a leading hyphen*/).arg(repo()->releases()->name());
|
||||
// Note: this format MUST align with the asset copy filter
|
||||
// the file is renamed post download to amend the extension
|
||||
QString name = QString("%1-%2%3-%4.tmp").arg(m_radio).arg(params()->language.toLower()).arg(m_buildFlags/* has a leading hyphen*/).arg(repo()->releases()->name());
|
||||
|
||||
repo()->assets()->setDownloadName(name.toLower());
|
||||
|
||||
@@ -454,6 +514,7 @@ bool UpdateCloudBuild::setAssetDownload()
|
||||
if (artifacts[i].isObject()) {
|
||||
const QJsonObject &artifact = artifacts[i].toObject();
|
||||
if (stringExists(artifact, "slug") && artifact.value("slug").toString() == "firmware") {
|
||||
//qDebug() << artifact;
|
||||
if (stringExists(artifact, "download_url")) {
|
||||
repo()->assets()->setDownloadUrl(artifact.value("download_url").toString());
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ class UpdateCloudBuild: public UpdateInterface
|
||||
int asyncInstall() override;
|
||||
void assetSettingsInit() override;
|
||||
bool buildFlaggedAsset(const int row) override;
|
||||
bool downloadFlaggedAsset(const int row) override;
|
||||
|
||||
private slots:
|
||||
void cancel();
|
||||
|
||||