Change back button combo, update readme, misc. cleanups

This commit is contained in:
spicyjpeg 2023-09-18 22:50:52 +02:00
parent 3e84285837
commit fa7beb023e
No known key found for this signature in database
GPG Key ID: 5CC87404C01DF393
13 changed files with 162 additions and 127 deletions

View File

@ -73,11 +73,13 @@ target_compile_definitions(
cart_tool PRIVATE
VERSION="${PROJECT_VERSION}"
$<IF:$<CONFIG:Debug>,
ENABLE_CART_MENU=1
ENABLE_DUMMY_DRIVER=1
ENABLE_I2C_LOGGING=1
ENABLE_PS1_CONTROLLER=1
,
#ENABLE_ARGV=1
ENABLE_CART_MENU=1
ENABLE_PS1_CONTROLLER=1
>
)

View File

@ -1,10 +1,22 @@
Konami System 573 security cartridge tool
# Credits
Lead developer: spicyjpeg
Cartridge database: smf
Testing: Naoki Saito
# Disclaimer
This tool is experimental and provided with no warranty whatsoever. It is not
guaranteed to work and improper usage can PERMANENTLY BRICK your System 573
security cartridges. Use this tool at your own risk.
# License
(C) 2022-2023 spicyjpeg
WARNING: This tool is experimental and provided with no warranty whatsoever. It
is not guaranteed to work and improper usage can PERMANENTLY BRICK your System
573 security cartridges. Use this tool at your own risk.
TODO: add a license
# Third-party licenses
@ -22,14 +34,14 @@ that the following condition is met:
this condition and the following disclaimer.
This software is provided by the copyright holder and contributors "AS IS"
and any warranties related to this software are DISCLAIMED.
and any warranties related to this software are DISCLAIMED.
The copyright owner or contributors be NOT LIABLE for any damages caused
by use of this software.
by use of this software.
## miniz (https://github.com/richgel999/miniz)
Copyright 2013-2014 RAD Game Tools and Valve Software
Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
Copyright 2013-2014 RAD Game Tools and Valve Software
Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
All Rights Reserved.
@ -100,15 +112,13 @@ this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
* The Software is provided "as is", without warranty of any kind, express or
subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
- The Software is provided "as is", without warranty of any kind, express or
implied, including but not limited to the warranties of merchantability,
fitness for a particular purpose and noninfringement. In no event shall the
authors or copyright holders be liable for any claim, damages or other
liability, whether in an action of contract, tort or otherwise, arising from,
out of or in connection with the Software or the use or other dealings in the
Software.
Software.

View File

