Initial commit

This commit is contained in:
m0rph3us1987 2023-12-28 13:44:18 +01:00
commit 446fc018f2
36 changed files with 31201 additions and 0 deletions

57
About.cpp Normal file
View File

@ -0,0 +1,57 @@
/*****************************************************************************
** About.cpp - Source file of About DialogBox containing info about program
** Author: Kraku
*****************************************************************************/
#include "About.h"
#include "about.xpm"
#include "const.h"
About::About (QWidget * parent): QDialog(parent)
{
all = new QVBoxLayout (this);
this->setWindowTitle (tr ("About"));
QPixmap
logo (about_xpm);
image = new QLabel (this);
image->setFixedSize (501, 218);
image->setPixmap (logo);
all->addWidget (image);
box = new QGroupBox (tr ("GB Cart Flasher Project"), this);
box->setFixedWidth (501);
labels = new QVBoxLayout (box);
name =
new QLabel (tr ("GB Cart Flasher for Linux by m0rph3us1987 v") +
VER, box);
labels->addWidget (name);
copy = new QLabel ("Based on GB Cart Flasher by Kraku & Chroost", box);
labels->addWidget (copy);
email =
new
QLabel (tr
("e-mail: <a href=mailto:gbflasher@interia.pl>gbflasher@interia.pl</a>"),
box);
labels->addWidget (email);
translator = new QLabel(tr("Translation by: Chroost"),box);
labels->addWidget(translator);
desc1 = new QLabel (tr ("This program and device, called set, enables to:\n"
"- make game backups from owned cartridges and play them on PC,\n"
"- transfer game saves between cartridge and PC, save and modify them,\n"
"- test written by yourself games directly on console (rewritable cartridge required)."),
box);
labels->addWidget (desc1);
warning = new QLabel (tr ("<b>WARNING!</b>"), box);
labels->addWidget (warning);
desc2 =
new
QLabel (tr("Using this set for purposes other than previously listed,\n"
"especially for making illegal copies of copyrighted games is strictly prohibited!"), box);
labels->addWidget (desc2);
all->addWidget (box);
ok_btn = new QPushButton (tr ("Close"), this);
all->addWidget (ok_btn);
connect (ok_btn, SIGNAL (clicked ()), this, SLOT (close ()));
}

25
About.h Normal file
View File

@ -0,0 +1,25 @@
/*****************************************************************************
** About.h
** Author: Kraku
*****************************************************************************/
#ifndef _ABOUT_H_
#define _ABOUT_H_
#include <QDialog>
#include <QPushButton>
#include <QPixmap>
#include <QLabel>
#include <QBoxLayout>
#include <QGroupBox>
class About:public QDialog
{
Q_OBJECT QPushButton * ok_btn;
QLabel *image;
QVBoxLayout *all;
QGroupBox *box;
QLabel *name, *copy, *desc1, *desc2, *email, *warning, *translator;
QVBoxLayout *labels;
public:
About (QWidget * parent = 0);
};
#endif

28
AbstractPort.h Normal file
View File

@ -0,0 +1,28 @@
/*****************************************************************************
** AbstractPort.h
** Author: Kraku
*****************************************************************************/
#ifndef _ABSTRACTPORT_H_
#define _ABSTRACTPORT_H_
#include <QObject>
#include <QString>
class AbstractPort:public QObject
{
Q_OBJECT public:
virtual bool open_port (QString port_name) = 0;
virtual bool close_port () = 0;
virtual int receive_char () = 0;
virtual bool send_char (unsigned char character) = 0;
virtual int receive_packet (unsigned char *packet) = 0;
virtual int send_packet (unsigned char *packet) = 0;
virtual ~AbstractPort ()
{
};
virtual bool isOpen () = 0;
signals:
void error (int err);
};
#endif

44
Console.h Normal file
View File

@ -0,0 +1,44 @@
/*****************************************************************************
** Console.h - header of Console used to print infos from other
** modules
** Author: Kraku
*****************************************************************************/
#ifndef _CONSOLE_H_
#define _CONSOLE_H_
#include <QTextEdit>
#include <QString>
#include <QPalette>
#include <QColor>
class Console:public QTextEdit
{
public:
Console (QWidget * parent):QTextEdit (parent)
{
this->setMinimumWidth (400);
this->setReadOnly (TRUE);
QPalette palette;
palette.setColor (QPalette::Base, QColor (0, 255, 0));
this->setPalette (palette);
QFont font ("Courier");
font.setPointSize (8);
this->setFont (font);
}
void print (QString string)
{
append (string);
}
void line ()
{
#ifdef Q_WS_X11
print ("<br>");
#else
print ("<hr><br>");
#endif
}
};
#endif

66
EraseThread.cpp Normal file
View File

@ -0,0 +1,66 @@
/*****************************************************************************
** EraseThread.cpp
** Author: Kraku
*****************************************************************************/
#include "EraseThread.h"
#include "Logic.h"
#include "const.h"
#include "Settings.h"
void
EraseThread::run ()
{
time_t tp, t0; /* time for erase */
unsigned short crc16;
unsigned char packet[PACKETSIZE];
/* filling single erase packet */
memset (packet, 0x00, PACKETSIZE);
packet[0] = DATA;
packet[1] = ERASE;
packet[2] = mem;
packet[3] = mbc;
packet[4] = par;
packet[5] = Settings::dap;
crc16 = Logic::generate_crc16 (packet);
packet[PACKETSIZE - 2] = crc16 / 256;
packet[PACKETSIZE - 1] = crc16 % 256;
end = FALSE;
/* send erase packet */
if (port->send_packet (packet) < PACKETSIZE)
{
port->close_port ();
emit error (SEND_ERROR);
return;
}
t0 = tp = time (NULL);
do
{
/* end of thread - operation canceled */
if(end) {
port->close_port();
emit error (END);
return;
}
/* erase done */
if (port->receive_char () == ACK)
{
port->close_port ();
emit set_progress (1, 1);
emit error (TRUE);
return;
}
if (time (NULL) != tp)
emit set_progress (time (NULL) - tp, DELTIME);
}
while (time (NULL) - tp < DELTIME);
/* wait for erase DELTIME sec.
* hardware independent!
*/
emit set_progress (1, 1); //100%
port->close_port ();
emit error (TIMEOUT);
return;
}

31
EraseThread.h Normal file
View File

@ -0,0 +1,31 @@
/*****************************************************************************
** EraseThread.h - Header file of thread responsible for process of
** FLASH and RAM erase
** Author: Kraku
*****************************************************************************/
#ifndef _ERASETHREAD_H_
#define _ERASETHREAD_H_
#include <QThread>
#include "AbstractPort.h"
#include "Logic.h"
class EraseThread:public QThread
{
Q_OBJECT
public:
char mem; /* memory type for erase */
char mbc; /* Memory Bank Controler type */
char par;
char dap;
bool end; /* end of thread marker */
AbstractPort *port;
/* main point of thread */
virtual void run ();
public slots:
void canceled (void) { end = TRUE; }
signals:
void set_progress (int ile, int max);
void error (int err);
};
#endif

646
Gui.cpp Normal file
View File

@ -0,0 +1,646 @@
/*****************************************************************************
** Gui.cpp - main class of GUI (Main Window)
** Author: Kraku
*****************************************************************************/
#include <QFileDialog>
#include <QPixmap>
#include <QMessageBox>
#include <QThread>
#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 ();
}

71
Gui.h Normal file
View File

@ -0,0 +1,71 @@
/*****************************************************************************
** Gui.h - class of main dialog window
** Author: Kraku
*****************************************************************************/
#include <QWidget>
#include <QLayout>
#include <QLabel>
#include <QProgressBar>
#include <QPushButton>
#include <QString>
#include "Settings.h"
#include "Console.h"
#include "Logic.h"
#include "About.h"
#include "ReadFlashThread.h"
#include "WriteFlashThread.h"
#include "EraseThread.h"
#include "ReadRamThread.h"
#include "WriteRamThread.h"
class Gui:public QWidget
{
Q_OBJECT Settings * settings;
Console *console;
QGridLayout *grid;
QVBoxLayout *left;
QVBoxLayout *right;
QVBoxLayout *center;
QHBoxLayout *down;
QProgressBar *progress;
QLabel *image;
QPixmap *logo;
QPushButton *cancel_btn;
QPushButton *status_btn;
QPushButton *rflash_btn;
QPushButton *wflash_btn;
QPushButton *rram_btn;
QPushButton *wram_btn;
QPushButton *eflash_btn;
QPushButton *eram_btn;
QPushButton *about_btn;
QString file_name;
QString path;
About about_dlg;
WriteFlashThread *thread_WFLA;
ReadFlashThread *thread_RFLA;
EraseThread *thread_E;
ReadRamThread *thread_RRAM;
WriteRamThread * thread_WRAM;
public:
Gui (QWidget * parent = 0);
static int port_type;
public slots:void startup_info (void);
void setEnabledButtons (bool stan);
void setRamButtons ();
void print_error (int err);
void write_flash (void);
void read_flash (void);
void read_ram (void);
void write_ram (void);
void show_info (void);
void erase_flash (void);
void erase_ram (void);
void about ();
void setProgress (int ile, int max);
AbstractPort *create_port ();
};

320
Logic.cpp Normal file
View File

