/***************************************************************************** ** Gui.cpp - main class of GUI (Main Window) ** Author: Kraku *****************************************************************************/ #include #include #include #include #include "Gui.h" #include "Settings.h" #include "Logic.h" #include "About.h" #ifdef Q_WS_X11 #include "SerialPort.h" #include "USBPort.h" #endif #ifdef Q_WS_WIN #include "USBPortWin.h" #include "SerialPortWin.h" #endif #include "const.h" #include "flasher.xpm" #include "icon.xpm" int Gui::port_type = SERIAL; Gui::Gui (QWidget * parent):QWidget (parent) { QThread::currentThread ()->setPriority (QThread::NormalPriority); path = "."; //current startup dir this->setWindowIcon (QIcon (QPixmap (icon))); this->setWindowTitle (tr ("GB Cart Flasher version ") + VER + tr(" ported by m0rph3us1987")); grid = new QGridLayout (this); left = new QVBoxLayout (); right = new QVBoxLayout (); center = new QVBoxLayout (); down = new QHBoxLayout (); image = new QLabel (this); image->setFixedSize (200, 162); settings = new Settings (this); left->addWidget (settings); left->addWidget (image); left->addStretch (1); grid->addLayout (left, 0, 0); console = new Console (this); QPixmap Logo (gameboy); image->setPixmap (Logo); right->addWidget (console); progress = new QProgressBar (this); down->addWidget (progress); cancel_btn = new QPushButton (tr ("Cancel"), this); cancel_btn->setEnabled (FALSE); down->addWidget (cancel_btn); right->addLayout (down); grid->addLayout (right, 0, 2); status_btn = new QPushButton (tr ("Cart Info"), this); rflash_btn = new QPushButton (tr ("Read FLASH"), this); wflash_btn = new QPushButton (tr ("Write FLASH"), this); rram_btn = new QPushButton (tr ("Read RAM"), this); wram_btn = new QPushButton (tr ("Write RAM"), this); eflash_btn = new QPushButton (tr ("Erase FLASH"), this); eram_btn = new QPushButton (tr ("Erase RAM"), this); about_btn = new QPushButton (tr ("About"), this); center->addWidget (status_btn, Qt::AlignTop); center->addWidget (rflash_btn); center->addWidget (wflash_btn); center->addWidget (rram_btn); center->addWidget (wram_btn); center->addWidget (eflash_btn); center->addWidget (eram_btn); center->addSpacing (20); center->addWidget (about_btn); center->addStretch (1); grid->addLayout (center, 0, 1); thread_WFLA = new WriteFlashThread; thread_RFLA = new ReadFlashThread; thread_E = new EraseThread; thread_RRAM = new ReadRamThread; thread_WRAM = new WriteRamThread; connect (cancel_btn, SIGNAL (clicked ()), thread_RFLA, SLOT (canceled ())); connect (cancel_btn, SIGNAL (clicked ()), thread_WFLA, SLOT (canceled ())); connect (cancel_btn, SIGNAL (clicked ()), thread_RRAM, SLOT (canceled ())); connect (cancel_btn, SIGNAL (clicked ()), thread_WRAM, SLOT (canceled ())); connect (cancel_btn, SIGNAL (clicked ()), thread_E, SLOT (canceled ())); connect (wflash_btn, SIGNAL (clicked ()), this, SLOT (write_flash ())); connect (rflash_btn, SIGNAL (clicked ()), this, SLOT (read_flash ())); connect (status_btn, SIGNAL (clicked ()), this, SLOT (show_info ())); connect (eflash_btn, SIGNAL (clicked ()), this, SLOT (erase_flash ())); connect (rram_btn, SIGNAL (clicked ()), this, SLOT (read_ram ())); connect (wram_btn, SIGNAL (clicked ()), this, SLOT (write_ram ())); connect (eram_btn, SIGNAL (clicked ()), this, SLOT (erase_ram ())); connect (about_btn, SIGNAL (clicked ()), this, SLOT (about ())); connect (thread_WFLA, SIGNAL (set_progress (int, int)), this, SLOT (setProgress (int, int))); connect (thread_RFLA, SIGNAL (set_progress (int, int)), this, SLOT (setProgress (int, int))); connect (thread_E, SIGNAL (set_progress (int, int)), this, SLOT (setProgress (int, int))); connect (thread_RRAM, SIGNAL (set_progress (int, int)), this, SLOT (setProgress (int, int))); connect (thread_WRAM, SIGNAL (set_progress (int, int)), this, SLOT (setProgress (int, int))); connect (thread_RFLA, SIGNAL (error (int)), this, SLOT (print_error (int))); connect (thread_WFLA, SIGNAL (error (int)), this, SLOT (print_error (int))); connect (thread_RRAM, SIGNAL (error (int)), this, SLOT (print_error (int))); connect (thread_WRAM, SIGNAL (error (int)), this, SLOT (print_error (int))); connect (thread_E, SIGNAL (error (int)), this, SLOT (print_error (int))); connect (settings, SIGNAL (refresh_ram_buttons (void)), this, SLOT (setRamButtons (void))); setProgress (0, 1); console->print (tr ("GB Cart Flasher version ") + VER + tr (" started.")); #ifdef Q_WS_WIN /* device detection is avilable only on Windows */ if (Settings::commanual == FALSE) { console->print (tr ("Detecting device...")); } #endif } AbstractPort * Gui::create_port (void) { switch (port_type) { case USB: #ifdef Q_WS_WIN return new USBPortWin; #endif #ifdef Q_WS_X11 return new USBPort; #endif case SERIAL: #ifdef Q_WS_WIN return new SerialPortWin; #endif #ifdef Q_WS_X11 return new SerialPort; #endif break; } return NULL; } void Gui::startup_info (void) { status_t status; int which_port = -1; //none at beggining if (Settings::commanual == FALSE) { port_type = USB; AbstractPort *port = create_port (); if (Logic::read_status (port, "USB", NREAD_ID, 0x00, 0x00, &status) == TRUE) { QString tmp; console->print (tr ("Device connected to: USB")); settings->setCom (4); //4 is index of usb in combobox tmp = tmp.sprintf (" %d%d.%d%d", status.ver_11, status.ver_12, status.ver_21, status.ver_22); console->print (tr ("Device firmware version:") + tmp); console->line (); return; } port_type = SERIAL; port = create_port (); for (int i = 0; i < PORTS_COUNT; i++) { if (Logic:: read_status (port, settings->getCom(i).toUtf8(), NREAD_ID, 0x00, 0x00, &status) == TRUE) { which_port = i; break; } } if (which_port == -1) { console->print (tr ("Device not found!")); console->print (tr ("Check COM port connection.")); } else { QString tmp; console->print (tr ("Device connected to: ") + settings->getCom (which_port)); settings->setCom (which_port); tmp = tmp.sprintf (" %d%d.%d%d", status.ver_11, status.ver_12, status.ver_21, status.ver_22); console->print (tr ("Device firmware version:") + tmp); } } console->line (); } void Gui::show_info () { status_t status; QString tmp; AbstractPort *port = create_port (); int return_code = Logic::read_status (port, settings->getCom().toUtf8(), READ_ID, settings->getMbc (), Settings::algorythm, &status); if (return_code == TRUE) /* no error */ { console->print (tr ("--Device information--")); tmp = tmp.sprintf (" %d%d.%d%d", status.ver_11, status.ver_12, status.ver_21, status.ver_22); console->print (tr ("Device firmware version:") + tmp); console->print ("\n" + tr ("--Cartridge information--")); tmp = tmp.sprintf (" 0x%x", status.manufacturer_id); console->print (tr ("FLASH memory manufacturer ID:") + tmp); tmp = tmp.sprintf (" %s", status.manufacturer); console->print (tr ("FLASH memory manufacturer name:") + tmp); tmp = tmp.sprintf (" 0x%x", status.chip_id); console->print (tr ("FLASH memory chip ID:") + tmp); if (Settings::showbbl == TRUE) { if (status.bbl == 1) tmp = tr ("Locked!"); else tmp = tr ("Unlocked"); console->print (tr ("Boot Block Status: ") + tmp); } if (status.logo_correct == 1) { console->print ("\n" + tr ("--ROM/FLASH content information--")); console->print (tr ("Game logo signature is correct.")); tmp = tmp.sprintf (" %s", status.game_name); console->print (tr ("Game title:") + tmp); if (status.cgb == 1) tmp = tr ("YES"); else tmp = tr ("NO"); console->print (tr ("Designed for Color GB: ") + tmp); if (status.sgb == 1) tmp = tr ("YES"); else tmp = tr ("NO"); console->print (tr ("Designed for Super GB: ") + tmp); tmp = tmp.sprintf (" %s", status.typ); console->print (tr ("Cartridge type:") + tmp); tmp = tmp.sprintf (" %s", status.rom_size); console->print (tr ("ROM size:") + tmp); tmp = tmp.sprintf (" %s", status.ram_size); console->print (tr ("RAM size:") + tmp); tmp = tmp.sprintf (" 0x%x", status.crc16); console->print (tr ("Checksum:") + tmp); console->line (); } else { console->print (tr ("Game logo signature is incorrect.")); console-> print (tr ("Cartridge is blank, damaged or not connected.")); console->line (); } } else print_error (return_code); } void Gui::read_flash (void) { file_name = QFileDialog::getSaveFileName (this, tr ("Write FLASH to..."), path, tr ("GB Rom Dumps (*.gb *.gbc *.sgb)")); path = Logic::get_path (file_name); if (file_name != "") { thread_RFLA->port = create_port (); if (thread_RFLA->port->open_port (settings->getCom().toUtf8()) == FALSE) { print_error (PORT_ERROR); return; } if (!file_name.contains (".gb", Qt::CaseInsensitive) && !file_name.contains (".gbc", Qt::CaseInsensitive) && !file_name.contains (".sgb", Qt::CaseInsensitive)) file_name = file_name + ".gb"; thread_RFLA->file = fopen (file_name.toUtf8 (), "wb"); thread_RFLA->mbc = settings->getMbc (); thread_RFLA->page_count = settings->getFlash () / 16; thread_RFLA->dap = Settings::dap; thread_RFLA->algorythm = Settings::algorythm; setEnabledButtons (FALSE); thread_RFLA->start (Settings::priority); console->print (tr ("Reading data from FLASH to file:") + "\n" + file_name); } } void Gui::write_flash (void) { file_name = QFileDialog::getOpenFileName (this, tr ("Read FLASH from..."), path, tr ("GB Rom Dumps (*.gb *.gbc *.sgb)")); path = Logic::get_path (file_name); if (file_name != "") { long bytes_count; short kilobytes_count; thread_WFLA->port = create_port (); if (thread_WFLA->port->open_port (settings->getCom().toUtf8()) == FALSE) { print_error (PORT_ERROR); return; } thread_WFLA->file = fopen (file_name.toUtf8 (), "rb"); thread_WFLA->mbc = settings->getMbc (); thread_WFLA->algorythm = Settings::algorythm; thread_WFLA->dap = Settings::dap; if (settings->isAuto () == FALSE) { bytes_count = Logic::file_size (thread_WFLA->file); thread_WFLA->page_count = (short) ((bytes_count % 16384L) ? (bytes_count / 16384 + 1) : (bytes_count / 16384L)); kilobytes_count = (short) ((bytes_count % 1024L) ? (bytes_count / 1024 + 1) : (bytes_count / 1024L)); } else if ((kilobytes_count = Logic::flash_file_size (thread_WFLA->file)) != FALSE) thread_WFLA->page_count = kilobytes_count / 16; else { print_error (WRONG_SIZE); thread_WFLA->port->close_port (); return; } setEnabledButtons (FALSE); thread_WFLA->start (Settings::priority); console->print (tr ("Writing data to FLASH from file:") + "\n" + file_name); console->print (tr ("File size: ") + QString::number (kilobytes_count) + "KB"); } } void Gui::read_ram (void) { file_name = QFileDialog::getSaveFileName (this, tr ("Write RAM to..."), path, tr ("GB Save (*.sav)")); path = Logic::get_path (file_name); if (file_name != "") { thread_RRAM->port = create_port (); if (thread_RRAM->port->open_port (settings->getCom().toUtf8()) == FALSE) { print_error (PORT_ERROR); return; } if (!file_name.contains (".sav", Qt::CaseInsensitive)) file_name = file_name + ".sav"; thread_RRAM->file = fopen (file_name.toUtf8 (), "wb"); thread_RRAM->mbc = settings->getMbc (); thread_RRAM->algorythm = Settings::algorythm; thread_RRAM->dap = Settings::dap; if (settings->getRam () == 2) { thread_RRAM->_2k = 1; thread_RRAM->page_count = 1; } else { thread_RRAM->_2k = 0; thread_RRAM->page_count = settings->getRam () / 8; } setEnabledButtons (FALSE); thread_RRAM->start (Settings::priority); console->print (tr ("Reading data from RAM to file:") + "\n" + file_name); } } void Gui::write_ram (void) { file_name = QFileDialog::getOpenFileName (this, tr ("Read RAM from..."), path, tr ("GB Save (*.sav)")); path = Logic::get_path (file_name); if (file_name != "") { long bytes_count; short kilobytes_count; thread_WRAM->port = create_port ();; if (thread_WRAM->port->open_port (settings->getCom().toUtf8()) == FALSE) { print_error (PORT_ERROR); return; } thread_WRAM->file = fopen (file_name.toUtf8 (), "rb"); thread_WRAM->mbc = settings->getMbc (); thread_WRAM->algorythm = Settings::algorythm; thread_WRAM->dap = Settings::dap; if (settings->isAuto () == FALSE) { bytes_count = Logic::file_size (thread_WRAM->file); if (bytes_count == 2048) { thread_WRAM->_2k = 1; thread_WRAM->page_count = 1; kilobytes_count = 2; } else { thread_WRAM->_2k = 0; thread_WRAM->page_count = (short) ((bytes_count % 8192L) ? (bytes_count / 8192L + 1) : bytes_count / 8192L); kilobytes_count = (short) ((bytes_count % 1024L) ? (bytes_count / 1024 + 1) : (bytes_count / 1024L)); } } else if ((kilobytes_count = Logic::ram_file_size (thread_WRAM->file)) != FALSE) if (kilobytes_count == 2) { thread_WRAM->_2k = 1; thread_WRAM->page_count = 1; } else { thread_WRAM->_2k = 0; thread_WRAM->page_count = kilobytes_count / 8; } else { print_error (WRONG_SIZE); thread_WRAM->port->close_port (); return; } setEnabledButtons (FALSE); thread_WRAM->start (Settings::priority); console->print (tr ("Writing data to RAM from file:") + "\n" + file_name); console->print (tr ("File size: ") + QString::number (kilobytes_count) + "KB"); } } void Gui::erase_flash (void) { thread_E->port = create_port (); if (thread_E->port->open_port (settings->getCom().toUtf8()) == FALSE) { print_error (PORT_ERROR); return; } thread_E->mbc = settings->getMbc (); thread_E->mem = EFLA; //FLASH thread_E->par = Settings::algorythm; thread_E->dap = Settings::dap; setEnabledButtons (FALSE); console->print (tr ("Erasing FLASH memory...")); thread_E->start (Settings::priority); } void Gui::erase_ram (void) { thread_E->port = create_port (); if (thread_E->port->open_port (settings->getCom().toUtf8()) == FALSE) { print_error (PORT_ERROR); return; } int window_count; thread_E->mbc = settings->getMbc (); thread_E->mem = ERAM; switch (settings->getRam ()) { case 2: case 8: window_count = 0; break; case 32: window_count = 3; break; case 128: window_count = 15; break; default: window_count = 15; } thread_E->par = window_count; thread_E->dap = Settings::dap; setEnabledButtons (FALSE); console->print (tr ("Erasing RAM memory...")); thread_E->start (Settings::priority); } void Gui::setProgress (int ile, int max) { progress->setMinimum (0); progress->setMaximum (max); progress->setValue (ile); } void Gui::setEnabledButtons (bool state) { status_btn->setEnabled (state); rflash_btn->setEnabled (state); wflash_btn->setEnabled (state); eflash_btn->setEnabled (state); cancel_btn->setEnabled (!state); //this buttons needs to be dissabled //if no ram is avilable if (settings->isRamDisabled ()) state = FALSE; rram_btn->setEnabled (state); wram_btn->setEnabled (state); eram_btn->setEnabled (state); } void Gui::setRamButtons () { if (status_btn->isEnabled ()) setEnabledButtons (TRUE); } void Gui::print_error (int err) { switch (err) { case FILEERROR_O: console->print (tr (">Error opening file.")); break; case FILEERROR_W: console->print (tr (">File write error.")); break; case FILEERROR_R: console->print (tr (">File read error.")); break; case SEND_ERROR: console->print (tr (">Error sending data to device.")); break; case TIMEOUT: console->print (tr (">Timeout!")); break; case END: console->print (tr (">Canceled.")); break; case PORT_ERROR: console->print (tr (">Error opening COM port.")); break; case WRONG_SIZE: console->print (tr (">Bad file size.")); break; case FALSE: console->print (tr (">Operation failure.")); break; case TRUE: console->print (tr (">Success!")); /* succes is not a error code */ break; } console->line (); setProgress (0, 1); setEnabledButtons (TRUE); } void Gui::about () { About about (this); about.exec (); }