@ -7,7 +7,6 @@
"App": {
"cartDetectWorker": {
"readDigitalIO": "Retrieving digital I/O board ID...",
"identifyCart": "Identifying security cartridge...",
"readCart": "Reading security cartridge...",
"identifyGame": "Attempting to identify game..."
},
@ -48,9 +47,10 @@
"dumpError": "An error occurred while writing dumps to the hard drive. Ensure the drive has at least 32 MB of free space (256 MB if both PCMCIA cards are inserted) and the filesystem is not damaged.\n\nPress the Test button to view debug logs."
},
"atapiEjectWorker": {
"eject": "Sending eject command...",
"success": "The drive's tray has been opened.\n\nYou may safely remove or replace the disc and close the tray. All data has been loaded into RAM and the tool will keep running until the 573 is turned off.",
"error": "Failed to open the drive's tray. Your drive might be incompatible with the ATAPI driver used by this tool.\n\nPress the Test button to view debug logs."
"eject": "Sending eject command...",
"success": "The drive's tray has been opened.\n\nYou may safely remove or replace the disc and close the tray. All data has been loaded into RAM and the tool will keep running until the 573 is turned off.",
"atapiError": "The drive currently configured as primary on the IDE bus is not an ATAPI CD-ROM drive and does not support ejecting.\n\nPress the Test button to view debug logs.",
"ejectError": "Failed to open the drive's tray. Your drive might be incompatible with the ATAPI driver used by this tool.\n\nPress the Test button to view debug logs."
},
"rebootWorker": {
"reboot": "Rebooting system..."
@ -71,7 +71,7 @@
"CartActionsScreen": {
"title": "{CART_ICON} Cartridge options",
"itemPrompt": "{RIGHT_ARROW} Press {START_BUTTON} to select, hold {LEFT_BUTTON} + {RIGHT_BUTTON} to go back",
"itemPrompt": "{RIGHT_ARROW} Press {START_BUTTON} to select, hold {LEFT_BUTTON}{RIGHT_BUTTON} + {START_BUTTON} to go back",
"qrDump": {
"name": "Dump cartridge as QR code",
@ -157,9 +157,9 @@
}
},
"prompt": {
"locked": "Press {START_BUTTON} to unlock the cartridge, hold {LEFT_BUTTON} + {RIGHT_BUTTON} to go back.",
"unlocked": "Press {START_BUTTON} to continue, hold {LEFT_BUTTON} + {RIGHT_BUTTON} to go back.",
"error": "Hold {LEFT_BUTTON} + {RIGHT_BUTTON} to go back."
"locked": "Press {START_BUTTON} to unlock, hold {LEFT_BUTTON}{RIGHT_BUTTON} + {START_BUTTON} to go back.",
"unlocked": "Press {START_BUTTON} to continue, hold {LEFT_BUTTON}{RIGHT_BUTTON} + {START_BUTTON} to go back.",
"error": "Hold {LEFT_BUTTON}{RIGHT_BUTTON} + {START_BUTTON} to go back."
},
"x76f041": {
@ -245,7 +245,7 @@
"ReflashGameScreen": {
"title": "{CART_ICON} Select game to convert cartridge to",
"prompt": "Make sure you select the correct region. Note that cartridges can only be converted for use with games that accept the same cartridge type.",
"itemPrompt": "{RIGHT_ARROW} Press {START_BUTTON} to select, hold {LEFT_BUTTON} + {RIGHT_BUTTON} to go back"
"itemPrompt": "{RIGHT_ARROW} Press {START_BUTTON} to select, hold {LEFT_BUTTON}{RIGHT_BUTTON} + {START_BUTTON} to go back"
},
"SystemIDEntryScreen": {
@ -263,7 +263,7 @@
"UnlockKeyScreen": {
"title": "{CART_ICON} Select unlocking key",
"prompt": "If the cartridge has been converted before, select the game it was last converted to. If it is currently blank, select 00-00-00-00-00-00-00-00.",
"itemPrompt": "{RIGHT_ARROW} Press {START_BUTTON} to select, hold {LEFT_BUTTON} + {RIGHT_BUTTON} to go back",
"itemPrompt": "{RIGHT_ARROW} Press {START_BUTTON} to select, hold {LEFT_BUTTON}{RIGHT_BUTTON} + {START_BUTTON} to go back",
"autoUnlock": "Use key from identified game (recommended)",
"useCustomKey": "Enter key manually...",

View File

@ -1,16 +1,27 @@
Konami System 573 security cartridge reset tool
===============================================
Konami System 573 security cartridge tool
=========================================
Version ${PROJECT_VERSION}
Release ${PROJECT_VERSION}
Use this disc by simply putting it into your 573; make sure DIP switch 4 (the
rightmost one) is off. Remember to insert the cartridge you want to reset or
dump prior to turning on the system.
# Usage
Use this disc by simply inserting it into your System 573 and rebooting. Ensure
DIP switch 4 (the rightmost one) is off in order to force the 573 to boot from
the CD-ROM drive rather than the internal flash memory. Remember to insert the
cartridge you want to reset, reflash or dump prior to turning on the system.
# Credits
Lead developer: spicyjpeg
Cartridge database: smf
Testing: Naoki Saito
# Disclaimer
This tool is experimental and provided with no warranty whatsoever. It is not
guaranteed to work and improper usage can PERMANENTLY BRICK your System 573
security cartridges. Use this tool at your own risk.
More information and source code are available at:
${PROJECT_HOMEPAGE_URL}
WARNING: This tool is experimental and provided with no warranty whatsoever. It
is not guaranteed to work and improper usage can PERMANENTLY BRICK your System
573 security cartridges. Use this tool at your own risk.

View File

@ -71,7 +71,7 @@ static const char *const _CARTDB_PATHS[cart::NUM_CHIP_TYPES]{
bool App::_cartDetectWorker(void) {
_workerStatus.setNextScreen(_cartInfoScreen);
_workerStatus.update(0, 4, WSTR("App.cartDetectWorker.identifyCart"));
_workerStatus.update(0, 3, WSTR("App.cartDetectWorker.readCart"));
_unloadCartData();
#ifdef ENABLE_DUMMY_DRIVER
@ -81,6 +81,7 @@ bool App::_cartDetectWorker(void) {
if (cart::dummyDriverDump.chipType) {
LOG("using dummy cart driver");
_driver = new cart::DummyDriver(_dump);
_driver->readSystemID();
} else {
_driver = cart::newCartDriver(_dump);
}
@ -91,7 +92,6 @@ bool App::_cartDetectWorker(void) {
if (_dump.chipType) {
LOG("cart dump @ 0x%08x", &_dump);
LOG("cart driver @ 0x%08x", _driver);
_workerStatus.update(1, 4, WSTR("App.cartDetectWorker.readCart"));
auto error = _driver->readCartID();
@ -106,7 +106,7 @@ bool App::_cartDetectWorker(void) {
_parser = cart::newCartParser(_dump);
LOG("cart parser @ 0x%08x", _parser);
_workerStatus.update(2, 4, WSTR("App.cartDetectWorker.identifyGame"));
_workerStatus.update(1, 3, WSTR("App.cartDetectWorker.identifyGame"));
if (!_db.ptr) {
if (!_resourceProvider->loadData(
@ -137,9 +137,13 @@ bool App::_cartDetectWorker(void) {
}
_cartInitDone:
_workerStatus.update(3, 4, WSTR("App.cartDetectWorker.readDigitalIO"));
_workerStatus.update(2, 3, WSTR("App.cartDetectWorker.readDigitalIO"));
#ifdef ENABLE_DUMMY_DRIVER
if (io::isDigitalIOPresent() && !(_dump.flags & cart::DUMP_SYSTEM_ID_OK)) {
#else
if (io::isDigitalIOPresent()) {
#endif
util::Data bitstream;
bool ready;
@ -158,15 +162,13 @@ _cartInitDone:
delayMicroseconds(5000); // Probably not necessary
io::initKonamiBitstream();
auto error = _driver->readSystemID();
if (error)
LOG("XID error [%s]", util::getErrorString(error));
}
// This must be outside of the if block above to make sure the system ID
// gets read with the dummy driver.
auto error = _driver->readSystemID();
if (error)
LOG("XID error [%s]", util::getErrorString(error));
return true;
}
@ -330,8 +332,6 @@ bool App::_cartReflashWorker(void) {
_parser->flush();
auto error = _driver->setDataKey(_selectedEntry->dataKey);
delayMicroseconds(1000000); // TODO: does this fix ZS01 bricking?
if (error)
LOG("key error [%s]", util::getErrorString(error));
else
@ -356,8 +356,6 @@ bool App::_cartEraseWorker(void) {
_workerStatus.update(0, 1, WSTR("App.cartEraseWorker.erase"));
auto error = _driver->erase();
delayMicroseconds(1000000); // TODO: does this fix ZS01 bricking?
_cartDetectWorker();
if (error) {
@ -533,6 +531,17 @@ _writeError:
bool App::_atapiEjectWorker(void) {
_workerStatus.update(0, 1, WSTR("App.atapiEjectWorker.eject"));
if (!(ide::devices[0].flags & ide::DEVICE_ATAPI)) {
LOG("primary drive is not ATAPI");
_messageScreen.setMessage(
MESSAGE_ERROR, _mainMenuScreen,
WSTR("App.atapiEjectWorker.atapiError")
);
_workerStatus.setNextScreen(_messageScreen);
return false;
}
ide::Packet packet;
packet.setStartStopUnit(ide::START_STOP_MODE_OPEN_TRAY);
@ -542,7 +551,8 @@ bool App::_atapiEjectWorker(void) {
LOG("eject error [%s]", util::getErrorString(error));
_messageScreen.setMessage(
MESSAGE_ERROR, _mainMenuScreen, WSTR("App.atapiEjectWorker.error")
MESSAGE_ERROR, _mainMenuScreen,
WSTR("App.atapiEjectWorker.ejectError")
);
_workerStatus.setNextScreen(_messageScreen);
return false;

View File

@ -179,10 +179,12 @@ void CartActionsScreen::update(ui::Context &ctx) {
ListScreen::update(ctx);
if (ctx.buttons.pressed(ui::BTN_START))
(this->*action.target)(ctx);
if (ctx.buttons.bothPressed(ui::BTN_LEFT, ui::BTN_RIGHT))
ctx.show(APP->_cartInfoScreen, true, true);
if (ctx.buttons.pressed(ui::BTN_START)) {
if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT))
ctx.show(APP->_cartInfoScreen, true, true);
else
(this->*action.target)(ctx);
}
}
static constexpr int _QR_CODE_SCALE = 2;
@ -200,10 +202,7 @@ void QRCodeScreen::show(ui::Context &ctx, bool goBack) {
}
void QRCodeScreen::update(ui::Context &ctx) {
if (
ctx.buttons.pressed(ui::BTN_START) ||
ctx.buttons.bothPressed(ui::BTN_LEFT, ui::BTN_RIGHT)
)
if (ctx.buttons.pressed(ui::BTN_START))
ctx.show(APP->_cartActionsScreen, true, true);
}
@ -230,10 +229,7 @@ void HexdumpScreen::show(ui::Context &ctx, bool goBack) {
void HexdumpScreen::update(ui::Context &ctx) {
TextScreen::update(ctx);
if (
ctx.buttons.pressed(ui::BTN_START) ||
ctx.buttons.bothPressed(ui::BTN_LEFT, ui::BTN_RIGHT)
)
if (ctx.buttons.pressed(ui::BTN_START))
ctx.show(APP->_cartActionsScreen, true, true);
}
@ -258,19 +254,21 @@ void ReflashGameScreen::update(ui::Context &ctx) {
ListScreen::update(ctx);
if (ctx.buttons.pressed(ui::BTN_START)) {
APP->_confirmScreen.setMessage(
*this,
[](ui::Context &ctx) {
APP->_setupWorker(&App::_cartReflashWorker);
ctx.show(APP->_workerStatusScreen, false, true);
},
STR("CartActionsScreen.reflash.confirm")
);
if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT)) {
ctx.show(APP->_cartActionsScreen, true, true);
} else {
APP->_confirmScreen.setMessage(
*this,
[](ui::Context &ctx) {
APP->_setupWorker(&App::_cartReflashWorker);
ctx.show(APP->_workerStatusScreen, false, true);
},
STR("CartActionsScreen.reflash.confirm")
);
APP->_selectedEntry = APP->_db.get(_activeItem);
ctx.show(APP->_confirmScreen, false, true);
} else if (ctx.buttons.bothPressed(ui::BTN_LEFT, ui::BTN_RIGHT)) {
ctx.show(APP->_cartActionsScreen, true, true);
APP->_selectedEntry = APP->_db.get(_activeItem);
ctx.show(APP->_confirmScreen, false, true);
}
}
}

View File

@ -207,14 +207,16 @@ void CartInfoScreen::show(ui::Context &ctx, bool goBack) {
void CartInfoScreen::update(ui::Context &ctx) {
TextScreen::update(ctx);
if (APP->_dump.chipType && ctx.buttons.pressed(ui::BTN_START)) {
if (APP->_dump.flags & cart::DUMP_PRIVATE_DATA_OK)
ctx.show(APP->_cartActionsScreen, false, true);
else
ctx.show(APP->_unlockKeyScreen, false, true);
if (ctx.buttons.pressed(ui::BTN_START)) {
if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT)) {
ctx.show(APP->_mainMenuScreen, true, true);
} else if (APP->_dump.chipType) {
if (APP->_dump.flags & cart::DUMP_PRIVATE_DATA_OK)
ctx.show(APP->_cartActionsScreen, false, true);
else
ctx.show(APP->_unlockKeyScreen, false, true);
}
}
if (ctx.buttons.bothPressed(ui::BTN_LEFT, ui::BTN_RIGHT))
ctx.show(APP->_mainMenuScreen, true, true);
}
enum SpecialEntryIndex {
@ -313,37 +315,38 @@ void UnlockKeyScreen::update(ui::Context &ctx) {
ListScreen::update(ctx);
if (ctx.buttons.pressed(ui::BTN_START)) {
int index = _activeItem + _getSpecialEntryOffset(ctx);
APP->_confirmScreen.setMessage(
APP->_unlockKeyScreen,
[](ui::Context &ctx) {
APP->_setupWorker(&App::_cartUnlockWorker);
ctx.show(APP->_workerStatusScreen, false, true);
},
STRH(_CART_TYPES[APP->_dump.chipType].warning)
);
APP->_messageScreen.setMessage(
MESSAGE_ERROR, APP->_cartInfoScreen,
STRH(_CART_TYPES[APP->_dump.chipType].error)
);
if (index < 0) {
(this->*_SPECIAL_ENTRIES[-index].target)(ctx);
if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT)) {
ctx.show(APP->_cartInfoScreen, true, true);
} else {
__builtin_memcpy(
APP->_dump.dataKey, APP->_db.get(index)->dataKey,
sizeof(APP->_dump.dataKey)
int index = _activeItem + _getSpecialEntryOffset(ctx);
APP->_confirmScreen.setMessage(
APP->_unlockKeyScreen,
[](ui::Context &ctx) {
APP->_setupWorker(&App::_cartUnlockWorker);
ctx.show(APP->_workerStatusScreen, false, true);
},
STRH(_CART_TYPES[APP->_dump.chipType].warning)
);
APP->_selectedEntry = APP->_db.get(index);
ctx.show(APP->_confirmScreen, false, true);
APP->_messageScreen.setMessage(
MESSAGE_ERROR, APP->_cartInfoScreen,
STRH(_CART_TYPES[APP->_dump.chipType].error)
);
if (index < 0) {
(this->*_SPECIAL_ENTRIES[-index].target)(ctx);
} else {
__builtin_memcpy(
APP->_dump.dataKey, APP->_db.get(index)->dataKey,
sizeof(APP->_dump.dataKey)
);
APP->_selectedEntry = APP->_db.get(index);
ctx.show(APP->_confirmScreen, false, true);
}
}
}
if (ctx.buttons.bothPressed(ui::BTN_LEFT, ui::BTN_RIGHT)) {
ctx.show(APP->_cartInfoScreen, true, true);
}
}
void KeyEntryScreen::show(ui::Context &ctx, bool goBack) {

View File

@ -81,14 +81,20 @@ public:
void (MainMenuScreen::*target)(ui::Context &ctx);
};
#ifdef ENABLE_CART_MENU
static constexpr int _NUM_MENU_ENTRIES = 5;
#else
static constexpr int _NUM_MENU_ENTRIES = 4;
#endif
static const MenuEntry _MENU_ENTRIES[_NUM_MENU_ENTRIES]{
{
#ifdef ENABLE_CART_MENU
.name = "MainMenuScreen.cartInfo.name"_h,
.prompt = "MainMenuScreen.cartInfo.prompt"_h,
.target = &MainMenuScreen::cartInfo
}, {
#endif
.name = "MainMenuScreen.dump.name"_h,
.prompt = "MainMenuScreen.dump.prompt"_h,
.target = &MainMenuScreen::dump
@ -194,11 +200,14 @@ void AboutScreen::show(ui::Context &ctx, bool goBack) {
auto ptr = reinterpret_cast<char *>(_text.ptr);
_body = ptr;
// Replace single newlines with spaces to reflow the text. The last
// character is also cut off and replaced with a null terminator.
// Replace single newlines with spaces to reflow the text, unless the line
// preceding the newline ends with a space. The last character is also cut
// off and replaced with a null terminator.
for (size_t i = _text.length - 1; i; i--, ptr++) {
if (*ptr != '\n')
continue;
if (__builtin_isspace(ptr[-1]))
continue;
if (ptr[1] == '\n')
i--, ptr++;
@ -221,9 +230,6 @@ void AboutScreen::hide(ui::Context &ctx, bool goBack) {
void AboutScreen::update(ui::Context &ctx) {
TextScreen::update(ctx);
if (
ctx.buttons.pressed(ui::BTN_START) ||
ctx.buttons.bothPressed(ui::BTN_LEFT, ui::BTN_RIGHT)
)
if (ctx.buttons.pressed(ui::BTN_START))
ctx.show(APP->_mainMenuScreen, true, true);
}

View File

@ -29,6 +29,11 @@ void Identifier::updateDSCRC(void) {
}
bool Identifier::validateDSCRC(void) const {
if (!data[0] || (data[0] == 0xff)) {
LOG("invalid 1-wire prefix 0x%02x", data[0]);
return false;
}
uint8_t value = util::dsCRC8(data, 7);
if (value != data[7]) {

View File

@ -28,7 +28,7 @@ void Font::draw(
switch (ch) {
case '\t':
x += metrics.tabWidth - 1;
x += metrics.tabWidth;
x -= x % metrics.tabWidth;
break;
@ -144,7 +144,7 @@ void Font::getStringBounds(
if (breakOnSpace)
goto _break;
x += metrics.tabWidth - 1;
x += metrics.tabWidth;
x -= x % metrics.tabWidth;
break;
@ -214,7 +214,7 @@ int Font::getStringWidth(const char *str, bool breakOnSpace) const {
if (breakOnSpace)
goto _break;
width += metrics.tabWidth - 1;
width += metrics.tabWidth;
width -= width % metrics.tabWidth;
break;

View File

@ -18,7 +18,7 @@ public:
inline uint32_t getCharacterSize(uint8_t ch) const {
uint32_t sizes = characterSizes[ch];
if (!sizes)
return characterSizes[FONT_INVALID_CHAR];
return characterSizes[int(FONT_INVALID_CHAR)];
return sizes;
}

View File

@ -125,15 +125,6 @@ void ButtonState::update(void) {
}
}
bool ButtonState::bothPressed(Button buttonA, Button buttonB) {
if (pressed(buttonA) && held(buttonB))
return true;
if (held(buttonA) && pressed(buttonB))
return true;
return false;
}
/* UI context */
Context::Context(gpu::Context &gpuCtx, void *screenData)

View File

@ -128,7 +128,6 @@ public:
ButtonState(void);
void update(void);
bool bothPressed(Button buttonA, Button buttonB);
};
/* UI context */