more OsmoSDR DFU upgrade stuff
This commit is contained in:
parent
a9f47efde6
commit
8cd4485471
|
@ -12,10 +12,12 @@ find_package(OpenGL REQUIRED)
|
||||||
find_package(PkgConfig)
|
find_package(PkgConfig)
|
||||||
find_package(LibOsmoSDR REQUIRED)
|
find_package(LibOsmoSDR REQUIRED)
|
||||||
find_package(Portaudio REQUIRED)
|
find_package(Portaudio REQUIRED)
|
||||||
|
find_package(LibUSB REQUIRED)
|
||||||
|
|
||||||
set(sdrangelove_SOURCES
|
set(sdrangelove_SOURCES
|
||||||
main.cpp
|
main.cpp
|
||||||
mainwindow.cpp
|
mainwindow.cpp
|
||||||
|
miniz.cpp
|
||||||
osdrupgrade.cpp
|
osdrupgrade.cpp
|
||||||
settings.cpp
|
settings.cpp
|
||||||
|
|
||||||
|
@ -97,6 +99,7 @@ include_directories(
|
||||||
${OPENGL_INCLUDE_DIR}
|
${OPENGL_INCLUDE_DIR}
|
||||||
${LIBOSMOSDR_INCLUDE_DIR}
|
${LIBOSMOSDR_INCLUDE_DIR}
|
||||||
${PORTAUDIO_INCLUDE_DIRS}
|
${PORTAUDIO_INCLUDE_DIRS}
|
||||||
|
${LIBUSB_INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
include(${QT_USE_FILE})
|
include(${QT_USE_FILE})
|
||||||
|
@ -120,4 +123,5 @@ target_link_libraries(sdrangelove
|
||||||
${OPENGL_LIBRARIES}
|
${OPENGL_LIBRARIES}
|
||||||
${LIBOSMOSDR_LIBRARIES}
|
${LIBOSMOSDR_LIBRARIES}
|
||||||
${PORTAUDIO_LIBRARIES}
|
${PORTAUDIO_LIBRARIES}
|
||||||
|
${LIBUSB_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
|
@ -945,6 +945,9 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>OsmoSDR &Firmware Upgrade...</string>
|
<string>OsmoSDR &Firmware Upgrade...</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Shift+U</string>
|
||||||
|
</property>
|
||||||
</action>
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
|
|
518
osdrupgrade.cpp
518
osdrupgrade.cpp
|
@ -1,14 +1,530 @@
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QCursor>
|
||||||
|
#include <QThread>
|
||||||
|
#include <libusb.h>
|
||||||
#include "osdrupgrade.h"
|
#include "osdrupgrade.h"
|
||||||
#include "ui_osdrupgrade.h"
|
#include "ui_osdrupgrade.h"
|
||||||
|
|
||||||
|
#define MINIZ_HEADER_FILE_ONLY
|
||||||
|
#include "miniz.cpp"
|
||||||
|
|
||||||
|
#define OSMOSDR_USB_VID 0x16c0
|
||||||
|
#define OSMOSDR_USB_PID 0x0763
|
||||||
|
|
||||||
|
// DFU commands
|
||||||
|
#define DFU_DETACH 0x00
|
||||||
|
#define DFU_DNLOAD 0x01
|
||||||
|
#define DFU_UPLOAD 0x02
|
||||||
|
#define DFU_GETSTATUS 0x03
|
||||||
|
#define DFU_CLRSTATUS 0x04
|
||||||
|
#define DFU_GETSTATE 0x05
|
||||||
|
#define DFU_ABORT 0x06
|
||||||
|
|
||||||
|
// DFU states
|
||||||
|
#define ST_appIDLE 0
|
||||||
|
#define ST_appDETACH 1
|
||||||
|
#define ST_dfuIDLE 2
|
||||||
|
#define ST_dfuDNLOAD_SYNC 3
|
||||||
|
#define ST_dfuDNBUSY 4
|
||||||
|
#define ST_dfuDNLOAD_IDLE 5
|
||||||
|
#define ST_dfuMANIFEST_SYNC 6
|
||||||
|
#define ST_dfuMANIFEST 7
|
||||||
|
#define ST_dfuMANIFEST_WAIT_RST 8
|
||||||
|
#define ST_dfuUPLOAD_IDLE 9
|
||||||
|
#define ST_dfuERROR 10
|
||||||
|
|
||||||
|
#define DFU_PACKETSIZE 512
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct dfu_getstatus {
|
||||||
|
quint8 bStatus;
|
||||||
|
quint8 bwPollTimeout[3];
|
||||||
|
quint8 bState;
|
||||||
|
quint8 iString;
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
|
||||||
OSDRUpgrade::OSDRUpgrade(QWidget* parent) :
|
OSDRUpgrade::OSDRUpgrade(QWidget* parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
ui(new Ui::OSDRUpgrade)
|
ui(new Ui::OSDRUpgrade),
|
||||||
|
m_usb(NULL)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
connect(&m_searchDeviceTimer, SIGNAL(timeout()), this, SLOT(searchDeviceTick()));
|
||||||
}
|
}
|
||||||
|
|
||||||
OSDRUpgrade::~OSDRUpgrade()
|
OSDRUpgrade::~OSDRUpgrade()
|
||||||
{
|
{
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OSDRUpgrade::on_browse_clicked()
|
||||||
|
{
|
||||||
|
QString filename = QFileDialog::getOpenFileName(this, tr("OsmoSDR Firmware File"), QString(), tr("OsmoSDR Firmware (*.ofw);;All Files (*)"));
|
||||||
|
if(filename.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QFile file(filename);
|
||||||
|
if(file.size() > 10 * 1024 * 1024) {
|
||||||
|
QMessageBox::critical(this, tr("File Open Error"), tr("File is too big to be a firmware update for OsmoSDR."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray dfuApp;
|
||||||
|
QByteArray radioApp;
|
||||||
|
QByteArray fpgaBin;
|
||||||
|
mz_zip_archive zip;
|
||||||
|
memset(&zip, 0x00, sizeof(zip));
|
||||||
|
|
||||||
|
if(!mz_zip_reader_init_file(&zip, qPrintable(filename), 0)) {
|
||||||
|
mz_zip_reader_end(&zip);
|
||||||
|
QMessageBox::critical(this, tr("File Open Error"), tr("File is not a valid OsmoSDR update."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dfuAppIndex = mz_zip_reader_locate_file(&zip, "dfuapp.bin", NULL, 0);
|
||||||
|
int radioAppIndex = mz_zip_reader_locate_file(&zip, "radioapp.bin", NULL, 0);
|
||||||
|
int fpgaIndex = mz_zip_reader_locate_file(&zip, "fpga.bin", NULL, 0);
|
||||||
|
|
||||||
|
if((dfuAppIndex < 0) && (radioAppIndex < 0) && (fpgaIndex < 0)) {
|
||||||
|
mz_zip_reader_end(&zip);
|
||||||
|
QMessageBox::critical(this, tr("File Open Error"), tr("File is not a valid OsmoSDR update."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mz_zip_reader_extract_to_callback(&zip, dfuAppIndex, zipHelper, &dfuApp, 0)) {
|
||||||
|
mz_zip_reader_end(&zip);
|
||||||
|
QMessageBox::critical(this, tr("File Open Error"), tr("File is not a valid OsmoSDR update."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mz_zip_reader_extract_to_callback(&zip, radioAppIndex, zipHelper, &radioApp, 0)) {
|
||||||
|
mz_zip_reader_end(&zip);
|
||||||
|
QMessageBox::critical(this, tr("File Open Error"), tr("File is not a valid OsmoSDR update."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mz_zip_reader_extract_to_callback(&zip, fpgaIndex, zipHelper, &fpgaBin, 0)) {
|
||||||
|
mz_zip_reader_end(&zip);
|
||||||
|
QMessageBox::critical(this, tr("File Open Error"), tr("File is not a valid OsmoSDR update."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mz_zip_reader_end(&zip);
|
||||||
|
m_dfuApp = dfuApp;
|
||||||
|
m_radioApp = radioApp;
|
||||||
|
m_fpgaBin = fpgaBin;
|
||||||
|
|
||||||
|
if(dfuAppIndex >= 0) {
|
||||||
|
ui->dfu->setEnabled(true);
|
||||||
|
ui->dfuSize->setText(tr("%1").arg(m_dfuApp.size()));
|
||||||
|
} else {
|
||||||
|
ui->dfu->setEnabled(false);
|
||||||
|
ui->dfuSize->setText(tr("-"));
|
||||||
|
}
|
||||||
|
if(radioAppIndex >= 0) {
|
||||||
|
ui->radio->setEnabled(true);
|
||||||
|
ui->radioSize->setText(tr("%1").arg(m_radioApp.size()));
|
||||||
|
} else {
|
||||||
|
ui->radio->setEnabled(false);
|
||||||
|
ui->dfuSize->setText(tr("-"));
|
||||||
|
}
|
||||||
|
if(fpgaIndex >= 0) {
|
||||||
|
ui->fpga->setEnabled(true);
|
||||||
|
ui->fpgaSize->setText(tr("%1").arg(m_fpgaBin.size()));
|
||||||
|
} else {
|
||||||
|
ui->fpga->setEnabled(false);
|
||||||
|
ui->fpgaSize->setText(tr("-"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if((dfuAppIndex >= 0) && (radioAppIndex < 0) && (fpgaIndex < 0)) {
|
||||||
|
ui->dfu->setChecked(true);
|
||||||
|
ui->radio->setChecked(false);
|
||||||
|
ui->fpga->setChecked(false);
|
||||||
|
} else {
|
||||||
|
ui->dfu->setChecked(false);
|
||||||
|
ui->radio->setChecked(radioAppIndex >= 0);
|
||||||
|
ui->fpga->setChecked(fpgaIndex >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->fwBox->setEnabled(true);
|
||||||
|
ui->progressBox->setEnabled(true);
|
||||||
|
|
||||||
|
QFileInfo fi(file.fileName());
|
||||||
|
ui->filename->setText(fi.fileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
void OSDRUpgrade::on_dfu_toggled(bool checked)
|
||||||
|
{
|
||||||
|
updateFlashButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OSDRUpgrade::on_radio_toggled(bool checked)
|
||||||
|
{
|
||||||
|
updateFlashButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OSDRUpgrade::on_fpga_toggled(bool checked)
|
||||||
|
{
|
||||||
|
updateFlashButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OSDRUpgrade::updateFlashButton()
|
||||||
|
{
|
||||||
|
if(ui->dfu->isChecked() || ui->radio->isChecked() || ui->fpga->isChecked())
|
||||||
|
ui->progressBox->setEnabled(true);
|
||||||
|
else ui->progressBox->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OSDRUpgrade::on_start_clicked()
|
||||||
|
{
|
||||||
|
ui->close->setEnabled(false);
|
||||||
|
ui->start->setEnabled(false);
|
||||||
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
|
|
||||||
|
ui->log->clear();
|
||||||
|
log(tr("Starting flash operation..."));
|
||||||
|
|
||||||
|
if(libusb_init(&m_usb) < 0) {
|
||||||
|
fail(tr("Could not initialize libusb."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switchToDFU();
|
||||||
|
|
||||||
|
m_searchTries = 0;
|
||||||
|
m_searchDeviceTimer.start(250);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OSDRUpgrade::searchDeviceTick()
|
||||||
|
{
|
||||||
|
m_searchTries++;
|
||||||
|
log(tr("Searching device (try %1)").arg(m_searchTries));
|
||||||
|
|
||||||
|
libusb_device_handle* device = libusb_open_device_with_vid_pid(m_usb, OSMOSDR_USB_VID, OSMOSDR_USB_PID);
|
||||||
|
if(device == NULL) {
|
||||||
|
if(m_searchTries >= 10) {
|
||||||
|
m_searchDeviceTimer.stop();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_searchDeviceTimer.stop();
|
||||||
|
|
||||||
|
libusb_device_descriptor deviceDescriptor;
|
||||||
|
|
||||||
|
if(libusb_get_descriptor(device, LIBUSB_DT_DEVICE, 0, (unsigned char*)&deviceDescriptor, sizeof(deviceDescriptor)) < 0) {
|
||||||
|
libusb_close(device);
|
||||||
|
fail(tr("Could not read device descriptor."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char sn[64];
|
||||||
|
memset(sn, 0x00, sizeof(sn));
|
||||||
|
libusb_get_string_descriptor_ascii(device, deviceDescriptor.iSerialNumber, (unsigned char*)sn, sizeof(sn));
|
||||||
|
sn[sizeof(sn) - 1] = '\0';
|
||||||
|
|
||||||
|
log(tr("OsmoSDR found (SN %1)").arg(sn));
|
||||||
|
|
||||||
|
quint8 buffer[255];
|
||||||
|
if(libusb_get_descriptor(device, LIBUSB_DT_CONFIG, 0, buffer, sizeof(buffer)) < 16) {
|
||||||
|
libusb_close(device);
|
||||||
|
fail(tr("Could not get a configuration descriptor"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(buffer[15] != 1) {
|
||||||
|
libusb_close(device);
|
||||||
|
fail(tr("Device not in DFU mode as it should be"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint8 state;
|
||||||
|
|
||||||
|
if(dfuGetState(device, &state) < 0) {
|
||||||
|
libusb_reset_device(device);
|
||||||
|
if(dfuGetState(device, &state) < 0) {
|
||||||
|
libusb_close(device);
|
||||||
|
fail(tr("Cannot get device DFU state"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if((state != ST_dfuIDLE) && (state != ST_dfuDNLOAD_IDLE)) {
|
||||||
|
dfuGetStatus(device);
|
||||||
|
libusb_close(device);
|
||||||
|
fail(tr("Device is not in dfuIDLE or dfuDNLOAD_IDLE state"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(libusb_claim_interface(device, 0) < 0) {
|
||||||
|
libusb_close(device);
|
||||||
|
fail(tr("Could not claim interface"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray* image;
|
||||||
|
int altSetting;
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
if(ui->dfu->isChecked()) {
|
||||||
|
log(tr("Starting download of DFU application"));
|
||||||
|
image = &m_dfuApp;
|
||||||
|
altSetting = 1;
|
||||||
|
} else if(ui->radio->isChecked()) {
|
||||||
|
log(tr("Starting download of radio application"));
|
||||||
|
image = &m_radioApp;
|
||||||
|
altSetting = 0;
|
||||||
|
} else if(ui->fpga->isChecked()) {
|
||||||
|
log(tr("Starting download of FPGA image"));
|
||||||
|
image = &m_fpgaBin;
|
||||||
|
altSetting = 2;
|
||||||
|
} else {
|
||||||
|
log(tr("Switching back to radio application mode"));
|
||||||
|
dfuDetach(device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(libusb_set_interface_alt_setting(device, 0, altSetting) < 0) {
|
||||||
|
libusb_close(device);
|
||||||
|
fail(tr("Could not set alternate interface setting to %1").arg(altSetting));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->progress->setMaximum((image->size() / DFU_PACKETSIZE) + ((image->size() % DFU_PACKETSIZE) ? 1 : 0));
|
||||||
|
|
||||||
|
int blocknum = 0;
|
||||||
|
while((state == ST_dfuIDLE) || (state == ST_dfuDNLOAD_IDLE)) {
|
||||||
|
int offset = blocknum * DFU_PACKETSIZE;
|
||||||
|
int blocklen = (int)image->size() - offset;
|
||||||
|
if(blocklen < 0)
|
||||||
|
blocklen = 0;
|
||||||
|
if(blocklen > DFU_PACKETSIZE)
|
||||||
|
blocklen = DFU_PACKETSIZE;
|
||||||
|
if(dfuDownloadBlock(device, blocknum, (const quint8*)(image->data() + offset), blocklen) < 0) {
|
||||||
|
if(dfuGetState(device, &state) < 0) {
|
||||||
|
if(ui->dfu->isChecked())
|
||||||
|
break;
|
||||||
|
libusb_close(device);
|
||||||
|
fail(tr("Cannot get device DFU state"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dfuGetStatus(device);
|
||||||
|
libusb_close(device);
|
||||||
|
fail(tr("Error downloading block %1").arg(blocknum));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dfuGetStatus(device);
|
||||||
|
if(blocklen == 0)
|
||||||
|
break;
|
||||||
|
blocknum++;
|
||||||
|
ui->progress->setValue(blocknum);
|
||||||
|
QApplication::processEvents();
|
||||||
|
}
|
||||||
|
log(tr("Download complete (state %1)").arg(state));
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(dfuGetState(device, &state) < 0) {
|
||||||
|
if(ui->dfu->isChecked()) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
libusb_close(device);
|
||||||
|
fail(tr("Cannot get device DFU state"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dfuGetStatus(device);
|
||||||
|
} while(state == ST_dfuMANIFEST);
|
||||||
|
|
||||||
|
if(ui->dfu->isChecked()) {
|
||||||
|
ui->dfu->setChecked(false);
|
||||||
|
m_searchTries = 0;
|
||||||
|
m_searchDeviceTimer.start(250);
|
||||||
|
libusb_close(device);
|
||||||
|
return;
|
||||||
|
} else if(ui->radio->isChecked()) {
|
||||||
|
ui->radio->setChecked(false);
|
||||||
|
} else if(ui->fpga->isChecked()) {
|
||||||
|
ui->fpga->setChecked(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
QApplication::processEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
log(tr("Upgrade finished without error"));
|
||||||
|
libusb_close(device);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OSDRUpgrade::switchToDFU()
|
||||||
|
{
|
||||||
|
libusb_device_handle* device = libusb_open_device_with_vid_pid(m_usb, OSMOSDR_USB_VID, OSMOSDR_USB_PID);
|
||||||
|
if(device == NULL) {
|
||||||
|
log(tr("No OsmoSDR VID:PID %1:%2 found").arg(OSMOSDR_USB_VID, 4, 16, QChar('0')).arg(OSMOSDR_USB_PID, 4, 16, QChar('0')));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint8 buffer[255];
|
||||||
|
if(libusb_get_descriptor(device, LIBUSB_DT_CONFIG, 0, buffer, sizeof(buffer)) < 16) {
|
||||||
|
log(tr("Could not get a valid configuration descriptor"));
|
||||||
|
libusb_close(device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(buffer[15] != 1) {
|
||||||
|
if(libusb_claim_interface(device, 0) < 0) {
|
||||||
|
log(tr("Could not claim interface"));
|
||||||
|
libusb_close(device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(tr("Switching device to DFU mode"));
|
||||||
|
libusb_control_transfer(device, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, 0x07, 0x0003, 0, NULL, 0, 50);
|
||||||
|
libusb_release_interface(device, 0);
|
||||||
|
} else {
|
||||||
|
log(tr("Device is already in DFU mode"));
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_close(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
int OSDRUpgrade::dfuGetState(libusb_device_handle* device, quint8* state)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = libusb_control_transfer(
|
||||||
|
device,
|
||||||
|
0xa1,
|
||||||
|
DFU_GETSTATE,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
(unsigned char*)state,
|
||||||
|
1,
|
||||||
|
1000);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if(res >= 0)
|
||||||
|
fprintf(stderr, "AT91 now in state %s (%d)\n", statedesc[*state], *state);
|
||||||
|
*/
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OSDRUpgrade::dfuGetStatus(libusb_device_handle* device)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
struct dfu_getstatus getstatus;
|
||||||
|
/*
|
||||||
|
static const char* statedesc[] = {
|
||||||
|
"appIDLE",
|
||||||
|
"appDETACH",
|
||||||
|
"dfuIDLE",
|
||||||
|
"dfuDNLOAD-SYNC",
|
||||||
|
"dfuDNBUSY",
|
||||||
|
"dfuDNLOAD-IDLE",
|
||||||
|
"dfuMANIFEST-SYNC",
|
||||||
|
"dfuMANIFEST",
|
||||||
|
"dfuMANIFEST-WAIT-RESET",
|
||||||
|
"dfuUPLOAD-IDLE",
|
||||||
|
"dfuERROR"
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
res = libusb_control_transfer(
|
||||||
|
device,
|
||||||
|
0xa1,
|
||||||
|
DFU_GETSTATUS,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
(unsigned char*)&getstatus,
|
||||||
|
sizeof(getstatus),
|
||||||
|
1000);
|
||||||
|
/*
|
||||||
|
if(res >= 0)
|
||||||
|
log(tr("OsmoSDR bStatus: %1, bState: %2 (%3)").arg(getstatus.bStatus).arg(statedesc[getstatus.bState]).arg(getstatus.bState));
|
||||||
|
*/
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OSDRUpgrade::dfuClrStatus(libusb_device_handle* device)
|
||||||
|
{
|
||||||
|
return libusb_control_transfer(
|
||||||
|
device,
|
||||||
|
0x21,
|
||||||
|
DFU_CLRSTATUS,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int OSDRUpgrade::dfuDownloadBlock(libusb_device_handle* device, quint16 block, const quint8* data, quint16 len)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
fprintf(stderr, "downloading block %d (%d bytes)\n", block, len);
|
||||||
|
*/
|
||||||
|
|
||||||
|
return libusb_control_transfer(
|
||||||
|
device,
|
||||||
|
0x21,
|
||||||
|
DFU_DNLOAD,
|
||||||
|
block,
|
||||||
|
0,
|
||||||
|
(unsigned char*)data,
|
||||||
|
len,
|
||||||
|
10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int OSDRUpgrade::dfuDetach(libusb_device_handle* device)
|
||||||
|
{
|
||||||
|
return libusb_control_transfer(
|
||||||
|
device,
|
||||||
|
0x21,
|
||||||
|
DFU_DETACH,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OSDRUpgrade::fail(const QString& msg)
|
||||||
|
{
|
||||||
|
log(tr("Fatal error: %1").arg(msg));
|
||||||
|
QMessageBox::critical(this, tr("OsmoSDR Upgrade Failed"), msg);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OSDRUpgrade::finish()
|
||||||
|
{
|
||||||
|
if(m_usb != NULL) {
|
||||||
|
libusb_exit(m_usb);
|
||||||
|
m_usb = NULL;
|
||||||
|
}
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
ui->start->setEnabled(true);
|
||||||
|
ui->close->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OSDRUpgrade::log(const QString& msg)
|
||||||
|
{
|
||||||
|
ui->log->appendPlainText(msg);
|
||||||
|
ui->log->moveCursor(QTextCursor::End);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OSDRUpgrade::reject()
|
||||||
|
{
|
||||||
|
if(ui->close->isEnabled())
|
||||||
|
return QDialog::reject();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t OSDRUpgrade::zipHelper(void* pOpaque, quint64 file_ofs, const void* pBuf, size_t n)
|
||||||
|
{
|
||||||
|
QByteArray* bytes = (QByteArray*)pOpaque;
|
||||||
|
bytes->append((const char*)pBuf, n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
#define INCLUDE_OSDRUPGRADE_H
|
#define INCLUDE_OSDRUPGRADE_H
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
typedef struct libusb_context libusb_context;
|
||||||
|
typedef struct libusb_device_handle libusb_device_handle;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class OSDRUpgrade;
|
class OSDRUpgrade;
|
||||||
|
@ -14,8 +18,42 @@ public:
|
||||||
explicit OSDRUpgrade(QWidget* parent = NULL);
|
explicit OSDRUpgrade(QWidget* parent = NULL);
|
||||||
~OSDRUpgrade();
|
~OSDRUpgrade();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_browse_clicked();
|
||||||
|
void on_dfu_toggled(bool checked);
|
||||||
|
void on_radio_toggled(bool checked);
|
||||||
|
void on_fpga_toggled(bool checked);
|
||||||
|
void on_start_clicked();
|
||||||
|
void searchDeviceTick();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::OSDRUpgrade* ui;
|
Ui::OSDRUpgrade* ui;
|
||||||
|
|
||||||
|
libusb_context* m_usb;
|
||||||
|
|
||||||
|
QByteArray m_dfuApp;
|
||||||
|
QByteArray m_radioApp;
|
||||||
|
QByteArray m_fpgaBin;
|
||||||
|
|
||||||
|
int m_searchTries;
|
||||||
|
QTimer m_searchDeviceTimer;
|
||||||
|
|
||||||
|
void updateFlashButton();
|
||||||
|
|
||||||
|
void switchToDFU();
|
||||||
|
int dfuGetState(libusb_device_handle* device, quint8* state);
|
||||||
|
int dfuGetStatus(libusb_device_handle* device);
|
||||||
|
int dfuClrStatus(libusb_device_handle* device);
|
||||||
|
int dfuDownloadBlock(libusb_device_handle* device, quint16 block, const quint8* data, quint16 len);
|
||||||
|
int dfuDetach(libusb_device_handle* device);
|
||||||
|
|
||||||
|
void fail(const QString& msg);
|
||||||
|
void finish();
|
||||||
|
void log(const QString& msg);
|
||||||
|
|
||||||
|
void reject();
|
||||||
|
|
||||||
|
static size_t zipHelper(void* pOpaque, quint64 file_ofs, const void* pBuf, size_t n);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_OSDRUPGRADE_H
|
#endif // INCLUDE_OSDRUPGRADE_H
|
||||||
|
|
137
osdrupgrade.ui
137
osdrupgrade.ui
|
@ -6,8 +6,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>324</width>
|
<width>382</width>
|
||||||
<height>250</height>
|
<height>503</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -26,14 +26,23 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="filename">
|
<widget class="QLabel" name="filename">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>256</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>Qt::PlainText</enum>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -47,29 +56,31 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox_2">
|
<widget class="QGroupBox" name="fwBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Firmware</string>
|
<string>Firmware</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="2" column="0">
|
<item row="2" column="1">
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="radioSize">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Radio App</string>
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="3" column="1">
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="fpgaSize">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>FPGA Image</string>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
<property name="alignment">
|
||||||
</item>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>DFU App</string>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -78,19 +89,76 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Size</string>
|
<string>Size</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
<property name="alignment">
|
||||||
</item>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
<item row="0" column="2">
|
|
||||||
<widget class="QLabel" name="label_5">
|
|
||||||
<property name="text">
|
|
||||||
<string>Signed</string>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1" colspan="2">
|
<item row="1" column="0">
|
||||||
<widget class="QPushButton" name="flash">
|
<widget class="QCheckBox" name="dfu">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Flash!</string>
|
<string>DFU Application</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QCheckBox" name="radio">
|
||||||
|
<property name="text">
|
||||||
|
<string>Radio Application</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QCheckBox" name="fpga">
|
||||||
|
<property name="text">
|
||||||
|
<string>FPGA Image</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="dfuSize">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="progressBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Progress</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QProgressBar" name="progress">
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="start">
|
||||||
|
<property name="text">
|
||||||
|
<string>Flash!</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPlainTextEdit" name="log">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -124,5 +192,22 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>close</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>OSDRUpgrade</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>331</x>
|
||||||
|
<y>247</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>190</x>
|
||||||
|
<y>134</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
</ui>
|
</ui>
|
||||||
|
|
Loading…
Reference in New Issue