|
|
|
#include "mainwindow.h"
|
|
|
|
#include "ui_mainwindow.h"
|
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QFileDialog>
|
|
|
|
#include <QtConcurrent/QtConcurrent>
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
|
|
|
#define MESSAGE_BOX(M) \
|
|
|
|
emit showMessage(M)
|
|
|
|
|
|
|
|
|
|
|
|
MainWindow::MainWindow(QWidget *parent)
|
|
|
|
: QMainWindow(parent)
|
|
|
|
, ui(new Ui::MainWindow)
|
|
|
|
{
|
|
|
|
ui->setupUi(this);
|
|
|
|
|
|
|
|
_settings = new QSettings("Hasis", "HwTester");
|
|
|
|
|
|
|
|
_usd = new UltraSoundDevice();
|
|
|
|
|
|
|
|
_dial = new WaitDialog();
|
|
|
|
_dial->setModal(true);
|
|
|
|
|
|
|
|
this->setFixedSize(this->width(),this->height());
|
|
|
|
|
|
|
|
ui->prg_binUpload->setVisible(false);
|
|
|
|
ui->prg_fpgaProgram->setVisible(false);
|
|
|
|
|
|
|
|
ui->tb_binFile->setReadOnly(true);
|
|
|
|
ui->tb_fpgaBit->setReadOnly(true);
|
|
|
|
|
|
|
|
ui->tb_binFile->setText(_settings->value(BIN_FILE_PATH).value<QString>());
|
|
|
|
ui->tb_binOffset->setText(_settings->value(BIN_OFFSET).value<QString>());
|
|
|
|
ui->cb_binBarNum->setCurrentIndex(_settings->value(BIN_BAR_INDEX).value<int>());
|
|
|
|
ui->rbtn_reg->setChecked(_settings->value(REG_ACCESS_SEL).value<bool>());
|
|
|
|
ui->rbtn_offset->setChecked(!_settings->value(REG_ACCESS_SEL).value<bool>());
|
|
|
|
ui->tb_fpgaBit->setText(_settings->value(FPGA_FILE_PATH).value<QString>());
|
|
|
|
|
|
|
|
connect(this, &MainWindow::updateBlockProgressValue, this, &MainWindow::newBlockProgressValue);
|
|
|
|
connect(this, &MainWindow::updateFpgaProgressValue, this, &MainWindow::newFpgaProgressValue);
|
|
|
|
connect(this, &MainWindow::updateBlockProgressVisibility, this, &MainWindow::newBlockProgressVisibility);
|
|
|
|
connect(this, &MainWindow::updateFpgaProgressVisibility, this, &MainWindow::newFpgaProgressVisibility);
|
|
|
|
connect(this, &MainWindow::showMessage, this, &MainWindow::newMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
MainWindow::~MainWindow()
|
|
|
|
{
|
|
|
|
delete ui;
|
|
|
|
|
|
|
|
delete _settings;
|
|
|
|
|
|
|
|
delete _usd;
|
|
|
|
|
|
|
|
delete _dial;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::on_btn_browse_clicked()
|
|
|
|
{
|
|
|
|
QFileDialog fileDialog;
|
|
|
|
fileDialog.setNameFilters({"SRAM binary file (*.bin)"});
|
|
|
|
auto result = fileDialog.exec();
|
|
|
|
|
|
|
|
if(result)
|
|
|
|
{
|
|
|
|
auto selectedPath = fileDialog.selectedFiles()[0];
|
|
|
|
ui->tb_binFile->setText(selectedPath);
|
|
|
|
_settings->setValue(BIN_FILE_PATH, selectedPath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::on_btn_binUpload_clicked()
|
|
|
|
{
|
|
|
|
auto bar = ui->cb_binBarNum->currentText().toUInt();
|
|
|
|
|
|
|
|
auto offset = ui->tb_binOffset->text().toUInt(Q_NULLPTR, 16);
|
|
|
|
if(offset == 0 && ui->tb_binOffset->text() != "0")
|
|
|
|
{
|
|
|
|
MESSAGE_BOX("Invalid input format for offset");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_settings->setValue(BIN_OFFSET, ui->tb_binOffset->text());
|
|
|
|
_settings->setValue(BIN_BAR_INDEX, ui->cb_binBarNum->currentIndex());
|
|
|
|
|
|
|
|
auto path = ui->tb_binFile->text();
|
|
|
|
|
|
|
|
QFutureWatcher<void> watcher;
|
|
|
|
connect(&watcher, &QFutureWatcher<void>::finished, this, &MainWindow::threadFinished);
|
|
|
|
auto future = QtConcurrent::run(this, &MainWindow::binaryFileUploader, bar, offset, path);
|
|
|
|
watcher.setFuture(future);
|
|
|
|
_dial->exec();
|
|
|
|
disconnect(&watcher, &QFutureWatcher<void>::finished, this, &MainWindow::threadFinished);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::on_btn_binVerify_clicked()
|
|
|
|
{
|
|
|
|
auto bar = ui->cb_binBarNum->currentText().toUInt();
|
|
|
|
|
|
|
|
auto offset = ui->tb_binOffset->text().toUInt(Q_NULLPTR, 16);
|
|
|
|
if(offset == 0 && ui->tb_binOffset->text() != "0")
|
|
|
|
{
|
|
|
|
MESSAGE_BOX("Invalid input format for offset");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_settings->setValue(BIN_OFFSET, ui->tb_binOffset->text());
|
|
|
|
_settings->setValue(BIN_BAR_INDEX, ui->cb_binBarNum->currentIndex());
|
|
|
|
|
|
|
|
auto path = ui->tb_binFile->text();
|
|
|
|
|
|
|
|
QFutureWatcher<void> watcher;
|
|
|
|
connect(&watcher, &QFutureWatcher<void>::finished, this, &MainWindow::threadFinished);
|
|
|
|
auto future = QtConcurrent::run(this, &MainWindow::binaryFileVerifier, bar, offset, path);
|
|
|
|
watcher.setFuture(future);
|
|
|
|
_dial->exec();
|
|
|
|
disconnect(&watcher, &QFutureWatcher<void>::finished, this, &MainWindow::threadFinished);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::binaryFileUploader(quint32 bar, quint32 offset, QString path)
|
|
|
|
{
|
|
|
|
QFile file(path);
|
|
|
|
|
|
|
|
if (!file.open(QFile::ReadOnly))
|
|
|
|
{
|
|
|
|
MESSAGE_BOX("Could not open binary file, aborting operation");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit updateBlockProgressVisibility(true);
|
|
|
|
emit updateBlockProgressValue(0);
|
|
|
|
|
|
|
|
const auto actualSize = file.size();
|
|
|
|
auto readSize = 0;
|
|
|
|
while(readSize < actualSize)
|
|
|
|
{
|
|
|
|
QByteArray chunk = file.read(4);
|
|
|
|
auto value = byteArrayTo32LittleEndian(chunk);
|
|
|
|
try
|
|
|
|
{
|
|
|
|
_usd->writeWord(offset + readSize, bar, value);
|
|
|
|
} catch (myexception e)
|
|
|
|
{
|
|
|
|
MESSAGE_BOX(e.what());
|
|
|
|
|
|
|
|
emit updateBlockProgressVisibility(false);
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
readSize += 4;
|
|
|
|
|
|
|
|
auto percentage = (readSize * 100 / actualSize);
|
|
|
|
emit updateBlockProgressValue(percentage);
|
|
|
|
}
|
|
|
|
|
|
|
|
MESSAGE_BOX("Binary file upload finished with success");
|
|
|
|
|
|
|
|
emit updateBlockProgressVisibility(false);
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::binaryFileVerifier(quint32 bar, quint32 offset, QString path)
|
|
|
|
{
|
|
|
|
QFile file(path);
|
|
|
|
|
|
|
|
if (!file.open(QFile::ReadOnly))
|
|
|
|
{
|
|
|
|
MESSAGE_BOX("Could not open binary file, aborting operation");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit updateBlockProgressVisibility(true);
|
|
|
|
emit updateBlockProgressValue(0);
|
|
|
|
|
|
|
|
const auto actualSize = file.size();
|
|
|
|
auto readSize = 0;
|
|
|
|
while(readSize < actualSize)
|
|
|
|
{
|
|
|
|
QByteArray chunk = file.read(4);
|
|
|
|
auto value = byteArrayTo32LittleEndian(chunk);
|
|
|
|
try
|
|
|
|
{
|
|
|
|
auto data = _usd->readWord(offset + readSize, bar);
|
|
|
|
if(data != value)
|
|
|
|
{
|
|
|
|
auto message = QString("Error in data @ offset 0x%1, expected 0x%2 saw 0x%3")
|
|
|
|
.arg(QString::number(offset + readSize))
|
|
|
|
.arg(QString::number(value, 16))
|
|
|
|
.arg(QString::number(data, 16));
|
|
|
|
MESSAGE_BOX(message);
|
|
|
|
|
|
|
|
emit updateBlockProgressVisibility(false);
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (myexception e)
|
|
|
|
{
|
|
|
|
MESSAGE_BOX(e.what());
|
|
|
|
|
|
|
|
emit updateBlockProgressVisibility(false);
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
readSize += 4;
|
|
|
|
|
|
|
|
auto percentage = (readSize * 100 / actualSize);
|
|
|
|
emit updateBlockProgressValue(percentage);
|
|
|
|
}
|
|
|
|
|
|
|
|
MESSAGE_BOX("Binary verified with success");
|
|
|
|
|
|
|
|
emit updateBlockProgressVisibility(false);
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::fpgaProgrammer(quint32 bar, quint32 offset, QString path)
|
|
|
|
{
|
|
|
|
QFile file(path);
|
|
|
|
|
|
|
|
if (!file.open(QFile::ReadOnly))
|
|
|
|
{
|
|
|
|
MESSAGE_BOX("Could not open bit file, aborting operation");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit updateFpgaProgressValue(0);
|
|
|
|
emit updateFpgaProgressVisibility(true);
|
|
|
|
|
|
|
|
const auto actualSize = file.size();
|
|
|
|
auto readSize = 0;
|
|
|
|
while(readSize < actualSize)
|
|
|
|
{
|
|
|
|
QByteArray chunk = file.read(4);
|
|
|
|
auto value = byteArrayTo32BigEndian(chunk);
|
|
|
|
try
|
|
|
|
{
|
|
|
|
_usd->writeWord(offset, bar, value);
|
|
|
|
auto temp = _usd->readWord(offset + 4, bar);
|
|
|
|
while ((temp & 0x01) == 0x01)
|
|
|
|
{
|
|
|
|
temp = _usd->readWord(offset + 4, bar);
|
|
|
|
}
|
|
|
|
|
|
|
|
if((temp & 0x08) == 0x08)
|
|
|
|
{
|
|
|
|
throw(myexception("init_fail flag raised"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if((temp & 0x10) == 0x10)
|
|
|
|
{
|
|
|
|
throw(myexception("time_out flag raised"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (myexception e)
|
|
|
|
{
|
|
|
|
MESSAGE_BOX(e.what());
|
|
|
|
|
|
|
|
emit updateFpgaProgressVisibility(false);
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
readSize += 4;
|
|
|
|
|
|
|
|
auto percentage = (readSize * 100 / actualSize);
|
|
|
|
emit updateFpgaProgressValue(percentage);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto temp = _usd->readWord(offset + 4, bar);
|
|
|
|
if((temp & 0x02) == 0x02)
|
|
|
|
{
|
|
|
|
MESSAGE_BOX("FPGA programming finished with success");
|
|
|
|
}
|
|
|
|
else if((temp & 0x04) == 0x04)
|
|
|
|
{
|
|
|
|
MESSAGE_BOX("FPGA programming failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
emit updateFpgaProgressVisibility(false);
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
quint32 MainWindow::byteArrayTo32LittleEndian(QByteArray data)
|
|
|
|
{
|
|
|
|
quint32 temp = 0;
|
|
|
|
|
|
|
|
temp = (data[0] & 0x000000FF) |
|
|
|
|
((data[1] << 8) & 0x0000FF00) |
|
|
|
|
((data[2] << 16) & 0x00FF0000) |
|
|
|
|
((data[3] << 24) & 0xFF000000);
|
|
|
|
|
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
quint32 MainWindow::byteArrayTo32BigEndian(QByteArray data)
|
|
|
|
{
|
|
|
|
quint32 temp = 0;
|
|
|
|
|
|
|
|
temp = (data[3] & 0x000000FF) |
|
|
|
|
((data[2] << 8) & 0x0000FF00) |
|
|
|
|
((data[1] << 16) & 0x00FF0000) |
|
|
|
|
((data[0] << 24) & 0xFF000000);
|
|
|
|
|
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::on_rbtn_reg_toggled(bool checked)
|
|
|
|
{
|
|
|
|
if(checked)
|
|
|
|
{
|
|
|
|
_settings->setValue(REG_ACCESS_SEL, true);
|
|
|
|
ui->l_regIndicator->setText("Register number: (Hex)");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::on_rbtn_offset_toggled(bool checked)
|
|
|
|
{
|
|
|
|
if(checked)
|
|
|
|
{
|
|
|
|
_settings->setValue(REG_ACCESS_SEL, false);
|
|
|
|
ui->l_regIndicator->setText("Register offset: (Hex)");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::on_btn_readReg_clicked()
|
|
|
|
{
|
|
|
|
auto bar = ui->cb_regBarNum->currentText().toUInt();
|
|
|
|
|
|
|
|
auto offset = ui->tb_regIndicator->text().toUInt(Q_NULLPTR, 16);
|
|
|
|
if(offset == 0 && ui->tb_regIndicator->text() != "0")
|
|
|
|
{
|
|
|
|
MESSAGE_BOX("Invalid input format for offset");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
quint64 value = 0;
|
|
|
|
auto width = ui->cb_regWidth->currentIndex();
|
|
|
|
switch(width)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
value = _usd->readByte(offset, bar);
|
|
|
|
ui->lcd_regvalue->setDigitCount(2);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if(ui->rbtn_reg->isChecked())
|
|
|
|
offset *= 2;
|
|
|
|
value = _usd->readShort(offset, bar);
|
|
|
|
ui->lcd_regvalue->setDigitCount(4);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if(ui->rbtn_reg->isChecked())
|
|
|
|
offset *= 4;
|
|
|
|
value = _usd->readWord(offset, bar);
|
|
|
|
ui->lcd_regvalue->setDigitCount(8);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if(ui->rbtn_reg->isChecked())
|
|
|
|
offset *= 8;
|
|
|
|
value = _usd->readLong(offset, bar);
|
|
|
|
ui->lcd_regvalue->setDigitCount(16);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ui->lcd_regvalue->display(QString::number(value, 16));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::on_btn_writeReg_clicked()
|
|
|
|
{
|
|
|
|
auto bar = ui->cb_regBarNum->currentText().toUInt();
|
|
|
|
|
|
|
|
auto offset = ui->tb_regIndicator->text().toUInt(Q_NULLPTR, 16);
|
|
|
|
if(offset == 0 && ui->tb_regIndicator->text() != "0")
|
|
|
|
{
|
|
|
|
MESSAGE_BOX("Invalid input format for offset");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto value = ui->tb_regValue->text().toULong(Q_NULLPTR, 16);
|
|
|
|
if(value == 0 && ui->tb_regValue->text() != "0")
|
|
|
|
{
|
|
|
|
MESSAGE_BOX("Invalid input format for write value");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto width = ui->cb_regWidth->currentIndex();
|
|
|
|
switch(width)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
_usd->writeByte(offset, bar, value);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if(ui->rbtn_reg->isChecked())
|
|
|
|
offset *= 2;
|
|
|
|
_usd->writeShort(offset, bar, value);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if(ui->rbtn_reg->isChecked())
|
|
|
|
offset *= 4;
|
|
|
|
_usd->writeWord(offset, bar, value);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if(ui->rbtn_reg->isChecked())
|
|
|
|
offset *= 8;
|
|
|
|
_usd->writeLong(offset, bar, value);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::newBlockProgressValue(int percentage)
|
|
|
|
{
|
|
|
|
ui->prg_binUpload->setValue(percentage);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::newFpgaProgressValue(int percentage)
|
|
|
|
{
|
|
|
|
ui->prg_fpgaProgram->setValue(percentage);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::newBlockProgressVisibility(bool show)
|
|
|
|
{
|
|
|
|
ui->prg_binUpload->setVisible(show);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::newFpgaProgressVisibility(bool show)
|
|
|
|
{
|
|
|
|
ui->prg_fpgaProgram->setVisible(show);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::on_btn_fpgaBrowse_clicked()
|
|
|
|
{
|
|
|
|
QFileDialog fileDialog;
|
|
|
|
fileDialog.setNameFilters({"FPGA program file (*.bit)"});
|
|
|
|
auto result = fileDialog.exec();
|
|
|
|
|
|
|
|
if(result)
|
|
|
|
{
|
|
|
|
auto selectedPath = fileDialog.selectedFiles()[0];
|
|
|
|
ui->tb_fpgaBit->setText(selectedPath);
|
|
|
|
_settings->setValue(FPGA_FILE_PATH, selectedPath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::on_btn_fpgaProgram_clicked()
|
|
|
|
{
|
|
|
|
auto bar = 0;
|
|
|
|
auto offset = 0x4;
|
|
|
|
|
|
|
|
auto path = ui->tb_fpgaBit->text();
|
|
|
|
|
|
|
|
QFutureWatcher<void> watcher;
|
|
|
|
connect(&watcher, &QFutureWatcher<void>::finished, this, &MainWindow::threadFinished);
|
|
|
|
auto future = QtConcurrent::run(this, &MainWindow::fpgaProgrammer, bar, offset, path);
|
|
|
|
watcher.setFuture(future);
|
|
|
|
_dial->exec();
|
|
|
|
disconnect(&watcher, &QFutureWatcher<void>::finished, this, &MainWindow::threadFinished);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************************************/
|
|
|
|
void MainWindow::newMessage(QString message)
|
|
|
|
{
|
|
|
|
QMessageBox msgBox;
|
|
|
|
msgBox.setText(message);
|
|
|
|
msgBox.exec();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::threadFinished()
|
|
|
|
{
|
|
|
|
_dial->close();
|
|
|
|
}
|