mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-04 05:30:32 -05:00 
			
		
		
		
	
		
			
	
	
		
			519 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			519 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								#include <QFileDialog>
							 | 
						||
| 
								 | 
							
								#include <QMessageBox>
							 | 
						||
| 
								 | 
							
								#include <QCursor>
							 | 
						||
| 
								 | 
							
								#include <QThread>
							 | 
						||
| 
								 | 
							
								#include <libusb.h>
							 | 
						||
| 
								 | 
							
								#include "osmosdrupgrade.h"
							 | 
						||
| 
								 | 
							
								#include "ui_osmosdrupgrade.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#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)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								OsmoSDRUpgrade::OsmoSDRUpgrade(QWidget* parent) :
							 | 
						||
| 
								 | 
							
									QDialog(parent),
							 | 
						||
| 
								 | 
							
									ui(new Ui::OsmoSDRUpgrade),
							 | 
						||
| 
								 | 
							
									m_usb(NULL)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									ui->setupUi(this);
							 | 
						||
| 
								 | 
							
									connect(&m_searchDeviceTimer, SIGNAL(timeout()), this, SLOT(searchDeviceTick()));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								OsmoSDRUpgrade::~OsmoSDRUpgrade()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									delete ui;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void OsmoSDRUpgrade::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 OsmoSDRUpgrade::on_dfu_toggled(bool checked)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									updateFlashButton();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void OsmoSDRUpgrade::on_radio_toggled(bool checked)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									updateFlashButton();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void OsmoSDRUpgrade::on_fpga_toggled(bool checked)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									updateFlashButton();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void OsmoSDRUpgrade::updateFlashButton()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if(ui->dfu->isChecked() || ui->radio->isChecked() || ui->fpga->isChecked())
							 | 
						||
| 
								 | 
							
										ui->progressBox->setEnabled(true);
							 | 
						||
| 
								 | 
							
									else ui->progressBox->setEnabled(false);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void OsmoSDRUpgrade::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 OsmoSDRUpgrade::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 successfully"));
							 | 
						||
| 
								 | 
							
									libusb_close(device);
							 | 
						||
| 
								 | 
							
									finish();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void OsmoSDRUpgrade::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 OsmoSDRUpgrade::dfuGetState(libusb_device_handle* device, quint8* state)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int res;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									res = libusb_control_transfer(
							 | 
						||
| 
								 | 
							
										device,
							 | 
						||
| 
								 | 
							
										0xa1,
							 | 
						||
| 
								 | 
							
										DFU_GETSTATE,
							 | 
						||
| 
								 | 
							
										0,
							 | 
						||
| 
								 | 
							
										0,
							 | 
						||
| 
								 | 
							
										(unsigned char*)state,
							 | 
						||
| 
								 | 
							
										1,
							 | 
						||
| 
								 | 
							
										1000);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return res;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int OsmoSDRUpgrade::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 OsmoSDRUpgrade::dfuClrStatus(libusb_device_handle* device)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return libusb_control_transfer(
							 | 
						||
| 
								 | 
							
										device,
							 | 
						||
| 
								 | 
							
										0x21,
							 | 
						||
| 
								 | 
							
										DFU_CLRSTATUS,
							 | 
						||
| 
								 | 
							
										0,
							 | 
						||
| 
								 | 
							
										0,
							 | 
						||
| 
								 | 
							
										NULL,
							 | 
						||
| 
								 | 
							
										0,
							 | 
						||
| 
								 | 
							
										1000);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int OsmoSDRUpgrade::dfuDownloadBlock(libusb_device_handle* device, quint16 block, const quint8* data, quint16 len)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return libusb_control_transfer(
							 | 
						||
| 
								 | 
							
										device,
							 | 
						||
| 
								 | 
							
										0x21,
							 | 
						||
| 
								 | 
							
										DFU_DNLOAD,
							 | 
						||
| 
								 | 
							
										block,
							 | 
						||
| 
								 | 
							
										0,
							 | 
						||
| 
								 | 
							
										(unsigned char*)data,
							 | 
						||
| 
								 | 
							
										len,
							 | 
						||
| 
								 | 
							
										10000);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int OsmoSDRUpgrade::dfuDetach(libusb_device_handle* device)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return libusb_control_transfer(
							 | 
						||
| 
								 | 
							
										device,
							 | 
						||
| 
								 | 
							
										0x21,
							 | 
						||
| 
								 | 
							
										DFU_DETACH,
							 | 
						||
| 
								 | 
							
										0,
							 | 
						||
| 
								 | 
							
										0,
							 | 
						||
| 
								 | 
							
										NULL,
							 | 
						||
| 
								 | 
							
										0,
							 | 
						||
| 
								 | 
							
										1000);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void OsmoSDRUpgrade::fail(const QString& msg)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									log(tr("Fatal error: %1").arg(msg));
							 | 
						||
| 
								 | 
							
									QMessageBox::critical(this, tr("OsmoSDR Upgrade Failed"), msg);
							 | 
						||
| 
								 | 
							
									finish();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void OsmoSDRUpgrade::finish()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if(m_usb != NULL) {
							 | 
						||
| 
								 | 
							
										libusb_exit(m_usb);
							 | 
						||
| 
								 | 
							
										m_usb = NULL;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									QApplication::restoreOverrideCursor();
							 | 
						||
| 
								 | 
							
									ui->start->setEnabled(true);
							 | 
						||
| 
								 | 
							
									ui->close->setEnabled(true);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void OsmoSDRUpgrade::log(const QString& msg)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									ui->log->appendPlainText(msg);
							 | 
						||
| 
								 | 
							
									ui->log->moveCursor(QTextCursor::End);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void OsmoSDRUpgrade::reject()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if(ui->close->isEnabled())
							 | 
						||
| 
								 | 
							
										return QDialog::reject();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								size_t OsmoSDRUpgrade::zipHelper(void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									QByteArray* bytes = (QByteArray*)pOpaque;
							 | 
						||
| 
								 | 
							
									bytes->append((const char*)pBuf, n);
							 | 
						||
| 
								 | 
							
									return n;
							 | 
						||
| 
								 | 
							
								}
							 |