807 lines
19 KiB
C++
807 lines
19 KiB
C++
#include <QFileDialog>
|
|
#include <QFile>
|
|
#include <QSerialPortInfo>
|
|
#include "qpsxserial.h"
|
|
#include "ui_qpsxserial.h"
|
|
|
|
#define LOST_PACKET_TIMEOUT 3000
|
|
#define CONNECT_TO_PSX_TIMEOUT 500
|
|
|
|
QPSXSerial::QPSXSerial(QWidget *parent, APP_INTERFACE interface) :
|
|
QMainWindow(parent),
|
|
ui(new Ui::QPSXSerial),
|
|
stdout_ui(new Ui::Stdout_Console),
|
|
stdout_dialog(new QDialog),
|
|
app_interface(interface),
|
|
ack(false),
|
|
exe_sent(false),
|
|
write_ready(false),
|
|
byte_sent_received(false),
|
|
first_entered(false),
|
|
disable_psx_stdout(false)
|
|
{
|
|
connect(&lost_packet_timer, SIGNAL(timeout()), this, SLOT(onPacketLost()));
|
|
connect(&serial, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)));
|
|
connect(&serial, SIGNAL(readyRead()), this, SLOT(onReadyRead(void)));
|
|
|
|
init_timer.setSingleShot(true);
|
|
init_timer.setInterval(CONNECT_TO_PSX_TIMEOUT);
|
|
|
|
connect(&init_timer, SIGNAL(timeout(void)), this, SLOT(connectToPSXTimeout(void)));
|
|
|
|
if (app_interface == GUI_APP)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
connect(ui->stdout_Button, SIGNAL(released()), this, SLOT(onStdOutButtonReleased()));
|
|
connect(ui->loadFile_Btn, SIGNAL(released()), this, SLOT(onLoadFileBtnReleased()));
|
|
connect(ui->updatePorts_Btn, SIGNAL(released()), this, SLOT(onUpdatePortsBtnReleased()));
|
|
connect(ui->send_Btn, SIGNAL(released()), this, SLOT(onSendBtnReleased()));
|
|
connect(ui->ports_ComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(onPortSelectedComboBox(QString)));
|
|
|
|
ui->exeProgressBar->setVisible(false);
|
|
ui->send_Btn->setEnabled(false);
|
|
ui->inFileName->setVisible(false);
|
|
|
|
stdout_ui->setupUi(stdout_dialog);
|
|
|
|
connect(stdout_ui->clean_Btn, SIGNAL(released()), stdout_ui->stdout_Log, SLOT(clear()));
|
|
connect(stdout_ui->close_Btn, SIGNAL(released()), stdout_dialog, SLOT(close()));
|
|
connect(this, SIGNAL(debug_frame_received(QString)), stdout_ui->stdout_Log, SLOT(append(QString)));
|
|
|
|
setWindowTitle( "QPSXSerial "
|
|
+ QString(QPSXSERIAL_VERSION_STR) );
|
|
}
|
|
}
|
|
|
|
QPSXSerial::~QPSXSerial()
|
|
{
|
|
delete ui;
|
|
}
|
|
|
|
void QPSXSerial::onStdOutButtonReleased(void)
|
|
{
|
|
stdout_dialog->show();
|
|
}
|
|
|
|
void QPSXSerial::showError(QString error)
|
|
{
|
|
QMessageBox box(QMessageBox::Critical, "QPSXSerial serror", error);
|
|
|
|
box.show();
|
|
}
|
|
|
|
void QPSXSerial::onLoadFileBtnReleased(void)
|
|
{
|
|
selectedFolder = QFileDialog::getExistingDirectory( this,
|
|
"Load folder with PSX data",
|
|
"C:/",
|
|
QFileDialog::ShowDirsOnly );
|
|
|
|
if (selectedFolder.isEmpty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
ui->loadedFile_LineEdit->setText(selectedFolder);
|
|
|
|
inputExe = getInputExeFromFolder(&selectedFolder);
|
|
|
|
if (selectedPort.isEmpty() == false)
|
|
{
|
|
ui->send_Btn->setEnabled(true);
|
|
}
|
|
}
|
|
|
|
void QPSXSerial::onUpdatePortsBtnReleased(void)
|
|
{
|
|
ui->ports_ComboBox->clear();
|
|
|
|
foreach(QSerialPortInfo port, QSerialPortInfo::availablePorts())
|
|
{
|
|
ui->ports_ComboBox->addItem(port.portName());
|
|
}
|
|
}
|
|
|
|
void QPSXSerial::onSendBtnReleased(void)
|
|
{
|
|
if (serial.isOpen() == false)
|
|
{
|
|
if (selectedPort.isEmpty())
|
|
{
|
|
showGUICLIerror("No selected port!");
|
|
return;
|
|
}
|
|
|
|
serial.setPortName(selectedPort);
|
|
serial.setBaudRate(QSerialPort::Baud115200);
|
|
serial.setParity(QSerialPort::NoParity);
|
|
serial.setDataBits(QSerialPort::Data8);
|
|
serial.setStopBits(QSerialPort::OneStop);
|
|
|
|
if (serial.open(QIODevice::ReadWrite) == false)
|
|
{
|
|
showGUICLIerror("Could not open port " + selectedPort);
|
|
return;
|
|
}
|
|
|
|
init_timer.start();
|
|
|
|
if (app_interface == GUI_APP)
|
|
{
|
|
ui->exeProgressBar->setVisible(true);
|
|
ui->exeProgressBar->setMinimum(0);
|
|
ui->exeProgressBar->setMaximum(0);
|
|
ui->inFileName->setText("Waiting for response from the device...");
|
|
ui->inFileName->setVisible(true);
|
|
ui->send_Btn->setText("Disconnect from PSX");
|
|
}
|
|
else
|
|
{
|
|
printf("Connected to port successfully.\n");
|
|
printf("Waiting for response from the device...\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (app_interface == GUI_APP)
|
|
{
|
|
ui->send_Btn->setText("Send to PSX!");
|
|
ui->exeProgressBar->setVisible(false);
|
|
ui->inFileName->clear();
|
|
}
|
|
|
|
serial.close();
|
|
first_entered = false;
|
|
exe_sent = false;
|
|
lost_packet_timer.stop();
|
|
init_timer.stop();
|
|
}
|
|
}
|
|
|
|
void QPSXSerial::connectToPSXTimeout(void)
|
|
{
|
|
QByteArray ba;
|
|
|
|
if (ack == false)
|
|
{
|
|
ba.append(99);
|
|
|
|
serial.write(ba);
|
|
|
|
init_timer.start(CONNECT_TO_PSX_TIMEOUT);
|
|
}
|
|
}
|
|
|
|
void QPSXSerial::onPortSelectedComboBox(QString port)
|
|
{
|
|
selectedPort = port;
|
|
|
|
if (inputExe.isEmpty() == false)
|
|
{
|
|
ui->send_Btn->setEnabled(true);
|
|
}
|
|
}
|
|
|
|
void QPSXSerial::onBytesWritten(qint64)
|
|
{
|
|
write_ready = true;
|
|
}
|
|
|
|
void QPSXSerial::onReadyRead(void)
|
|
{
|
|
const QByteArray data = serial.readAll();
|
|
static QTime time = QTime::currentTime();
|
|
static bool cdrom_petition;
|
|
|
|
if (exe_sent)
|
|
{
|
|
static QByteArray fileName;
|
|
|
|
if (data.contains("#"))
|
|
{
|
|
cdrom_petition = true;
|
|
fileName.clear();
|
|
}
|
|
|
|
if (data.count() == 1)
|
|
{
|
|
if (data.at(0) == 'b')
|
|
{
|
|
ack = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
qDebug() << data;
|
|
|
|
if (cdrom_petition)
|
|
{
|
|
if (data.contains("#"))
|
|
{
|
|
int initial_i = data.indexOf("#");
|
|
|
|
qDebug() << initial_i;
|
|
|
|
fileName.append(data.mid(initial_i, data.count() - initial_i));
|
|
}
|
|
else
|
|
{
|
|
fileName.append(data);
|
|
}
|
|
|
|
if (fileName.contains("@"))
|
|
{
|
|
int terminator_i = fileName.indexOf("@");
|
|
|
|
if (terminator_i >= fileName.count())
|
|
{
|
|
fileName.chop(terminator_i - fileName.count() - 1);
|
|
}
|
|
|
|
cdrom_petition = false;
|
|
|
|
qDebug() << "INPUT FRAME: " + fileName;
|
|
QString filePath = QString(fileName);
|
|
|
|
filePath.remove("@");
|
|
filePath.remove("#");
|
|
|
|
filePath.remove("cdrom:\\");
|
|
|
|
qDebug() << "selectedFolder = " + selectedFolder;
|
|
|
|
filePath.prepend(selectedFolder);
|
|
|
|
filePath.replace("\\", "/");
|
|
|
|
filePath.chop(2); // Remove ending ";1"
|
|
|
|
qDebug() << "filePath = " + filePath;
|
|
|
|
QFile f(filePath);
|
|
|
|
if (f.open(QFile::ReadOnly) == false)
|
|
{
|
|
qDebug() << "Error while reading input file!";
|
|
return;
|
|
}
|
|
|
|
QByteArray file_data = f.readAll();
|
|
quint32 sz = file_data.count();
|
|
|
|
sendDataSize(sz);
|
|
|
|
if (serial.waitForReadyRead() == false)
|
|
{
|
|
qDebug() << "Did not receive any ACK!";
|
|
}
|
|
else
|
|
{
|
|
qDebug() << "sendData for file...";
|
|
onReadyRead();
|
|
|
|
sendData(file_data, filePath);
|
|
|
|
f.close();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (app_interface == GUI_APP)
|
|
{
|
|
emit debug_frame_received(QString(data));
|
|
}
|
|
else if (app_interface == CLI_APP)
|
|
{
|
|
if (disable_psx_stdout == false)
|
|
{
|
|
const char* string_received = data.toStdString().c_str();
|
|
|
|
printf("%s\n", string_received);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (data.isEmpty() == false)
|
|
{
|
|
quint8 data_byte = static_cast<quint8>(data.at(0));
|
|
|
|
if (data_byte == 'b')
|
|
{
|
|
// Received handshaking byte. Start transmission!
|
|
|
|
ack = true;
|
|
|
|
init_timer.stop();
|
|
|
|
if (first_entered == false)
|
|
{
|
|
first_entered = true;
|
|
|
|
if (sendExe() == false)
|
|
{
|
|
qDebug() << "An error happened when sending EXE file!";
|
|
}
|
|
|
|
exe_sent = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
time = QTime::currentTime();
|
|
}
|
|
|
|
bool QPSXSerial::sendExe(void)
|
|
{
|
|
QFile f(inputExe);
|
|
|
|
if (f.open(QFile::ReadOnly) == false)
|
|
{
|
|
qDebug() << "Could not open input EXE file!";
|
|
return false;
|
|
}
|
|
|
|
f.seek(0);
|
|
|
|
ack = false;
|
|
|
|
QByteArray data = f.read(2048 /* PSX-EXE header */);
|
|
|
|
if (app_interface == GUI_APP)
|
|
{
|
|
ui->inFileName->setText("Sending PSX-EXE size...");
|
|
}
|
|
else if (app_interface == CLI_APP)
|
|
{
|
|
printf("Sending PSX-EXE header data...\n");
|
|
}
|
|
|
|
// PSX-EXE header is actually 2048 bytes long, but initial 32 bytes
|
|
// contain all the information we need for this.
|
|
for (int i = 0; i < 32; i+=4)
|
|
{
|
|
QByteArray send;
|
|
write_ready = false;
|
|
|
|
QThread::msleep(100);
|
|
|
|
QApplication::processEvents();
|
|
|
|
qDebug() << "Sending " + data.mid(i, 4).toHex();
|
|
|
|
send.append(data.mid(i, 4));
|
|
|
|
serial.write(send);
|
|
}
|
|
|
|
if (app_interface == GUI_APP)
|
|
{
|
|
ui->inFileName->setText("Sending PSX-EXE size...");
|
|
}
|
|
else if (app_interface == CLI_APP)
|
|
{
|
|
printf("Sending PSX-EXE size...\n");
|
|
}
|
|
|
|
if (serial.waitForReadyRead() == false)
|
|
{
|
|
qDebug() << "Did not receive any ACK!";
|
|
}
|
|
else
|
|
{
|
|
onReadyRead();
|
|
}
|
|
|
|
qDebug () << "Sending EXE size...";
|
|
|
|
qint64 sz = f.size() - 2048;
|
|
|
|
sendDataSize(static_cast<quint32>(sz));
|
|
|
|
if (serial.waitForReadyRead() == false)
|
|
{
|
|
qDebug() << "Did not receive any ACK!";
|
|
}
|
|
else
|
|
{
|
|
onReadyRead();
|
|
}
|
|
|
|
// Send file size without header
|
|
|
|
qDebug() << "Dump EXE data...";
|
|
|
|
f.seek(2048);
|
|
|
|
data = f.readAll();
|
|
|
|
qDebug() << data.count();
|
|
|
|
sendData(data, inputExe);
|
|
|
|
f.close();
|
|
|
|
qDebug() << "PSX-EXE sent successfully!";
|
|
|
|
return true;
|
|
}
|
|
|
|
void QPSXSerial::sendDataSize(quint32 size)
|
|
{
|
|
QByteArray ar;
|
|
|
|
for (unsigned int i = 0; i < sizeof(quint32); i++)
|
|
{
|
|
char send = (char)( size >> (i << 3) );
|
|
|
|
QByteArray send_arr;
|
|
|
|
send_arr.append(send);
|
|
|
|
ar.append(send);
|
|
|
|
serial.write(send_arr);
|
|
|
|
while (write_ready == false)
|
|
{
|
|
QApplication::processEvents();
|
|
}
|
|
}
|
|
|
|
/*for (unsigned int i = 0; i < sizeof(quint32); i++)
|
|
{
|
|
qDebug() << "0x" + QString::number(ar.at(i), 16);
|
|
}*/
|
|
|
|
ack = false;
|
|
}
|
|
|
|
void QPSXSerial::onPacketLost(void)
|
|
{
|
|
qDebug() << "Entering onPacketLost...";
|
|
|
|
if (ack == false)
|
|
{
|
|
serial.write(last_packet_sent);
|
|
lost_packet_timer.start(LOST_PACKET_TIMEOUT);
|
|
}
|
|
}
|
|
|
|
void QPSXSerial::sendData(QByteArray data, QString fileName)
|
|
{
|
|
static int last_i;
|
|
|
|
last_i = 0;
|
|
|
|
if (app_interface == GUI_APP)
|
|
{
|
|
ui->exeProgressBar->setVisible(true);
|
|
ui->exeProgressBar->setRange(0, data.count());
|
|
ui->inFileName->setText(fileName);
|
|
ui->inFileName->setVisible(true);
|
|
}
|
|
|
|
lost_packet_timer.setInterval(LOST_PACKET_TIMEOUT);
|
|
lost_packet_timer.setSingleShot(true);
|
|
|
|
for (int i = 0; i < data.count(); i+= 8)
|
|
{
|
|
QByteArray send;
|
|
ack = false;
|
|
|
|
send.append(data.mid(i, 8));
|
|
|
|
//qDebug() << "Sent packet";
|
|
|
|
QApplication::processEvents();
|
|
|
|
serial.write(send);
|
|
|
|
last_packet_sent = send;
|
|
|
|
lost_packet_timer.start(LOST_PACKET_TIMEOUT);
|
|
|
|
if (serial.waitForReadyRead() == false)
|
|
{
|
|
qDebug() << "Did not receive any ACK!";
|
|
}
|
|
else
|
|
{
|
|
onReadyRead();
|
|
}
|
|
|
|
if (app_interface == GUI_APP)
|
|
{
|
|
ui->exeProgressBar->setValue(i);
|
|
}
|
|
else if (app_interface == CLI_APP)
|
|
{
|
|
if ( ( (i - last_i) > (data.count() >> 7))
|
|
||
|
|
(i > (data.count() - (data.count() >> 7) ) ) )
|
|
{
|
|
int j;
|
|
bool draw_arrow = true;
|
|
|
|
// Fancy, CLI progress bar
|
|
|
|
printf("\r");
|
|
|
|
printf("|");
|
|
|
|
for (j = 0; j < data.count(); j += data.count() >> 5)
|
|
{
|
|
if (i > j)
|
|
{
|
|
printf("=");
|
|
}
|
|
else if (i < j)
|
|
{
|
|
if (draw_arrow)
|
|
{
|
|
draw_arrow = false;
|
|
printf(">");
|
|
}
|
|
printf(" ");
|
|
}
|
|
else
|
|
{
|
|
printf(">");
|
|
}
|
|
}
|
|
|
|
printf("|");
|
|
|
|
printf("\t%d/%d bytes sent...", i, data.count());
|
|
|
|
last_i = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
lost_packet_timer.stop();
|
|
|
|
if (app_interface == GUI_APP)
|
|
{
|
|
ui->exeProgressBar->setValue(data.count());
|
|
ui->inFileName->setText("Transfer complete!");
|
|
}
|
|
else if (app_interface == CLI_APP)
|
|
{
|
|
printf("Transfer complete!\n");
|
|
}
|
|
|
|
ack = false;
|
|
}
|
|
|
|
void QPSXSerial::cli_run(void)
|
|
{
|
|
QStringList allowed_flags;
|
|
bool correct_flag_used = false;
|
|
|
|
allowed_flags.append("--help");
|
|
allowed_flags.append("--port");
|
|
allowed_flags.append("--inpath");
|
|
|
|
foreach(QString flag, allowed_flags)
|
|
{
|
|
if (_paramlist.contains(flag))
|
|
{
|
|
correct_flag_used = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( (_paramlist.count() < 2) ||
|
|
(_paramlist.contains("--help")) ||
|
|
(correct_flag_used == false) )
|
|
{
|
|
showHelp();
|
|
|
|
emit finished();
|
|
|
|
return;
|
|
}
|
|
|
|
// Check specified port
|
|
|
|
int port_i = _paramlist.indexOf("--port");
|
|
|
|
if (port_i == -1)
|
|
{
|
|
printf("No port specified! Please include \"--port\" flag and port name e.g.: \"--port COM7\"\n");
|
|
|
|
emit finished();
|
|
return;
|
|
}
|
|
|
|
if (_paramlist.count() > (++port_i ) )
|
|
{
|
|
selectedPort = _paramlist.at(port_i);
|
|
}
|
|
else
|
|
{
|
|
printf("No port name specified! Please write port name e.g.: \"--port COM7\"\n");
|
|
emit finished();
|
|
return;
|
|
}
|
|
|
|
// Check specified folder
|
|
|
|
int folder_i = _paramlist.indexOf("--input_folder");
|
|
|
|
if (folder_i == -1)
|
|
{
|
|
printf("No input folder has been specified. Please include \"--help\" for further reference"
|
|
" about QPSXSerial usage.\n");
|
|
emit finished();
|
|
return;
|
|
}
|
|
|
|
if (_paramlist.count() > (++folder_i ) )
|
|
{
|
|
selectedFolder = _paramlist.at(folder_i);
|
|
}
|
|
else
|
|
{
|
|
printf( "No input folder path! Please write valid folder path e.g.: "
|
|
"--input-folder ~/MyGame/cdimg\n");
|
|
emit finished();
|
|
return;
|
|
}
|
|
|
|
inputExe = getInputExeFromFolder(&selectedFolder);
|
|
|
|
if (inputExe.isEmpty())
|
|
{
|
|
printf("Could not find PSX-EXE from specified input folder.\n");
|
|
emit finished();
|
|
return;
|
|
}
|
|
|
|
// Check optional flags
|
|
|
|
int psx_sdtout_flag = _paramlist.indexOf("--disable_psx_stdout");
|
|
|
|
if (psx_sdtout_flag != -1)
|
|
{
|
|
disable_psx_stdout = true;
|
|
}
|
|
else
|
|
{
|
|
disable_psx_stdout = false;
|
|
}
|
|
|
|
onSendBtnReleased();
|
|
}
|
|
|
|
void QPSXSerial::showHelp(void)
|
|
{
|
|
printf("##########################\n");
|
|
printf("QPSXSerial version %s\n", QPSXSERIAL_VERSION_STR);
|
|
printf("##########################\n");
|
|
printf("This application allows uploading PSX-EXE files to a PlayStation 1\n");
|
|
printf("console (also known as PSX) using serial port interface.\n");
|
|
printf("To be used together with OpenSend, available on the link below:\n");
|
|
|
|
printf("\n%s\n\n", OPENSEND_URL);
|
|
printf("Report any bugs, issues or suggestions on the official Github repository for QPSXSerial:\n");
|
|
printf("\n%s\n\n", QPSXSERIAL_URL);
|
|
|
|
printf("Usage:\n\n");
|
|
|
|
printf("QPSXSerial --input_folder inpath --port PORTNAME [options]\n\n");
|
|
|
|
printf("The following options are available:\n");
|
|
printf("--disable_psx_stdout\t\tDisables stdout messages from console to PC\n\n");
|
|
|
|
printf("Additionally to PSX-EXEs, QPSXSerial can also send external files e.g.:\n"
|
|
"*.TIM or *.VAG files whenever the game requests such data.\n");
|
|
printf("A working example of this bidirectional communication can be found on my open-source\n");
|
|
printf("video game \"Airport\", available on the following Github repository:\n");
|
|
printf("\nhttps://github.com/XaviDCR92/Airport/\n\n");
|
|
printf("QPSXSerial, OpenSend and Airport written by Xavier Del Campo (aka Xavi92).\n");
|
|
printf("All software released under the General Public License (GPL-3.0).\n");
|
|
printf("This application has been created using Qt toolkit %s\n", QT_VERSION_STR);
|
|
printf("\nINFO: In case you do not set any parameters, GUI is enabled by default.\n");
|
|
}
|
|
|
|
QString QPSXSerial::getInputExeFromFolder(QString* folder)
|
|
{
|
|
QFile system_f(*folder + "\\SYSTEM.CNF");
|
|
|
|
QString fileSelected;
|
|
QString retExe;
|
|
|
|
if ( (folder->endsWith("/") == false) && (folder->endsWith("\\") == false) )
|
|
{
|
|
folder->append("/");
|
|
}
|
|
|
|
if (system_f.exists() == false)
|
|
{
|
|
QDir d(*folder);
|
|
QStringList filters;
|
|
|
|
filters.append("*.EXE");
|
|
filters.append("*.exe");
|
|
|
|
QStringList exe_list = d.entryList(filters);
|
|
|
|
if (exe_list.isEmpty())
|
|
{
|
|
retExe.clear();
|
|
return retExe;
|
|
}
|
|
|
|
if (exe_list.contains("PSX.EXE"))
|
|
{
|
|
fileSelected = "PSX.EXE";
|
|
}
|
|
else
|
|
{
|
|
fileSelected = exe_list.first();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (system_f.open(QFile::ReadOnly) == false)
|
|
{
|
|
QString error = "Could not open " + *folder + "\\SYSTEM.CNF";
|
|
showGUICLIerror(error);
|
|
|
|
retExe.clear();
|
|
return retExe;
|
|
}
|
|
|
|
QTextStream system_txt(&system_f);
|
|
|
|
do
|
|
{
|
|
QString line = system_txt.readLine();
|
|
|
|
QStringList tokens = line.split("=");
|
|
|
|
if (tokens.isEmpty())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (tokens.at(0).contains("BOOT") == false)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
fileSelected = tokens.at(1).split("\\").at(1);
|
|
|
|
fileSelected.chop(2); // Remove ";1" suffix.
|
|
break;
|
|
|
|
}while (system_txt.atEnd() == false);
|
|
}
|
|
|
|
|
|
retExe = *folder + fileSelected;
|
|
|
|
return retExe;
|
|
}
|
|
|
|
void QPSXSerial::showGUICLIerror(QString error)
|
|
{
|
|
if (app_interface == GUI_APP)
|
|
{
|
|
showError(error);
|
|
}
|
|
else if (app_interface == CLI_APP)
|
|
{
|
|
const char* c_str_error = error.toStdString().c_str();
|
|
|
|
printf("%s\n", c_str_error);
|
|
}
|
|
}
|