#include #include #include #include "qpsxserial.h" #include "ui_qpsxserial.h" QPSXSerial::QPSXSerial(QWidget *parent) : QMainWindow(parent), ui(new Ui::QPSXSerial) { ui->setupUi(this); lost_packet_timer = new QTimer(); connect(lost_packet_timer, SIGNAL(timeout()), this, SLOT(onPacketLost())); 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))); connect(&serial, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64))); connect(&serial, SIGNAL(readyRead()), this, SLOT(onReadyRead(void))); ack = false; init_timer = NULL; ui->exeProgressBar->setVisible(false); ui->send_Btn->setEnabled(false); ui->inFileName->setVisible(false); write_ready = false; exe_sent = false; } QPSXSerial::~QPSXSerial() { if(serial.isOpen() == true) { serial.close(); } delete ui; } void QPSXSerial::onLoadFileBtnReleased(void) { selectedFolder = QFileDialog::getExistingDirectory( this, "Load folder with PSX data", "C:/", QFileDialog::ShowDirsOnly ); if(selectedFolder.isEmpty() == true) { return; } selectedFolder.append("/"); ui->loadedFile_LineEdit->setText(selectedFolder); QFile system_f(selectedFolder + "\\SYSTEM.CNF"); if(system_f.open(QFile::ReadOnly) == false) { qDebug() << "Could not open " + selectedFolder + "\\SYSTEM.CNF"; return; } QTextStream system_txt(&system_f); QString fileSelected; do { if(system_txt.atEnd() == true) { return; } QString line = system_txt.readLine(); QStringList tokens = line.split("="); if(tokens.isEmpty() == true) { continue; } if(tokens.at(0).contains("BOOT") == false) { continue; } fileSelected = tokens.at(1).split("\\").at(1); fileSelected.chop(2); // Remove ";1" suffix. break; }while(1); inputExe = selectedFolder + fileSelected; qDebug() << "inputExe = " + inputExe; } void QPSXSerial::onUpdatePortsBtnReleased(void) { ui->ports_ComboBox->clear(); foreach(QSerialPortInfo port, QSerialPortInfo::availablePorts()) { ui->ports_ComboBox->addItem(port.portName()); } } void QPSXSerial::onSendBtnReleased(void) { qDebug() << serial.isOpen(); if(serial.isOpen() == false) { if(selectedPort.isEmpty() == true) { qDebug() << "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) { qDebug() << "Could not open port " + selectedPort; return; } qDebug() << "Connected succesfully to " + selectedPort; if(init_timer == NULL) { init_timer = new QTimer(); init_timer->setSingleShot(true); init_timer->setInterval(1000); connect(init_timer, SIGNAL(timeout(void)), this, SLOT(connectToPSXTimeout(void))); } ui->exeProgressBar->setVisible(true); ui->exeProgressBar->setMinimum(0); ui->exeProgressBar->setMaximum(0); ui->inFileName->setText("Waiting for PSX response..."); ui->inFileName->setVisible(true); init_timer->start(1000); ui->send_Btn->setText("Disconnect from PSX"); } else { serial.close(); ui->send_Btn->setText("Send to PSX!"); qDebug() << "Disconnected"; init_timer->stop(); } } void QPSXSerial::connectToPSXTimeout(void) { QByteArray ba; if(ack == false) { ba.append(99); serial.write(ba); //qDebug() << "Retry..."; init_timer->start(1000); } } void QPSXSerial::onPortSelectedComboBox(QString port) { selectedPort = port; ui->send_Btn->setEnabled(true); qDebug() << "Selected port: " + selectedPort; } void QPSXSerial::onBytesWritten(qint64) { //qDebug() << "Bytes written: " + QString::number(bytes_written); /*byte_sent_received = false; while(byte_sent_received == false) { QApplication::processEvents(); }*/ write_ready = true; } void QPSXSerial::onReadyRead(void) { static bool first_entered = false; QByteArray data = serial.readAll(); static QTime time = QTime::currentTime(); //qDebug() << QString("Received ") + QString::number(data.count()) + QString(" bytes."); //qDebug() << QString("Took ") + QString::number(time.msecsTo(QTime::currentTime())); if(exe_sent == true) { //qDebug() << data; QByteArray header = data.left(5); if(header == "cdrom") { qDebug() << "INPUT FRAME: " + data; QString filePath = QString(data); 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); while(ack == false) { QApplication::processEvents(); } qDebug() << "sendData for file..."; sendData(file_data, filePath); } else { if(data.count() == 1) { if(data.at(0) == 'b') { ack = true; } } else { qDebug() << data; } } } if(data.isEmpty() == false) { quint8 data_byte = (quint8)data.at(0); if(data_byte == 'b') { //qDebug() << "Received ACK"; // 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 */); qDebug () << "Sending PSX-EXE header..."; for(int i = 0; i < 32; i++) { QByteArray send; write_ready = false; send.append(data[i]); serial.write(send); while(write_ready == false) { QApplication::processEvents(); } } while(ack == false) { QApplication::processEvents(); } qDebug () << "Sending EXE size..."; qint64 sz = f.size() - 2048; sendDataSize((quint32)sz); while(ack == false) { QApplication::processEvents(); } // Send file size without header qDebug() << "Dump EXE data..."; f.seek(2048); data = f.readAll(); qDebug() << data.count(); sendData(data, inputExe); f.close(); 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(100); } } void QPSXSerial::sendData(QByteArray data, QString fileName) { ui->exeProgressBar->setVisible(true); ui->exeProgressBar->setRange(0, data.count()); ui->inFileName->setText(fileName); ui->inFileName->setVisible(true); lost_packet_timer->setInterval(100); 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"; serial.write(send); last_packet_sent = send; lost_packet_timer->start(100); while(ack == false) { QApplication::processEvents(); } ui->exeProgressBar->setValue(i); } lost_packet_timer->stop(); ui->exeProgressBar->setValue(data.count()); ui->inFileName->setText("Transfer complete!"); ack = false; }