@ -0,0 +1,320 @@
/*****************************************************************************
** Logic.cpp - Source file containing all utility functions used in
** communication process by Threads and Gui
** Author: Kraku
*****************************************************************************/
#include "Logic.h"
#include "const.h"
#include "AbstractPort.h"
#include <ctype.h>
#include <cassert>
/* array used to generate crc16 */
unsigned short crc16_tab[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
/* array of producers names and codes */
desc_t producers[] = {
{0x01, "AMD"}, {0x02, "AMI"}, {0xe5, "Analog Devices"},
{0x1f, "Atmel"}, {0x31, "Catalyst"}, {0x34, "Cypress"},
{0x04, "Fujitsu"}, {0xE0, "Goldstar"}, {0x07, "Hitachi"},
{0xad, "Hyundai"}, {0xc1, "Infineon"}, {0x89, "Intel"},
{0xd5, "Intg. Silicon Systems"}, {0xc2, "Macronix"}, {0x29, "Microchip"},
{0x2c, "Micron"}, {0x1c, "Mitsubishi"}, {0x10, "Nec"},
{0x15, "Philips Semiconductors"}, {0xce, "Samsung"}, {0x62, "Sanyo"},
{0x20, "SGS Thomson"}, {0xb0, "Sharp"}, {0xbf, "SST"},
{0x97, "Texas Instruments"}, {0x98, "Toshiba"}, {0xda, "Winbond"},
{0x19, "Xicor"}, {0xc9, "Xilinx"}
};
/* array of cart types - source GB CPU Manual */
desc_t carts[] = {
{0x00, "ROM ONLY"}, {0x01, "ROM+MBC1"},
{0x02, "ROM+MBC1+RAM"}, {0x03, "ROM+MBC1+RAM+BATT"},
{0x05, "ROM+MBC2"}, {0x06, "ROM+MBC2+BATTERY"},
{0x08, "ROM+RAM"}, {0x09, "ROM+RAM+BATTERY"},
{0x11, "ROM+MBC3"},
{0x0b, "ROM+MMMO1"}, {0x0c, "ROM+MMMO1+SRAM"},
{0x0d, "ROM+MMMO1+SRAM+BATT"}, {0x0f, "ROM+MBC3+TIMER+BATT"},
{0x10, "ROM+MBC3+TIMER+RAM+BAT"}, {0x12, "ROM+MBC3+RAM"},
{0x13, "ROM+MBC3+RAM+BATT"}, {0x19, "ROM+MBC5"},
{0x1a, "ROM+MBC5+RAM"}, {0x1b, "ROM+MBC5+RAM+BATT"},
{0x1c, "ROM+MBC5+RUMBLE"}, {0x1d, "ROM+MBC5+RUMBLE+SRAM"},
{0x1e, "ROM+MBC5+RUMBLE+SRAM+BATT"}, {0x1f, "Pocket Camera"},
{0xfd, "Bandai TAMA5"}, {0xfe, "Hudson HuC-3"}
};
desc_t rom_sizes[] = {
{0x00, "32KB"}, {0x01, "64KB"}, {0x02, "128KB"}, {0x03, "256KB"},
{0x04, "512KB"}, {0x05, "1MB"}, {0x06, "2MB"}, {0x52, "1.1MB"},
{0x53, "1.2MB"}, {0x54, "1.5MB"}
};
desc_t ram_sizes[] = {
{0x00, "0KB"}, {0x01, "2KB"}, {0x02, "8KB"}, {0x03, "32KB"}, {0x04, "128KB"}
};
Logic::Logic (QObject * parent):QObject (parent)
{
//version with threads
//TODO: move it
}
int
Logic::read_status (AbstractPort * port, const char *port_name, char id, char mbc,
char algorythm, status_t * flasher_stat)
{
assert (port != NULL);
if (port->open_port (port_name) == FALSE)
return PORT_ERROR;
unsigned short crc16;
unsigned char packet[PACKETSIZE];
memset (packet, 0x00, PACKETSIZE);
packet[0] = DATA;
packet[1] = STATUS;
packet[2] = id;
packet[3] = mbc;
packet[4] = algorythm;
crc16 = generate_crc16 (packet);
packet[PACKETSIZE - 2] = crc16 / 256;
packet[PACKETSIZE - 1] = crc16 % 256;
if (port->send_packet (packet) < PACKETSIZE)
{
port->close_port ();
return SEND_ERROR;
}
else
{
if (port->receive_packet (packet) == DATA)
{
int i, producers_count = sizeof producers / sizeof producers[0];
int types_count = sizeof carts / sizeof carts[0];
int types_count_rom = sizeof rom_sizes / sizeof rom_sizes[0];
int types_count_ram = sizeof ram_sizes / sizeof ram_sizes[0];
/* filling struct with data from packet */
flasher_stat->ver_11 = packet[2] / 16;
flasher_stat->ver_12 = packet[2] % 16;
flasher_stat->ver_21 = packet[3] / 16;
flasher_stat->ver_22 = packet[3] % 16;
flasher_stat->manufacturer_id = packet[4];
/* if code if not found - it remains unknown */
strcpy (flasher_stat->manufacturer,
tr ("Unknown manufacturer").toLocal8Bit ());
for (i = 0; i < producers_count; i++)
if (flasher_stat->manufacturer_id == producers[i].index)
{
memset (flasher_stat->manufacturer, 0x00, 30);
strcpy (flasher_stat->manufacturer, producers[i].name);
}
flasher_stat->chip_id = packet[5];
flasher_stat->bbl = packet[6] & 0x01;
flasher_stat->logo_correct = packet[8];
memcpy (flasher_stat->game_name, &packet[9], 16);
for (int i = 0; i < 16; i++)
if (!isalnum (flasher_stat->game_name[i])
|| flasher_stat->game_name[i] == '\n')
flasher_stat->game_name[i] = ' ';
flasher_stat->game_name[16] = '\0';
flasher_stat->cgb = (packet[24] == 0x80) ? 1 : 0;
flasher_stat->sgb = (packet[27] == 0x03) ? 1 : 0;
strcpy (flasher_stat->typ, tr ("Unknown type").toLocal8Bit ());
for (i = 0; i < types_count; i++)
if (packet[28] == carts[i].index)
{
memset (flasher_stat->typ, 0x00, 30);
strcpy (flasher_stat->typ, carts[i].name);
}
for (i = 0; i < types_count_rom; i++)
if (packet[29] == rom_sizes[i].index)
{
memset (flasher_stat->rom_size, 0x00,
sizeof flasher_stat->rom_size);
strcpy (flasher_stat->rom_size, rom_sizes[i].name);
}
for (i = 0; i < types_count_ram; i++)
if (packet[30] == ram_sizes[i].index)
{
memset (flasher_stat->ram_size, 0x00,
sizeof flasher_stat->ram_size);
strcpy (flasher_stat->ram_size, ram_sizes[i].name);
}
flasher_stat->crc16 = 256 * packet[35] + packet[36];
port->close_port ();
return TRUE;
}
else
{
port->close_port ();
return FALSE;
}
}
}
unsigned short
Logic::generate_crc16 (unsigned char packet[PACKETSIZE])
{
int i;
unsigned short crc16 = 0x0000;
/* generate for whole packet, except for two last bytes */
for (i = 0; i < PACKETSIZE - 2; i++)
crc16 = (crc16 << 8) ^ crc16_tab[((crc16 >> 8) ^ packet[i]) & 0xFF];
return crc16;
}
void
Logic::fill_data_packet (unsigned char packet[PACKETSIZE],
unsigned char data[FRAMESIZE], char packet_type,
unsigned char packet_index, int page_index)
{
unsigned short crc16;
memset (packet, 0x00, PACKETSIZE);
packet[0] = DATA;
packet[1] = packet_type;
packet[2] = RESERVED;
packet[3] = packet_index;
packet[4] = page_index / 256;
packet[5] = page_index % 256;
/* copy data to packet */
memcpy (&packet[6], data, FRAMESIZE);
/* generate and set crc */
crc16 = generate_crc16 (packet);
packet[PACKETSIZE - 2] = crc16 / 256;
packet[PACKETSIZE - 1] = crc16 % 256;
}
int
Logic::check_packet (unsigned char packet[PACKETSIZE])
{
unsigned short crc16 = generate_crc16 (packet);
/* data packet with correct crc */
if (packet[0] == DATA && packet[PACKETSIZE - 2] == crc16 / 256
&& packet[PACKETSIZE - 1] == crc16 % 256)
return packet[1]; /* return packet type */
else
return BAD_PACKET;
}
long
Logic::file_size (FILE * file)
{
long size = 0;
fseek (file, 0x00, SEEK_END);
size = ftell (file);
fseek (file, 0x00, SEEK_SET);
return size;
}
short
Logic::flash_file_size (FILE * file)
{
long mem_size = Logic::file_size (file);
/* file_size w kB */
switch (mem_size)
{
case 32 * 1024:
case 64 * 1024:
case 128 * 1024:
case 256 * 1024:
case 512 * 1024:
case 1024 * 1024:
case 2048 * 1024:
case 4096 * 1024:
case 8192 * 1024:
return (short) (mem_size / 1024L);
default:
return FALSE;
}
}
short
Logic::ram_file_size (FILE * file)
{
long mem_size = Logic::file_size (file);
switch (mem_size)
{
case 2 * 1024:
case 8 * 1024:
case 32 * 1024:
case 128 * 1024:
return (short) (mem_size / 1024L);
default:
return FALSE;
}
}
bool
Logic::send_start_packet (AbstractPort * port, config_t cfg)
{
unsigned short crc16;
unsigned char packet[PACKETSIZE];
memset (packet, 0x00, PACKETSIZE);
packet[0] = DATA;
packet[1] = CONFIG;
packet[2] = cfg.operation;
packet[3] = cfg.mbc;
packet[4] = cfg.algorythm;
packet[5] = cfg.dap;
packet[6] = (cfg.page_count - 1) / 256;
packet[7] = (cfg.page_count - 1) % 256;
crc16 = Logic::generate_crc16 (packet);
packet[PACKETSIZE - 2] = crc16 / 256;
packet[PACKETSIZE - 1] = crc16 % 256;
if (port->send_packet (packet) < PACKETSIZE)
return FALSE;
else
return TRUE;
}
QString
Logic::get_path (QString name)
{
int end;
if ((end = name.lastIndexOf ("/")) != -1)
{
return name.left (end);
}
else
return QString (".");
}

92
Logic.h Normal file
View File

@ -0,0 +1,92 @@
/*****************************************************************************
** Logic.h - Header file for utility functions used in communication proces
** Author: Kraku
*****************************************************************************/
#ifndef _LOGIC_H_
#define _LOGIC_H_
#include <QObject>
#include "const.h"
#include "AbstractPort.h"
/*
* structure consist of key/value pairs for any kind of descriptions
* most of those codes/descriptions are taken from GB CPU Manual
*/
typedef struct
{
unsigned char index;
char name[30];
} desc_t;
/* struct being used to fill packet header */
typedef struct
{
unsigned char operation;
unsigned char mbc;
unsigned char algorythm;
unsigned char dap;
int page_count;
} config_t;
/* struct filled by status */
typedef struct
{
/* digits describing version of device soft */
unsigned char ver_11;
unsigned char ver_12;
unsigned char ver_21;
unsigned char ver_22;
/* flash chip date */
unsigned char manufacturer_id;
char manufacturer[30];
unsigned char chip_id;
unsigned char bbl;
/* info about loaded game */
unsigned char logo_correct;
unsigned char cgb;
unsigned char sgb;
char rom_size[6];
char ram_size[6];
unsigned short crc16;
char typ[30];
char game_name[17];
} status_t;
/* Logic has to inherit from QObject in order to send signals */
class Logic:public QObject
{
Q_OBJECT public:
/* generate crc16 checksum stored in last two bytes of packet */
static unsigned short generate_crc16 (unsigned char packet[PACKETSIZE]);
/* both function calculate file size, and check if it's correct ROM/RAM size
* if it's OK it returns file size in kB else return FALSE
*/
static short flash_file_size (FILE * file);
static short ram_file_size (FILE * file);
/* additional function returning exact file size in B */
static long file_size (FILE * file);
/* function extracting path from fully qualified filename */
static QString get_path (QString name);
/* check packet type and crc
* return packet type if ok or BAD_PACKET otherwise
*/
static int check_packet (unsigned char packet[PACKETSIZE]);
/* create data packet from data, and set packet/page number and crc */
static void fill_data_packet (unsigned char packet[PACKETSIZE],
unsigned char data[FRAMESIZE],
char packet_type, unsigned char packet_number,
int page_number);
Logic (QObject * parent = 0);
/* query device for status of itself and cart, fills status_t struct */
static int read_status (AbstractPort * port, const char *name_portu, char id,
char mbc, char alg, status_t * flasher_stat);
/* sends start packet generateg from given configuration */
static bool send_start_packet (AbstractPort * port, config_t cfg);
signals:
void set_progress (int procent, int max);
void refresh (void);
};
#endif

177
ReadFlashThread.cpp Normal file
View File

@ -0,0 +1,177 @@
/*****************************************************************************
** ReadFlashThread.cpp
** Author: Kraku
*****************************************************************************/
#include "ReadFlashThread.h"
#include "Settings.h"
#include "Logic.h"
#include "const.h"
void
ReadFlashThread::run ()
{
end = FALSE;
unsigned char packet[72], data[16384];
int character, data_type = 0x00, recived = 0, retries =
0, page_number, packet_number, prv_count = 0;
config_t cfg;
cfg.operation = RROM;
cfg.mbc = mbc;
cfg.algorythm = algorythm;
cfg.dap = Settings::dap;
cfg.page_count = page_count;
if (file == NULL)
{
port->close_port ();
emit error (FILEERROR_O);
return;
}
do
{ /* send start packet and wait for first one of response */
if (Logic::send_start_packet (port, cfg) == FALSE)
{
port->close_port ();
fclose (file);
emit error (SEND_ERROR);
return;
}
character = port->receive_packet (packet);
if (character == END || character == TIMEOUT)
{
port->close_port ();
fclose (file);
emit error (character);
return;
}
if (character == DATA) /* if packet received - check it */
data_type = Logic::check_packet (packet);
}
while (data_type != NORMAL_DATA && ++retries < 10);
if (retries == 10)
{
port->close_port ();
fclose (file);
emit error (TIMEOUT);
return;
}
retries = 0;
/* work until LAST_DATA */
do
{
if (recived != 0) /* if first packet, don't need to get it */
character = port->receive_packet (packet);
if (character == TIMEOUT || character == END)
{
port->close_port ();
fclose (file);
emit error (character);
return;
}
//end of thread!!!!
if (end)
{
port->send_char (END);
port->close_port ();
fclose (file);
emit error (END);
return;
}
data_type = Logic::check_packet (packet);
if (data_type == NORMAL_DATA || data_type == LAST_DATA)
{ /* valid data packet */
page_number = recived / 256; /* 256 packets = page */
packet_number = recived % 256;
retries = 0;
/* current packet */
if (packet_number == packet[3]
&& page_number == packet[4] * 256 + packet[5])
{
memcpy (&data[packet_number * 64], &packet[6], FRAMESIZE);
if (packet_number == 255) /* if entire page - save it to file */
if (fwrite (data, 1, sizeof data, file) < sizeof data)
{
port->close_port ();
fclose (file);
emit error (FILEERROR_W);
return;
}
port->send_char (ACK); /* send confirmation */
recived++;
prv_count = 0;
/* set progress bar status */
emit set_progress (recived, page_count * 256 - 1);
}
/* last packet received- packet is lost */
else if (((packet_number - 1) % 255) == packet[3])
{
/* device is sending last packets - end of transmision */
if (++prv_count == 10)
{
port->send_char (END);
port->close_port ();
fclose (file);
emit error (END);
return;
}
else
port->send_char (ACK);
/* confirm receivment, force device to send current packet */
}
else
{ /* valid packet, but not current nor last */
port->send_char (END);
port->close_port ();
fclose (file);
emit error (END);
return;
}
}
else
{ /* bad data or NAK */
if (++retries < 10)
port->send_char (NAK);
else
{
port->send_char (END);
port->close_port ();
fclose (file);
emit error (END);
return;
}
}
}
while (data_type != LAST_DATA);
/* if correct data size received - end */
if (recived * 64 == page_count * 16384)
{
port->close_port ();
fclose (file);
emit error (TRUE);
}
else
{
port->close_port ();
fclose (file);
emit error (END);
}
}
void
ReadFlashThread::canceled (void)
{
end = TRUE;
}

33
ReadFlashThread.h Normal file
View File

@ -0,0 +1,33 @@
/*****************************************************************************
** ReadFlashThread.h
** Author: Kraku
*****************************************************************************/
#ifndef _READFLASHTHREAD_H_
#define _READFLASHTHREAD_H_
#include <QThread>
#include "AbstractPort.h"
#include "Logic.h"
class ReadFlashThread:public QThread
{
Q_OBJECT public:
ReadFlashThread ()
{
}
virtual void run ();
bool end;
FILE *file;
char mbc;
char algorythm;
char dap;
int page_count;
AbstractPort *port;
public slots:void canceled (void);
signals:
void set_progress (int ile, int max);
void error (int err);
};
#endif

184
ReadRamThread.cpp Normal file
View File

@ -0,0 +1,184 @@
/*****************************************************************************
** ReadRamThread.cpp
** Author: Kraku
*****************************************************************************/
#include "ReadRamThread.h"
#include "Settings.h"
#include "Logic.h"
#include "const.h"
void
ReadRamThread::run ()
{
end = FALSE;
unsigned char packet[72], data[2048]; /* 2kB cart is avilable */
int n, data_type = 0x00, recived = 0, retries =
0, page_number, packet_number, prv_count = 0;
config_t cfg;
cfg.operation = RRAM;
cfg.mbc = mbc;
cfg.algorythm = algorythm;
cfg.dap = Settings::dap;
cfg.page_count = page_count;
if (_2k) /* if only 2kB to process */
page_count = 1; /* treat as 8kB - one page of RAM */
if (file == NULL)
{
port->close_port ();
emit error (FILEERROR_O);
return;
}
do
{
if (Logic::send_start_packet (port, cfg) == FALSE)
{
port->close_port ();
fclose (file);
emit error (SEND_ERROR);
return;
}
n = port->receive_packet (packet);
if (n == END || n == TIMEOUT)
{
port->close_port ();
fclose (file);
emit error (n);
return;
}
if (n == DATA)
data_type = Logic::check_packet (packet);
}
while (data_type != NORMAL_DATA && ++retries < 10);
if (retries == 10)
{
port->close_port ();
fclose (file);
emit error (TIMEOUT);
return;
}
retries = 0;
do
{
if (recived != 0)
n = port->receive_packet (packet);
if (n == TIMEOUT || n == END)
{
port->close_port ();
fclose (file);
emit error (n);
return;
}
//end of thread!!!!
if (end)
{
port->send_char (END);
port->close_port ();
fclose (file);
emit error (END);
return;
}
data_type = Logic::check_packet (packet);
if (data_type == NORMAL_DATA || data_type == LAST_DATA)
{ /* good packet */
page_number = recived / 128; /* each ram page consist of 128 packets */
packet_number = recived % 128;
retries = 0;
/* current packet */
if (packet_number == packet[3]
&& page_number == packet[4] * 256 + packet[5])
{
memcpy (&data[(packet_number % 32) * 64], &packet[6],
FRAMESIZE);
if (packet_number % 32 == 31)
if (fwrite (data, 1, sizeof data, file) < sizeof data)
{
port->close_port ();
fclose (file);
emit error (FILEERROR_W);
return;
}
/* if only 2kB RAM, then force end of transmision (send END),
* device try to process whole page - 8kB*/
if (_2k && recived == 31)
{ /*_2k => page_count = 1 */
port->send_char (END);
port->close_port ();
fclose (file);
emit error (TRUE);
return;
}
else
port->send_char (ACK);
recived++;
prv_count = 0;
/* set amount of data with _2k flag */
emit set_progress (recived + 1, _2k ? 32 : page_count * 128);
}
else if (((packet_number - 1) % 127) == packet[3])
{ /* last packet */
if (++prv_count == 10)
{
port->send_char (END);
port->close_port ();
fclose (file);
emit error (END);
return;
}
else
port->send_char (ACK);
}
else
{ /* packet valid but not current */
port->send_char (END);
port->close_port ();
fclose (file);
emit error (END);
return;
}
}
else
{ /* bad data or NAK */
if (++retries < 10)
port->send_char (NAK);
else
{
port->send_char (END);
port->close_port ();
fclose (file);
emit error (END);
return;
}
}
}
while (data_type != LAST_DATA);
if (recived * 64 == page_count * 8192)
{
port->close_port ();
fclose (file);
emit error (TRUE);
return;
}
else
{
port->close_port ();
fclose (file);
emit error (END);
return;
}
}
void
ReadRamThread::canceled (void)
{
end = TRUE;
}

33
ReadRamThread.h Normal file
View File

@ -0,0 +1,33 @@
/*****************************************************************************
** ReadRamThread.h
** Author: Kraku
*****************************************************************************/
#ifndef _READRAMTHREAD_H_
#define _READRAMTHREAD_H_
#include <QThread>
#include "AbstractPort.h"
#include "Logic.h"
class ReadRamThread:public QThread
{
Q_OBJECT public:
virtual void run ();
ReadRamThread ()
{
}
bool end;
FILE *file;
char _2k;
char mbc;
char algorythm;
char dap;
int page_count;
AbstractPort *port;
public slots:void canceled (void);
signals:
void set_progress (int ile, int max);
void error (int err);
};
#endif

173
SerialPort.cpp Normal file
View File

@ -0,0 +1,173 @@
/*****************************************************************************
** SerialPort.cpp
** Author: Kraku
*****************************************************************************/
#include "const.h"
#include "SerialPort.h"
extern "C"{
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
/*
* Header files for RS232C support under Linux
*/
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
}
SerialPort::SerialPort()
:AbstractPort()
{
descriptor = -1;
/* Descriptor -1 is invalid - something like NULL */
}
bool SerialPort::open_port(QString port_name)
{
/* Open port in RW mode, don't check DCD line */
descriptor = open (port_name.toUtf8(), O_RDWR | O_NOCTTY | O_NDELAY);
if (descriptor != -1) /* is port opened */
{
opened = TRUE;
struct termios ts; /* structure describing port */
tcgetattr (descriptor, &ts); /* get actual state of port */
/*
* set line settings
*/
cfsetispeed (&ts, (speed_t)B115200);
cfsetospeed (&ts, (speed_t)B115200);
ts.c_cflag |= (CLOCAL | CREAD); /* important */
ts.c_cflag &= ~PARENB; /* no parity */
ts.c_cflag &= ~CSTOPB; /* 1 stop bit */
ts.c_cflag &= ~CSIZE;
ts.c_cflag |= CS8; /* 8 data bits */
/*
* raw input/output
*/
ts.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
ts.c_iflag &= ~(IXON | IXOFF | IXANY);
ts.c_oflag &= ~OPOST;
ts.c_iflag &= ~(INLCR | IGNCR | ICRNL);
/*
* set all info
*/
tcsetattr (descriptor, TCSANOW, &ts);
fcntl (descriptor, F_SETFL, FNDELAY); /* don't wait for data while reading */
return TRUE;
}
else
return FALSE;
}
bool SerialPort::close_port ()
{
if (descriptor == -1)
return FALSE;
else
{
close (descriptor);
opened = FALSE;
return TRUE;
}
}
int SerialPort::send_packet(unsigned char packet[PACKETSIZE])
{
return write (descriptor, packet, PACKETSIZE);
}
bool SerialPort::send_char (unsigned char character)
{
if (write (descriptor, &character, 1))
return TRUE;
else
return FALSE;
}
int SerialPort::receive_char (void)
{
time_t tp = time (NULL); /* save current time */
unsigned char character;
int read_count = 0;
do
{
read_count = read (descriptor, &character, 1); /* try to read char... */
}
while (read_count <= 0 && time (NULL) - tp < SLEEPTIME);
/*
* ...until done or SLEEPTIME is over
*/
if (read_count == 0)
return TIMEOUT;
/* ACK and END are only accepted chars */
if (character == ACK || character == END)
return character;
else
return NAK;
}
int SerialPort::receive_packet (unsigned char *packet)
{
time_t tp = time (NULL);
int read_count;
do
{
read_count = read (descriptor, packet, 1);
}
while (read_count <= 0 && time (NULL) - tp < SLEEPTIME);
if (read_count <= 0)
return TIMEOUT;
else
{
if (packet[0] != DATA) /* if it's not a packet, then treat it as char */
{
if (packet[0] == ACK)
return ACK;
else if (packet[0] == END)
return END;
else
return NAK;
}
else /* if packet, read rest of it */
{
int data_left = PACKETSIZE - 1;
tp = time (NULL);
do
{
/*
* read rest of data and put it in packet
*/
read_count =
read (descriptor, &packet[PACKETSIZE - data_left], data_left);
if (read_count > 0)
{
data_left -= read_count;
tp = time (NULL); /* reset wait timer */
}
}
while (data_left != 0 && time (NULL) - tp < SLEEPTIME);
/*
* read until packet is full or time ends
*/
if (data_left > 0)
return TIMEOUT;
else
return DATA; /* DATA signals read of full packet */
}
}
}

30
SerialPort.h Normal file
View File

@ -0,0 +1,30 @@
/*****************************************************************************
** SerialPort.h - SerialPort driver for Linux/Posix based systems
** Author: Kraku
*****************************************************************************/
#ifndef _SERIALPORT_H_
#define _SERIALPORT_H_
#include "AbstractPort.h"
class SerialPort:public AbstractPort
{
Q_OBJECT
int descriptor;
bool opened;
public:
SerialPort ();
bool open_port (QString port_name);
bool close_port ();
int receive_char ();
bool send_char (unsigned char character);
int receive_packet (unsigned char *packet);
int send_packet (unsigned char *packet);
bool isOpen ()
{
return opened;
}
signals:
void error (int err);
};
#endif

61
SerialPortWin.cpp Normal file
View File

@ -0,0 +1,61 @@
/*
#include "const.h"
#include "AbstractPort.h"
#include "SerialPortWin.h"
#include "Settings.h"
extern "C"{
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
}
SerialPortWin::SerialPortWin()
:AbstractPort()
{
//hCommDev=NULL;
}
bool SerialPortWin::open_port(QString port_name)
{
return FALSE;
}
bool SerialPortWin::close_port ()
{
return TRUE;
}
int SerialPortWin::send_packet (unsigned char packet[PACKETSIZE])
{
return 0;
}
bool SerialPortWin::send_char (unsigned char character)
{
return FALSE;
}
int SerialPortWin::receive_char (void)
{
return 0;
}
int SerialPortWin::receive_packet (unsigned char *packet)
{
return 0;
}
*/

37
SerialPortWin.h Normal file
View File

@ -0,0 +1,37 @@
/*
#ifndef _SERIALPORTWIN_H_
#define _SERIALPORTWIN_H_
#include <windows.h>
#include "AbstractPort.h"
#include <time.h>
class SerialPortWin : public AbstractPort
{
Q_OBJECT
HANDLE hCommDev;
DCB dcb;
COMSTAT Stat;
DWORD Errors;
bool opened;
public:
SerialPortWin();
bool open_port (QString port_name);
bool close_port ();
int receive_char ();
bool send_char (unsigned char character);
int receive_packet (unsigned char *packet);
int send_packet (unsigned char *packet);
bool isOpen()
{
return opened;
}
signals:
void error(int err);
};
#endif
*/

320
Settings.cpp Normal file
View File

@ -0,0 +1,320 @@
/*****************************************************************************
** Settings.cpp
** Author: Kraku
*****************************************************************************/
#include <QLabel>
#include <QLayout>
#include <QComboBox>
#include <QMessageBox>
#include <QSettings>
#include "Settings.h"
#include "Gui.h"
#include <math.h>
bool
Settings::commanual = FALSE;
alg_t
Settings::algorythm = ALG16;
dap_t
Settings::dap = TOGGLE;
bool
Settings::showbbl = FALSE;
speed_type
Settings::speed = STANDARD;
QThread::Priority Settings::priority = QThread::NormalPriority;
Settings::Settings (QWidget * parent):QGroupBox (tr ("Settings"), parent)
{
QSettings
set;
labels = new QVBoxLayout ();
combo_boxes = new QVBoxLayout ();
down = new QHBoxLayout ();
north = new QHBoxLayout ();
all = new QVBoxLayout ();
com_label = new QLabel ("PORT:", this);
labels->addWidget (com_label);
com_combo = new QComboBox (this);
combo_boxes->addWidget (com_combo);
#ifdef Q_WS_X11
com_combo->insertItem (0, "/dev/ttyS0");
com_combo->insertItem (1, "/dev/ttyS1");
com_combo->insertItem (2, "/dev/ttyS2");
if (set.contains ("user_com"))
{
com_combo->insertItem (3, set.value ("user_com").toString ());
com_combo->setCurrentIndex (3);
}
else
{
// /dev/flasher can be symbolic link to device,
// if it's connected to some strange port
com_combo->insertItem (3, "/dev/flasher");
}
com_combo->insertItem (4, "USB");
#endif
#ifdef Q_WS_WIN
com_combo->insertItem (0, "COM1");
com_combo->insertItem (1, "COM2");
com_combo->insertItem (2, "COM3");
if (set.contains ("user_com"))
{
com_combo->insertItem (3, set.value ("user_com").toString ());
com_combo->setCurrentIndex (3);
}
else
{
com_combo->insertItem (3, "COM4");
}
com_combo->insertItem (4, "USB");
#endif
mbc_label = new QLabel ("MBC:", this);
labels->addWidget (mbc_label);
mbc_combo = new QComboBox (this);
combo_boxes->addWidget (mbc_combo);
mbc_combo->insertItem (0, "MBC AUTO");
mbc_combo->insertItem (1, "MBC1");
mbc_combo->insertItem (2, "MBC2");
mbc_combo->insertItem (3, "MBC3");
mbc_combo->insertItem (4, "ROM ONLY");
mbc_combo->insertItem (5, "MBC5");
mbc_combo->insertItem (6, "RUMBLE");
flash_label = new QLabel ("FLASH:", this);
labels->addWidget (flash_label);
flash_combo = new QComboBox (this);
combo_boxes->addWidget (flash_combo);
flash_combo->insertItem (0, "32 KB");
flash_combo->insertItem (1, "64 KB");
flash_combo->insertItem (2, "128 KB");
flash_combo->insertItem (3, "256 KB");
flash_combo->insertItem (4, "512 KB");
flash_combo->insertItem (5, "1024 KB");
flash_combo->insertItem (6, "2048 KB");
flash_combo->insertItem (7, "4096 KB");
flash_combo->insertItem (8, "8192 KB");
flash_combo->setCurrentIndex (4);
ram_label = new QLabel ("RAM:", this);
labels->addWidget (ram_label);
ram_combo = new QComboBox (this);
combo_boxes->addWidget (ram_combo);
ram_combo->insertItem (0, "2 KB");
ram_combo->insertItem (1, "8 KB");
ram_combo->insertItem (2, "32 KB");
ram_combo->insertItem (3, "128 KB");
ram_combo->setCurrentIndex (1);
lang_label = new QLabel (tr ("LANGUAGE:"), this);
labels->addWidget (lang_label);
lang_combo = new QComboBox (this);
combo_boxes->addWidget (lang_combo);
get_langs();
auto_check = new QCheckBox (tr ("Check file size"), this);
auto_check->setCheckState (Qt::Checked);
down->addWidget (auto_check);
north->addLayout (labels);
north->addLayout (combo_boxes);
all->addLayout (north);
all->addLayout (down);
setLayout (all);
auto_size = TRUE;
mbc = MBCAUTO;
ram_size = 8;
flash_size = 512;
com_name = com_combo->currentText ();
Gui::port_type = SERIAL;
connect (com_combo, SIGNAL (activated (int)), this, SLOT (setCom (int)));
connect (mbc_combo, SIGNAL (activated (int)), this, SLOT (setMbc (int)));
connect (flash_combo, SIGNAL (activated (int)), this,
SLOT (setFlash (int)));
connect (ram_combo, SIGNAL (activated (int)), this, SLOT (setRam (int)));
connect (lang_combo, SIGNAL (activated (const QString &)), this,
SLOT (setLang (const QString &)));
connect (auto_check, SIGNAL (stateChanged (int)), this,
SLOT (setAuto (int)));
}
void
Settings::setCom (int index)
{
com_name = getCom (index);
com_combo->setCurrentIndex (index);
if (index < PORTS_COUNT)
Gui::port_type = SERIAL;
else
Gui::port_type = USB;
}
void
Settings::setFlash (int index)
{
/* size = 32 * 2 ^ index */
flash_size = 32 * (int) pow (2.0, (double) index);
}
void
Settings::setRam (int index)
{
switch (index)
{
case 0:
ram_size = 2;
break;
case 1:
ram_size = 8;
break;
case 2:
ram_size = 32;
break;
case 3:
ram_size = 128;
break;
}
}
void
Settings::setMbc (int mbc_nr)
{
mbc = (mbc_t) mbc_nr;
switch (mbc)
{
case MBCAUTO:
ram_types (4);
flash_types (8);
break;
case MBC1:
ram_types (3);
flash_types (6);
break;
case MBC2:
ram_types (0);
flash_types (3);
break;
case MBC3:
ram_types (3);
flash_types (6);
break;
case ROMONLY:
ram_types (0);
flash_types (0);
break;
case MBC5:
ram_types (4);
flash_types (8);
break;
case RUMBLE:
ram_types (3);
flash_types (8);
break;
}
setFlash (flash_combo->currentIndex ());
setRam (ram_combo->currentIndex ());
emit refresh_ram_buttons ();
}
//fill ram_combo depending on cart type
void
Settings::ram_types (int type)
{
int ile = ram_combo->count ();
for (int i = ile - 1; i >= 0; i--)
ram_combo->removeItem (i);
switch (type)
{
case 0:
break;
case 3:
ram_combo->insertItem (0, "2 KB");
ram_combo->insertItem (1, "8 KB");
ram_combo->insertItem (2, "32 KB");
break;
case 4:
ram_combo->insertItem (0, "2 KB");
ram_combo->insertItem (1, "8 KB");
ram_combo->insertItem (2, "32 KB");
ram_combo->insertItem (3, "128 KB");
break;
}
}
void
Settings::flash_types (int type)
{
int ile = flash_combo->count ();
for (int i = ile - 1; i >= 0; i--)
flash_combo->removeItem (i);
for (int i = 0; i <= type; i++)
{
int pojemnosc = 32 * (int) pow (2.0, (double) i);
flash_combo->insertItem (i, QString::number (pojemnosc) + " KB");
}
}
void
Settings::get_langs() {
QSettings settings;
int selectedIndex = 0;
QString selectedLang = settings.value("selected_lang").toString();
settings.beginGroup("lang");
QStringList keys = settings.childKeys();
for (int i = 0; i < keys.size(); ++i) {
lang_combo->insertItem(i,settings.value(keys.at(i)).toString());
if(selectedLang == keys.at(i))
selectedIndex = i;
}
settings.endGroup();
lang_combo->setCurrentIndex(selectedIndex);
}
void
Settings::setLang (const QString & lang)
{
QSettings settings;
settings.beginGroup("lang");
QString langFileName = settings.value("selected_lang").toString();
QStringList keys = settings.childKeys();
for (int i = 0; i < keys.size(); ++i) {
if(lang == settings.value(keys.at(i)).toString())
langFileName = keys.at(i);
}
settings.endGroup();
settings.setValue ("selected_lang", langFileName);
QMessageBox::information (this, tr ("Change language"),
tr
("After program restart language will be changed to: ")
+ lang, QMessageBox::Ok);
}
void
Settings::setAuto (int state)
{
if (state == Qt::Checked)
auto_size = TRUE;
else
auto_size = FALSE;
}

107
Settings.h Normal file
View File

@ -0,0 +1,107 @@
/*****************************************************************************
** Settings.h - configuration widget
** Author: Kraku
*****************************************************************************/
#ifndef _SETTINGS_H_
#define _SETTINGS_H_
#include <QGroupBox>
#include <QComboBox>
#include <QLabel>
#include <QLayout>
#include <QString>
#include <QCheckBox>
#include <QThread>
#include "const.h"
class Settings:public QGroupBox
{
Q_OBJECT mbc_t mbc;
QString com_name;
int flash_size;
int ram_size;
bool auto_size;
QComboBox *com_combo;
QComboBox *mbc_combo;
QComboBox *flash_combo;
QComboBox *ram_combo;
QComboBox *lang_combo;
QLabel *com_label;
QLabel *mbc_label;
QLabel *flash_label;
QLabel *ram_label;
QLabel *lang_label;
QCheckBox *auto_check;
QVBoxLayout *labels, *combo_boxes;
QHBoxLayout *north, *down;
QVBoxLayout *all;
public:
static bool commanual;
static alg_t algorythm;
static dap_t dap;
static bool showbbl;
static speed_type speed;
static QThread::Priority priority;
Settings (QWidget * parent = 0);
int getFlash ()
{
return flash_size;
}
int getRam ()
{
return ram_size;
}
QString getCom (void)
{
return com_name;
}
QString getCom (int index)
{
return com_combo->itemText (index);
}
mbc_t getMbc ()
{
if (mbc == MBC5 || mbc == RUMBLE)
return MBC5;
else
return mbc;
}
bool isAuto ()
{
return auto_size;
}
bool isRamDisabled ()
{
return (ram_combo->currentText () == "");
}
void ram_types (int type);
void flash_types (int type);
void get_langs();
public slots:
void setCom (int index);
void setMbc (int mbc_nr);
void setFlash (int index);
void setRam (int index);
void setLang (const QString & lang);
void setAuto (int state);
signals:
void refresh_ram_buttons ();
};
#endif

161
USBPort.cpp Normal file
View File

@ -0,0 +1,161 @@
/*****************************************************************************
** USBPort.cpp
** Author: Kraku
*****************************************************************************/
#include "const.h"
#include "USBPort.h"
#include "Settings.h"
#include <ftdi.h>
#include <iostream>
extern "C"
{
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
}
USBPort::USBPort ():
AbstractPort ()
{
ftdi_init (&ftdic);
}
bool
USBPort::open_port (QString /*port_name*/)
{
if (ftdi_usb_open (&ftdic, 0x0403, 0x6001) < 0)
return FALSE;
/* choose speed */
if (Settings::speed == STANDARD)
{
if (ftdi_set_baudrate (&ftdic, 185000) < 0)
return FALSE;
}
else if (Settings::speed == LOW)
{
if (ftdi_set_baudrate (&ftdic, 125000) < 0)
return FALSE;
}
else if (Settings::speed == HIGH)
{
if (ftdi_set_baudrate (&ftdic, 375000) < 0)
return FALSE;
}
if (ftdi_set_latency_timer (&ftdic, 2) < 0)
return FALSE;
if (ftdi_set_line_property (&ftdic, BITS_8, STOP_BIT_1, NONE) < 0)
return FALSE;
//if(FT_SetTimeouts(ftHandle,5000,0) != FT_OK)
// return FALSE;
//if(ftdi_enable_bitbang(&ftdic,0xFF) < 0)
// return FALSE;
return TRUE; /* all ok */
}
bool
USBPort::close_port ()
{
ftdi_usb_close (&ftdic);
return TRUE;
}
int
USBPort::send_packet (unsigned char packet[PACKETSIZE])
{
int bytesSent;
bytesSent = ftdi_write_data (&ftdic, packet, PACKETSIZE);
return bytesSent;
}
bool
USBPort::send_char (unsigned char character)
{
int bytesSent;
bytesSent = ftdi_write_data (&ftdic, &character, 1);
return bytesSent == 1;
}
int
USBPort::receive_char (void)
{
time_t tp = time (NULL);
unsigned char character;
int bytesReceived = 0;
do
{
bytesReceived = ftdi_read_data (&ftdic, &character, 1);
if (bytesReceived != 0)
break;
}
while (time (NULL) - tp < SLEEPTIME);
if (bytesReceived == 0)
return TIMEOUT;
if (character == ACK || character == END)
return character;
else
return NAK;
}
int
USBPort::receive_packet (unsigned char *packet)
{
time_t tp = time (NULL);
int bytesReceived = 0, bytesLeft;
do
{
bytesReceived = ftdi_read_data (&ftdic, packet, 1);
}
while (time (NULL) - tp < SLEEPTIME && bytesReceived == 0);
if (bytesReceived == 0)
return TIMEOUT;
else
{
if (packet[0] != DATA)
{
if (packet[0] == ACK)
return ACK;
else if (packet[0] == END)
return END;
else
return NAK;
}
else
{
unsigned int remaining = PACKETSIZE - 1;
tp = time (NULL);
bytesReceived = 0;
do
{
bytesLeft = remaining;
bytesReceived =
ftdi_read_data (&ftdic, &packet[PACKETSIZE - remaining],
bytesLeft);
remaining -= bytesReceived;
tp = time (NULL);
}
while (time (NULL) - tp < SLEEPTIME && remaining != 0);
if (remaining > 0)
return TIMEOUT;
else
return DATA;
}
}
}

35
USBPort.h Normal file
View File

@ -0,0 +1,35 @@
/*****************************************************************************
** USBPort.h - USB driver for Linux based on libftdi
** Author: Kraku
*****************************************************************************/
#ifndef _USBPORT_H_
#define _USBPORT_H_
#include "AbstractPort.h"
#include <ftdi.h>
#include <time.h>
class USBPort:public AbstractPort
{
Q_OBJECT
struct ftdi_context ftdic;
FILE *file;
bool opened;
public:
USBPort ();
bool open_port (QString port_name);
bool close_port ();
int receive_char ();
bool send_char (unsigned char character);
int receive_packet (unsigned char *packet);
int send_packet (unsigned char *packet);
bool isOpen ()
{
return opened;
}
signals:
void error (int err);
};
#endif

158
USBPortWin.cpp Normal file
View File

@ -0,0 +1,158 @@
/*
#include "const.h"
#include "USBPortWin.h"
#include "Settings.h"
extern "C"{
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
}
USBPortWin::USBPortWin()
:AbstractPort()
{
}
bool USBPortWin::open_port (QString port_name)
{
if(FT_Open(0,&ftHandle) != FT_OK)
return FALSE;
if(Settings::speed == STANDARD){
if(FT_SetBaudRate(ftHandle,185000) != FT_OK)
return FALSE;
}
else if(Settings::speed == LOW){
if(FT_SetBaudRate(ftHandle,125000) != FT_OK)
return FALSE;
}
else if(Settings::speed == HIGH){
if(FT_SetBaudRate(ftHandle,375000) != FT_OK)
return FALSE;
}
if(FT_SetLatencyTimer(ftHandle, 2) != FT_OK)
return FALSE;
if(FT_SetDataCharacteristics(ftHandle,FT_BITS_8,FT_STOP_BITS_1,FT_PARITY_NONE) != FT_OK)
return FALSE;
if(FT_SetDataCharacteristics(ftHandle,FT_BITS_8,FT_STOP_BITS_1,FT_PARITY_NONE) != FT_OK)
return FALSE;
if(FT_SetTimeouts(ftHandle,5000,0) != FT_OK)
return FALSE;
return TRUE;
}
bool USBPortWin::close_port ()
{
FT_Close(ftHandle);
return TRUE;
}
int USBPortWin::send_packet (unsigned char packet[PACKETSIZE])
{
DWORD sendCount;
FT_Write(ftHandle, packet, PACKETSIZE, &sendCount);
return sendCount;
}
bool USBPortWin::send_char (unsigned char character)
{
DWORD sendCount;
FT_Write(ftHandle, &character, 1, &sendCount);
return sendCount;
}
int USBPortWin::receive_char (void)
{
time_t tp = time(NULL);
unsigned char character;
DWORD cbInQue = 0;
DWORD recivedCount=0;
FT_GetQueueStatus(ftHandle,&cbInQue);
do
{
if (cbInQue > 0)
FT_Read(ftHandle, &character, 1, &recivedCount);
if(recivedCount != 0)
break;
FT_GetQueueStatus(ftHandle,&cbInQue);
}while(time(NULL) - tp < SLEEPTIME);
if (recivedCount == 0)
return TIMEOUT;
if(character == ACK || character == END)
return character;
else
return NAK;
}
int USBPortWin::receive_packet (unsigned char *packet)
{
time_t tp = time(NULL);
DWORD recivedCount=0, bytesToReceive;
DWORD cbInQue = 0;
FT_GetQueueStatus(ftHandle,&cbInQue);
do
{
if (cbInQue > 0)
FT_Read(ftHandle, packet, 1, &recivedCount);
FT_GetQueueStatus(ftHandle,&cbInQue);
} while(time(NULL) - tp < SLEEPTIME && recivedCount == 0);
if (recivedCount == 0)
return TIMEOUT;
else
{
if(packet[0] != DATA)
{
if(packet[0] == ACK)
return ACK;
else if(packet[0] == END)
return END;
else
return NAK;
}
else
{
unsigned int bytesLeft = PACKETSIZE-1;
tp = time(NULL);
recivedCount = 0;
FT_GetQueueStatus(ftHandle,&cbInQue);
do
{
if (cbInQue > 0)
{
if (cbInQue > bytesLeft)
bytesToReceive = bytesLeft;
else
bytesToReceive = cbInQue;
FT_Read(ftHandle, &packet[PACKETSIZE-bytesLeft], bytesToReceive, &recivedCount);
bytesLeft -= recivedCount;
tp = time(NULL);
}
FT_GetQueueStatus(ftHandle,&cbInQue);
}while(time(NULL) - tp < SLEEPTIME && bytesLeft != 0);
if(bytesLeft > 0)
return TIMEOUT;
else
return DATA;
}
}
}
*/

34
USBPortWin.h Normal file
View File

@ -0,0 +1,34 @@
/*
#ifndef _USBPORTWIN_H_
#define _USBPORTWIN_H_
#include <windows.h>
#include "AbstractPort.h"
#include <ftd2xx.h>
#include <time.h>
class USBPortWin : public AbstractPort
{
Q_OBJECT
FT_HANDLE ftHandle;
FT_STATUS ftStatus;
bool opened;
public:
USBPortWin();
bool open_port (QString port_name);
bool close_port ();
int receive_char ();
bool send_char (unsigned char character);
int receive_packet (unsigned char *packet);
int send_packet (unsigned char *packet);
bool isOpen()
{
return opened;
}
signals:
void error(int err);
};
#endif
*/

149
WriteFlashThread.cpp Normal file
View File

@ -0,0 +1,149 @@
/*****************************************************************************
** WriteFlashThread.cpp
** Author: Kraku
*****************************************************************************/
#include "WriteFlashThread.h"
#include "Settings.h"
#include "Logic.h"
#include "const.h"
void
WriteFlashThread::run ()
{
end = FALSE;
bool zamykanie = FALSE;
int character, page_number, packet_number, retries = 0;
unsigned char packet[72], data[16384]; /* 16 kB is one page */
config_t cfg;
cfg.operation = WROM;
cfg.mbc = mbc;
cfg.algorythm = algorythm;
cfg.dap = Settings::dap;
cfg.page_count = page_count;
if (file == NULL)
{
port->close_port ();
emit error (FILEERROR_O);
return;
}
do
{ /* send start and wait for ACK */
if (Logic::send_start_packet (port, cfg) == FALSE)
{
port->close_port ();
fclose (file);
emit error (SEND_ERROR);
return;
}
character = port->receive_char ();
if (character == END || character == TIMEOUT)
{
port->close_port ();
fclose (file);
emit error (character);
return;
}
}
while (character != ACK && ++retries < 10); /* repeat 10 times */
if (retries == 10)
{ /* wait time passed */
port->close_port ();
fclose (file);
emit error (TIMEOUT);
return;
}
retries = 0;
/* send rest of data - page after page*/
for (page_number = 0; page_number < page_count; page_number++)
{
packet_number = 0;
/* read another page of data */
memset (data, 0xff, sizeof data);
fread (data, sizeof (char), sizeof (data), file);
/* first packet on page */
Logic::fill_data_packet (packet, &data[packet_number * 64], NORMAL_DATA,
packet_number, page_number);
do
{ /* send packet and wait for ACK */
//end of thread!!!!
if (end)
{
Logic::fill_data_packet (packet, &data[packet_number * 64],
LAST_DATA, packet_number, page_number);
zamykanie = TRUE;
}
if (port->send_packet (packet) < PACKETSIZE)
{
port->close_port ();
fclose (file);
emit error (SEND_ERROR);
return;
}
character = port->receive_char ();
if (character == END || character == TIMEOUT)
{
port->close_port ();
fclose (file);
emit error (character);
return;
}
if (character == ACK)
{ /* ACK of packet recive */
if (zamykanie)
{
port->close_port ();
fclose (file);
emit error (END);
return;
}
if (++packet_number == 256) /* last packet on page */
break;
retries = 0;
/* is it last packet of transmision ? */
if (packet_number == 255 && page_number == page_count - 1)
Logic::fill_data_packet (packet, &data[packet_number * 64],
LAST_DATA, packet_number,
page_number);
else /* nope, it it ordinary packet */
Logic::fill_data_packet (packet, &data[packet_number * 64],
NORMAL_DATA, packet_number,
page_number);
/* update progress */
emit set_progress (page_number * 256 + packet_number,
page_count * 256 - 1);
}
/* NAK - bad packet */
else if (++retries == 10)
{
port->close_port ();
fclose (file);
emit error (END);
return;
}
}
while (1); /* until all page is send and all ACK recived */
}
port->close_port ();
fclose (file);
emit error (TRUE);
}
void
WriteFlashThread::canceled (void)
{
end = TRUE;
}

32
WriteFlashThread.h Normal file
View File

@ -0,0 +1,32 @@
/*****************************************************************************
** WriteFlashThread.h
** Author: Kraku
*****************************************************************************/
#ifndef _WRITEFLASHTHREAD_H_
#define _WRITEFLASHTHREAD_H_
#include <QThread>
#include "AbstractPort.h"
#include "Logic.h"
class WriteFlashThread:public QThread
{
Q_OBJECT public:
WriteFlashThread ()
{
}
virtual void run ();
FILE *file;
char mbc;
char algorythm;
char dap;
int page_count;
bool end;
AbstractPort *port;
public slots:void canceled (void);
signals:
void set_progress (int ile, int max);
void error (int err);
};
#endif

154
WriteRamThread.cpp Normal file
View File

@ -0,0 +1,154 @@
/*****************************************************************************
** WriteRamThread.cpp
** Author: Kraku
*****************************************************************************/
#include "WriteRamThread.h"
#include "Settings.h"
#include "Logic.h"
#include "const.h"
void
WriteRamThread::run ()
{
end = FALSE;
bool closing = FALSE;
/* function similar to write_flash */
int character, page_number, packet_number, retries = 0;
unsigned char packet[72], data[8192];
config_t cfg;
cfg.operation = WRAM;
cfg.mbc = mbc;
cfg.algorythm = 0x00;
cfg.dap = Settings::dap;
if (_2k)
page_count = 1;
cfg.page_count = page_count;
if (file == NULL)
{
port->close_port ();
emit error (FILEERROR_O);
return;
}
do
{
if (Logic::send_start_packet (port, cfg) == FALSE)
{
port->close_port ();
fclose (file);
emit error (SEND_ERROR);
return;
}
character = port->receive_char ();
if (character == END || character == TIMEOUT)
{
port->close_port ();
fclose (file);
emit error (character);
return;
}
}
while (character != ACK && ++retries < 10);
if (retries == 10)
{
port->close_port ();
emit error (TIMEOUT);
fclose (file);
return;
}
retries = 0;
for (page_number = 0; page_number < page_count; page_number++)
{
packet_number = 0;
memset (data, 0x00, sizeof data);
if (_2k) /* if set, read only 2kB - some carts */
fread (data, sizeof (char), 2048, file);
else
fread (data, sizeof (char), sizeof (data), file);
/* send first packet */
Logic::fill_data_packet (packet, &data[packet_number * 64], NORMAL_DATA,
packet_number, page_number);
do
{ /* send packet and wait for ack */
if (end)
{
Logic::fill_data_packet (packet, &data[packet_number * 64],
LAST_DATA, packet_number, page_number);
closing = TRUE;
}
if (port->send_packet (packet) < PACKETSIZE)
{
port->close_port ();
fclose (file);
emit error (SEND_ERROR);
return;
}
character = port->receive_char ();
if (character == END || character == TIMEOUT)
{
port->close_port ();
fclose (file);
emit error (character);
return;
}
if (character == ACK)
{
if (closing)
{
port->close_port ();
fclose (file);
emit error (END);
return;
}
if (_2k == 1 && packet_number == 31)
{
port->close_port ();
fclose (file);
emit error (TRUE);
return; /* end of 2kB page */
}
if (++packet_number == 128)
break;
retries = 0;
if ((packet_number == 127 && page_number == page_count - 1)
|| (_2k && packet_number == 31))
Logic::fill_data_packet (packet, &data[packet_number * 64],
LAST_DATA, packet_number,
page_number);
else
Logic::fill_data_packet (packet, &data[packet_number * 64],
NORMAL_DATA, packet_number,
page_number);
emit set_progress (page_number * 128 + packet_number + 1,
_2k ? 32 : page_count * 128);
}
else if (++retries == 10)
{
port->close_port ();
fclose (file);
emit error (END);
return;
}
}
while (1);
}
port->close_port ();
fclose (file);
emit error (TRUE);
return;
}
void
WriteRamThread::canceled (void)
{
end = TRUE;
}

32
WriteRamThread.h Normal file
View File

@ -0,0 +1,32 @@
/*****************************************************************************
** WriteRamThread.h
** Author: Kraku
*****************************************************************************/
#ifndef _WRITERAMTHREAD_H_
#define _WRITERAMTHREAD_H_
#include <QThread>
#include "AbstractPort.h"
#include "Logic.h"
class WriteRamThread:public QThread
{
Q_OBJECT public:
WriteRamThread ()
{
}
virtual void run ();
FILE *file;
char mbc;
char algorythm;
char dap;
int page_count;
bool end;
AbstractPort *port;
char _2k;
public slots:void canceled (void);
signals:
void set_progress (int ile, int max);
void error (int err);
};
#endif

16355
about.xpm Normal file

File diff suppressed because it is too large Load Diff

79
const.h Normal file
View File

@ -0,0 +1,79 @@
/*****************************************************************************
** const.h - definitions of constants used in program
** Author: Kraku
*****************************************************************************/
#ifndef _CONST_H_
#define _CONST_H_
/* control characters */
enum cchars
{ ACK = 0xAA, NAK = 0xF0, END = 0x0F, DATA = 0x55 };
#define SLEEPTIME 3 /* time to wait for connection in sec. */
#define DELTIME 60 /* time to wait for delete in sec. */
#define PACKETSIZE 72
#define FRAMESIZE 64
#define AUTOSIZE -1
#define PORTS_COUNT 4
#define VER "1.1"
#define USB 0
#define SERIAL 1
#define TRUE 1
#define FALSE 0
/* strings for version information */
#ifdef Q_WS_X11
#define SYSTEM "LINUX"
#define DEVELOPED "GCC 11.4.1 + QT 5.15.3"
#endif
#ifdef Q_WS_WIN
#define SYSTEM "WINDOWS"
#define DEVELOPED "Dev-C++ 4.9.9.2 + QT 4.3.2"
#endif
/* return values and errors */
enum error_tt
{ TIMEOUT = -1, FILEERROR_O = -2, FILEERROR_W = -3, FILEERROR_R =
-4, SEND_ERROR = -5,
BAD_PACKET = -6, BAD_PARAMS = -7, PORT_ERROR = -8, WRONG_SIZE = -9
};
/* packet types */
#define CONFIG 0x00
#define NORMAL_DATA 0x01
#define LAST_DATA 0x02
#define ERASE 0x03
#define STATUS 0x04
#define RESERVED 0x00
#define NREAD_ID 0x00
#define READ_ID 0x01
/* operations */
#define RROM 0x00
#define RRAM 0x01
#define WROM 0x02
#define WRAM 0x03
#define EFLA 0x00
#define ERAM 0x01
enum alg_t
{ ALG16 = 0x00, ALG12 = 0x01 };
enum dap_t
{ LONGER = 0x00, DEFAULT = 0x01, DATAPOLL = 0x02, TOGGLE = 0x03 };
enum speed_type
{ LOW = 0x00, STANDARD = 0x01, HIGH = 0x02 };
/* MBC types */
enum mbc_t
{ MBCAUTO = 0x00, MBC1 = 0x01, MBC2 = 0x02, MBC3 = 0x03,
ROMONLY = 0x04, MBC5 = 0x05, RUMBLE = 0x06
};
#endif

10600
flasher.xpm Normal file

File diff suppressed because it is too large Load Diff

123
gbcflsh.cpp Normal file
View File

@ -0,0 +1,123 @@
/*****************************************************************************
** gbcflsh.cpp - Main source file, starts application, parse args
** and load translation files
** Author: Kraku
*****************************************************************************/
#include <QApplication>
#include <QTranslator>
#include <QSettings>
#include <QTimer>
#include <QTextCodec>
#include <QMessageBox>
#include "Gui.h"
#include "const.h"
#include "Settings.h"
#include <stdio.h>
#include <iostream>
void
parse_params (int /*argc*/, char *argv[])
{
while (*++argv)
{
/* disable auto com search in windows */
if (strcmp (*argv, "-commanual") == 0)
Settings::commanual = TRUE;
/* additional communication params */
if (strcmp (*argv, "-12bit") == 0)
Settings::algorythm = ALG12;
if (strcmp (*argv, "-longer") == 0)
Settings::dap = LONGER;
if (strcmp (*argv, "-default") == 0)
Settings::dap = DEFAULT;
if (strcmp (*argv, "-datapoll") == 0)
Settings::dap = DATAPOLL;
if (strcmp (*argv, "-showbbl") == 0)
Settings::showbbl = TRUE;
/*
* USB speed LOW 125000bps HI 375000
*/
if (strcmp (*argv, "-lowspeed") == 0)
Settings::speed = LOW;
if (strcmp (*argv, "-highspeed") == 0)
Settings::speed = HIGH;
/*
* communication threads prioryty are used when communication
* or gui is freezing
*/
if ((*argv)[0] == '-' && isdigit ((*argv)[1]) && (*argv)[1] >= '0'
&& (*argv)[1] <= '7')
{
switch ((*argv)[1] - '0')
{
case 0:
Settings::priority = QThread::IdlePriority;
break;
case 1:
Settings::priority = QThread::LowestPriority;
break;
case 2:
Settings::priority = QThread::LowPriority;
break;
case 3:
Settings::priority = QThread::NormalPriority;
break;
case 4:
Settings::priority = QThread::HighPriority;
break;
case 5:
Settings::priority = QThread::HighestPriority;
break;
case 6:
Settings::priority = QThread::TimeCriticalPriority;
break;
case 7:
Settings::priority = QThread::InheritPriority;
break;
}
}
}
}
int
main (int argc, char *argv[])
{
parse_params (argc, argv);
QApplication app (argc, argv);
/*
* Organization and aplication names are used for naming settings
* file/directory in Linux def. ~/.config/GBCFProject/GameBoyCartFlasher.conf
* registry keys in Windows
* def. HKEY_CURRENT_USER\Software\GBCFProject/GameBoyCartFlasher.conf
*/
QCoreApplication::setOrganizationName ("GBCFProject");
QCoreApplication::setApplicationName ("GameBoyCartFlasher");
QSettings settings;
/*
* Default language for application is English. It can be canged with
* files containing compiled QT translations. All files have same naming
* convention gbcflsh_langname.qm i.e. gbcflsh_polish.qm. Program knows
* about them, thanks to [lang] group in settings file/registry. Every lang
* is represented as single setting i.e. polish=Polski. This record contains
* pair of key=value, where value is name of lang shown in ComboBox and key
* is langname in filename. Lang selected with ComboBox is saved in
* selected_lang record as langname.
*/
//QTextCodec::setCodecForTr (QTextCodec::codecForName ("UTF-8"));
QString langName = settings.value("selected_lang").toString ();
QString langPath = settings.value("lang_path").toString();
if(langPath == "")
langPath = "./";
QTranslator translator;
translator.load ( "gbcflsh_" + langName,langPath);
app.installTranslator (&translator);
Gui window;
window.show ();
#ifdef Q_WS_WIN
window.startup_info();
#endif
return app.exec ();
}

54
gbcflsh_1.1.pro Normal file
View File

@ -0,0 +1,54 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
About.cpp \
EraseThread.cpp \
Gui.cpp \
Logic.cpp \
ReadFlashThread.cpp \
ReadRamThread.cpp \
SerialPort.cpp \
SerialPortWin.cpp \
Settings.cpp \
USBPort.cpp \
USBPortWin.cpp \
WriteFlashThread.cpp \
WriteRamThread.cpp \
gbcflsh.cpp
HEADERS += \
About.h \
AbstractPort.h \
Console.h \
EraseThread.h \
Gui.h \
Logic.h \
ReadFlashThread.h \
ReadRamThread.h \
SerialPort.h \
SerialPortWin.h \
Settings.h \
USBPort.h \
USBPortWin.h \
WriteFlashThread.h \
WriteRamThread.h \
const.h
FORMS +=
LIBS += -lftdi
DEFINES += Q_WS_X11=1
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

263
gbcflsh_1.1.pro.user Normal file
View File

@ -0,0 +1,263 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 6.0.2, 2023-12-28T13:34:34. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{fe6a0c16-8c7a-4d97-8241-f89b2320f9ae}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
<value type="bool" key="AutoTest.Framework.Boost">true</value>
<value type="bool" key="AutoTest.Framework.CTest">false</value>
<value type="bool" key="AutoTest.Framework.Catch">true</value>
<value type="bool" key="AutoTest.Framework.GTest">true</value>
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
</valuemap>
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
<value type="int" key="AutoTest.RunAfterBuild">0</value>
<value type="bool" key="AutoTest.UseGlobal">true</value>
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey"/>
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
<value type="QString" key="ClangCodeModel.WarningConfigId">Builtin.BuildSystem</value>
<valuemap type="QVariantMap" key="ClangTools">
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
<value type="int" key="ClangTools.ParallelJobs">6</value>
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
</valuemap>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="DeviceType">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{8c52ab2b-8dea-4a85-a5bb-94aecabf912c}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="int" key="EnableQmlDebugging">0</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/m0rph3us1987/build-QTDemo-Desktop-Debug</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/m0rph3us1987/build-QTDemo-Desktop-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/m0rph3us1987/build-QTDemo-Desktop-Release</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/m0rph3us1987/build-QTDemo-Desktop-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="int" key="EnableQmlDebugging">0</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/m0rph3us1987/build-QTDemo-Desktop-Profile</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory.shadowDir">/home/m0rph3us1987/build-QTDemo-Desktop-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<valuelist type="QVariantList" key="QtProjectManager.QMakeBuildStep.SelectedAbis"/>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="int" key="SeparateDebugInfo">0</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/home/m0rph3us1987/gbcflsh_1.1/gbcflsh_1.1.pro</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/m0rph3us1987/gbcflsh_1.1/gbcflsh_1.1.pro</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/m0rph3us1987/build-QTDemo-Desktop-Debug</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">22</value>
</data>
<data>
<variable>Version</variable>
<value type="int">22</value>
</data>
</qtcreator>

BIN
icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

437
icon.xpm Normal file
View File

@ -0,0 +1,437 @@
/* XPM - program icon */
static const char * icon[] = {
"27 35 399 2",
" c #6F6F6F",
". c #000000",
"+ c #5C5C5C",
"@ c #F9FAFC",
"# c #DAE4EE",
"$ c #DAE4ED",
"% c #D9E3ED",
"& c #D9E3EC",
"* c #D8E2EC",
"= c #D7E1EB",
"- c #D6E1EA",
"; c #D6E0EA",
"> c #D5E0E9",
", c #D4DFE9",
"' c #D4DEE8",
") c #D3DEE7",
"! c #D3DDE7",
"~ c #D2DCE6",
"{ c #D1DCE6",
"] c #D1DBE5",
"^ c #D0DAE4",
"/ c #A0AFBD",
"( c #DEE7EF",
"_ c #9DB8D2",
": c #C2D2DF",
"< c #8299AE",
"[ c #88A0B6",
"} c #B5C8D9",
"| c #859DB4",
"1 c #98B3CD",
"2 c #96B2CC",
"3 c #95B0CA",
"4 c #93AEC8",
"5 c #91ADC7",
"6 c #8FABC5",
"7 c #8EA9C3",
"8 c #8CA8C2",
"9 c #8AA6C0",
"0 c #89A4BE",
"a c #87A3BD",
"b c #85A1BB",
"c c #849FB9",
"d c #829EB8",
"e c #809CB6",
"f c #7E9BB5",
"g c #6F889F",
"h c #9BB6D0",
"i c #99B4CE",
"j c #97B3CD",
"k c #96B1CB",
"l c #94AFC9",
"m c #92AEC8",
"n c #91ACC6",
"o c #8FAAC4",
"p c #8DA9C3",
"q c #8BA7C1",
"r c #8AA5BF",
"s c #88A4BE",
"t c #86A2BC",
"u c #839FB9",
"v c #819DB7",
"w c #7E9AB4",
"x c #7C98B2",
"y c #6C869D",
"z c #88A1B8",
"A c #6A839A",
"B c #96ACBF",
"C c #698199",
"D c #DDE6EF",
"E c #5F7F50",
"F c #6C8860",
"G c #748E69",
"H c #78916C",
"I c #7B946F",
"J c #7E9772",
"K c #839C77",
"L c #879F7A",
"M c #8DA480",
"N c #8BA37E",
"O c #8AA17E",
"P c #859D78",
"Q c #809874",
"R c #93AABE",
"S c #678097",
"T c #DDE6EE",
"U c #98B4CE",
"V c #628154",
"W c #6D8962",
"X c #77916C",
"Y c #7A936E",
"Z c #7C9570",
"` c #7F9772",
" . c #829A75",
".. c #849C77",
"+. c #819A75",
"@. c #7E9773",
"#. c #92A8BC",
"$. c #647E95",
"%. c #DCE5EE",
"&. c #5C8054",
"*. c #6E8963",
"=. c #738E67",
"-. c #77906B",
";. c #79926D",
">. c #7C946F",
",. c #7E9671",
"'. c #7F9773",
"). c #7F9873",
"!. c #7D9671",
"~. c #7A946F",
"{. c #91A6BA",
"]. c #627C93",
"^. c #DBE4ED",
"/. c #637585",
"(. c #3C454F",
"_. c #5D8055",
":. c #6D8963",
"<. c #738D68",
"[. c #768F6A",
"}. c #79936E",
"|. c #8EA5B8",
"1. c #617991",
"2. c #DAE4EC",
"3. c #597D51",
"4. c #678459",
"5. c #708B65",
"6. c #758E69",
"7. c #76906A",
"8. c #78926D",
"9. c #758F69",
"0. c #8CA3B7",
"a. c #5E788F",
"b. c #DAE3EC",
"c. c #54784D",
"d. c #5D8155",
"e. c #69875C",
"f. c #718C66",
"g. c #758F6A",
"h. c #738D67",
"i. c #8BA1B6",
"j. c #5C768D",
"k. c #D9E2EB",
"l. c #8DA8C2",
"m. c #4E7248",
"n. c #577B50",
"o. c #608258",
"p. c #6A875D",
"q. c #748E68",
"r. c #708B64",
"s. c #899FB3",
"t. c #5A748B",
"u. c #D8E1EA",
"v. c #8BA6C0",
"w. c #44683F",
"x. c #4F7449",
"y. c #577C50",
"z. c #5E8156",
"A. c #68855B",
"B. c #6F8A64",
"C. c #718C65",
"D. c #728D67",
"E. c #728D66",
"F. c #728C66",
"G. c #68865B",
"H. c #879EB2",
"I. c #587189",
"J. c #D7E1E9",
"K. c #395E36",
"L. c #456940",
"M. c #5A7E52",
"N. c #5F8257",
"O. c #62845A",
"P. c #6A875C",
"Q. c #65865C",
"R. c #63845A",
"S. c #5F8157",
"T. c #859CB0",
"U. c #567087",
"V. c #D7E0E9",
"W. c #31572F",
"X. c #385C34",
"Y. c #41663C",
"Z. c #4A6D44",
"`. c #50754A",
" + c #54794E",
".+ c #5C7F54",
"++ c #5B7E53",
"@+ c #5A7D53",
"#+ c #577A50",
"$+ c #849AAF",
"%+ c #546E85",
"&+ c #D6DFE8",
"*+ c #84A0BA",
"=+ c #284F26",
"-+ c #2E542C",
";+ c #345931",
">+ c #3B5F38",
",+ c #42673D",
"'+ c #486C43",
")+ c #4D7247",
"!+ c #4F7349",
"~+ c #50744A",
"{+ c #51754B",
"]+ c #4E7148",
"^+ c #4C6F46",
"/+ c #8299AC",
"(+ c #516C83",
"_+ c #D5DEE7",
":+ c #444E56",
"<+ c #879BAE",
"[+ c #506A81",
"}+ c #D4DEE6",
"|+ c #7F9BB5",
"1+ c #242B31",
"2+ c #2D353C",
"3+ c #282E35",
"4+ c #2F373F",
"5+ c #2C333B",
"6+ c #0E1113",
"7+ c #465058",
"8+ c #9CACBC",
"9+ c #5A7791",
"0+ c #4E687F",
"a+ c #D4DDE6",
"b+ c #7D99B3",
"c+ c #94AABF",
"d+ c #97ADC1",
"e+ c #94AABE",
"f+ c #92A9BD",
"g+ c #8FA5B9",
"h+ c #8DA4B8",
"i+ c #8CA2B6",
"j+ c #8DA3B6",
"k+ c #8AA0B4",
"l+ c #849BAF",
"m+ c #8499AE",
"n+ c #879DAF",
"o+ c #9AADBC",
"p+ c #90A3B4",
"q+ c #597690",
"r+ c #57758F",
"s+ c #4C667D",
"t+ c #D3DCE5",
"u+ c #7A97B1",
"v+ c #7995AF",
"w+ c #7793AD",
"x+ c #7592AC",
"y+ c #7490AA",
"z+ c #728EA8",
"A+ c #708DA7",
"B+ c #6E8BA5",
"C+ c #6D8AA4",
"D+ c #728CA4",
"E+ c #68849D",
"F+ c #63809A",
"G+ c #617E98",
"H+ c #5F7C96",
"I+ c #5D7B95",
"J+ c #5C7993",
"K+ c #587690",
"L+ c #57748E",
"M+ c #55738D",
"N+ c #49647B",
"O+ c #D2DBE4",
"P+ c #7894AE",
"Q+ c #7693AD",
"R+ c #7591AB",
"S+ c #7390AA",
"T+ c #718EA8",
"U+ c #708CA6",
"V+ c #6C89A3",
"W+ c #6A87A1",
"X+ c #BEC9D4",
"Y+ c #97AABC",
"Z+ c #95A9BB",
"`+ c #96AABC",
" @ c #95A8B9",
".@ c #8FA3B4",
"+@ c #5D7A94",
"@@ c #5B7993",
"#@ c #597791",
"$@ c #58758F",
"%@ c #56748E",
"&@ c #54728C",
"*@ c #53708A",
"=@ c #486279",
"-@ c #D1DBE3",
";@ c #7692AC",
">@ c #7491AB",
",@ c #728FA9",
"'@ c #5B7287",
")@ c #485C6D",
"!@ c #4C6174",
"~@ c #5F788F",
"{@ c #68859F",
"]@ c #66839D",
"^@ c #65829C",
"/@ c #617F99",
"(@ c #607D97",
"_@ c #5E7B95",
":@ c #5C7A94",
"<@ c #5B7892",
"[@ c #54718B",
"}@ c #52708A",
"|@ c #506E88",
"1@ c #466077",
"2@ c #D1DAE3",
"3@ c #566C82",
"4@ c #B5B5B5",
"5@ c #8B8B8B",
"6@ c #93A8BA",
"7@ c #64819B",
"8@ c #62809A",
"9@ c #4C657C",
"0@ c #496278",
"a@ c #42596D",
"b@ c #41586C",
"c@ c #516F89",
"d@ c #4E6C86",
"e@ c #435E75",
"f@ c #D0D9E2",
"g@ c #4D6274",
"h@ c #4D5F70",
"i@ c #4F6577",
"j@ c #707070",
"k@ c #94A8BA",
"l@ c #627F99",
"m@ c #5E7C96",
"n@ c #465F74",
"o@ c #A5A6A9",
"p@ c #727878",
"q@ c #788999",
"r@ c #9EA0A3",
"s@ c #6C6F73",
"t@ c #778DA1",
"u@ c #4D6B85",
"v@ c #4C6A84",
"w@ c #425D74",
"x@ c #CFD9E1",
"y@ c #6F8CA6",
"z@ c #485B6C",
"A@ c #AFAFAF",
"B@ c #494949",
"C@ c #4A5E71",
"D@ c #27323C",
"E@ c #676767",
"F@ c #585858",
"G@ c #8EA2B5",
"H@ c #5A7892",
"I@ c #486176",
"J@ c #74787D",
"K@ c #10161B",
"L@ c #798997",
"M@ c #5A5E62",
"N@ c #0F151A",
"O@ c #71899D",
"P@ c #4B6983",
"Q@ c #CED8E0",
"R@ c #6D89A3",
"S@ c #4F6578",
"T@ c #949494",
"U@ c #1E262E",
"V@ c #51697E",
"W@ c #9BADBD",
"X@ c #55728C",
"Y@ c #758DA2",
"Z@ c #8599AC",
"`@ c #5E7990",
" # c #8397A9",
".# c #7B92A4",
"+# c #CED7E0",
"@# c #778B9C",
"## c #92A7B9",
"$# c #696969",
"%# c #2F2F2F",
"&# c #A1B2C1",
"*# c #9FB0C0",
"=# c #94A7B8",
"-# c #506D87",
";# c #4F6C86",
"># c #CDD7DF",
",# c #526F89",
"'# c #4F6D87",
")# c #CCD6DE",
"!# c #56738D",
"~# c #53718B",
"{# c #CBD5DD",
"]# c #516E88",
"^# c #CBD4DD",
"/# c #5F7D97",
"(# c #CAD4DC",
"_# c #C7CED3",
":# c #486074",
"<# c #485E72",
"[# c #465D72",
"}# c #445C71",
"|# c #445D72",
"1# c #455D73",
"2# c #565656",
" . . . . . . . . . . . . . . . . . . . . . . . . . + ",
". @ # # # # # # $ % & * = - ; > , ' ) ! ~ { ] ^ ^ / . ",
". ( _ : < : [ } | 1 2 3 4 5 6 7 8 9 0 a b c d e f g . ",
". ( _ _ _ _ h i j k l m n o p q r s t b u v e w x y . ",
". ( _ . . . . . . . . . . . . . . . . . . . . . z A . ",
". ( _ . . . . . . . . . . . . . . . . . . . . . B C . ",
". D h . . . . E F G H I J K L M N O P Q . . . . R S . ",
". T U . . . . V W G X Y Z ` .P P ..+.@.. . . . #.$.. ",
". %.k . . . . &.*.=.-.;.Y >.,.'.).J !.~.. . . . {.].. ",
". ^.l . /.(.. _.:.<.[.H H Y Y I I I }.H . . . . |.1.. ",
". 2.5 . . . . 3.4.5.6.7.H 8.;.;.;.;.H 9.. . . . 0.a.. ",
". b.6 . . . . c.d.e.f.6.7.-.X H X -.g.h.. . . . i.j.. ",
". k.l.. . . . m.n.o.p.f.q.9.[.7.[.9.<.r.. . . . s.t.. ",
". u.v.. . . . w.x.y.z.A.B.C.h.D.E.F.5.G.. . . . H.I.. ",
". J.s . . . . K.L.m.c.M.N.O.p.P.p.Q.R.S.. . . . T.U.. ",
". V.t . . . . W.X.Y.Z.`. +n..+.+_.++@+#+. . . . $+%+. ",
". &+*+. . . . =+-+;+>+,+'+)+!+~+{+{+]+^+. . . . /+(+. ",
". _+v . . . . . . . . . . . . . . . . . . . . :+<+[+. ",
". }+|+. . . . . 1+2+3+. . 4+5+6+. . . . . . 7+8+9+0+. ",
". a+b+c+d+B e+f+#.{.g+h+i+j+k+s.H.T.l+m+n+o+p+q+r+s+. ",
". t+u+v+w+x+y+z+A+B+C+D+E+E+E+E+F+G+H+I+J+9+K+L+M+N+. ",
". O+P+Q+R+S+T+U+B+V+W+X+Y+Z+`+ @.@H++@@@#@$@%@&@*@=@. ",
". -@;@>@,@'@)@!@~@W+{@]@^@F+/@(@_@:@<@q+r+M+[@}@|@1@. ",
". 2@y+z+A+3@4@5@6@{@]@7@8@G+H+I+J+9@0@L+a@b@c@|@d@e@. ",
". f@T+g@h@i@j@. k@^@7@l@(@m@+@<@n@o@p@q@r@s@t@u@v@w@. ",
". x@y@z@A@B@C@D@E@F@G@(@_@J+H@q+I@J@K@L@M@N@O@P@P@w@. ",
". Q@R@S@T@. U@V@F@. W@I+J+9+K+%@X@Y@Z@`@ #.#P@P@P@w@. ",
". +#W+@#k@##$#%#&#*#=#<@#@$@X@[@*@|@-#;#v@P@P@P@v@w@. ",
". >#{@]@^@F+F@. W@J+H@q+L+[@,#|@|@'#|@|@u@u@d@'#'#w@. ",
". )#]@7@l@G+G+G+G+G+G+#@%@&@M+!#[@*@~#[@c@|@'#;#u@w@. ",
". {#F+l@(@m@m@m@m@m@m@@@r+M+M+%@M+!#]#]#|@}@|@|@v@w@. ",
". ^#G+/#_@J+J+J+J+J+J+J+r+r+r+r+~#|@'#'#|@]#}@c@P@w@. ",
". (#H++@@@9+9+9+9+9+9+9+9+9+M+c@c@c@c@c@}@}@'#*@u@w@. ",
". _#:#<#[#}#}#}#}#}#}#}#}#}#}#}#}#}#}#}#|#|#1#}#}#}#}#",
"2#. . . . . . . . . . . . . . . . . . . . . . . . . . "};