mirror of
https://github.com/spicyjpeg/573in1.git
synced 2025-01-22 19:52:05 +01:00
Bump version to 0.3.2, add system ID resetting
This commit is contained in:
parent
4a2e01402d
commit
a0976dee11
@ -6,7 +6,7 @@ set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain.cmake")
|
||||
project(
|
||||
cart_tool_private
|
||||
LANGUAGES C CXX ASM
|
||||
VERSION 0.3.1
|
||||
VERSION 0.3.2
|
||||
DESCRIPTION "Konami System 573 security cartridge tool"
|
||||
)
|
||||
|
||||
@ -63,9 +63,14 @@ target_include_directories(
|
||||
target_compile_definitions(
|
||||
cart_tool PRIVATE
|
||||
VERSION="${PROJECT_VERSION}"
|
||||
#ENABLE_ARGV=1
|
||||
ENABLE_PS1_CONTROLLER=1
|
||||
ENABLE_I2C_LOGGING=1
|
||||
$<IF:$<CONFIG:Debug>,
|
||||
ENABLE_DUMMY_DRIVER=1
|
||||
ENABLE_I2C_LOGGING=1
|
||||
ENABLE_PS1_CONTROLLER=1
|
||||
,
|
||||
#ENABLE_ARGV=1
|
||||
ENABLE_PS1_CONTROLLER=1
|
||||
>
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
@ -104,7 +109,8 @@ ps1_target_incbin(
|
||||
#add_custom_command(
|
||||
# COMMAND
|
||||
# "${Python3_EXECUTABLE}" "${PROJECT_SOURCE_DIR}/tools/buildCDImage.py"
|
||||
# -s "${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/cd.json" cart_tool.iso
|
||||
# -s "${PROJECT_BINARY_DIR}"
|
||||
# "${PROJECT_SOURCE_DIR}/cd.json" cart_tool.iso
|
||||
# OUTPUT cart_tool.iso
|
||||
# DEPENDS cd.json cart_tool
|
||||
# COMMENT "Building CD-ROM image"
|
||||
|
@ -6,12 +6,21 @@
|
||||
"readCart": "Reading security cartridge...",
|
||||
"identifyGame": "Attempting to identify game..."
|
||||
},
|
||||
"cartEraseWorker": {
|
||||
"erase": "Performing cartridge erase...",
|
||||
"error": "An error occurred while erasing the cartridge's EEPROM.\n\nPress the Test button to view debug logs."
|
||||
},
|
||||
"cartUnlockWorker": {
|
||||
"read": "Dumping cartridge...",
|
||||
"identifyGame": "Attempting to identify game..."
|
||||
},
|
||||
"cartWriteWorker": {
|
||||
"write": "Writing new data to cartridge...",
|
||||
"error": "An error occurred while writing to the cartridge's EEPROM.\n\nPress the Test button to view debug logs."
|
||||
},
|
||||
"hddDumpWorker": {
|
||||
"save": "Saving cartridge dump..."
|
||||
"save": "Saving cartridge dump...",
|
||||
"error": "An error occurred while saving the dump to the hard drive. Turn off the system and make sure the drive is connected to the IDE bus properly, set as secondary and formatted with a single FAT16, FAT32 or exFAT partition.\n\nPress the Test button to view debug logs."
|
||||
},
|
||||
"qrCodeWorker": {
|
||||
"compress": "Compressing cartridge dump...",
|
||||
@ -44,23 +53,23 @@
|
||||
},
|
||||
"hddDump": {
|
||||
"name": "Dump cartridge to hard drive",
|
||||
"prompt": "Save the contents of the cartridge's EEPROM to a file on the IDE hard drive or CF card connected as secondary drive (if any).",
|
||||
"error": "An error occurred while saving the dump to the hard drive. Turn off the system and make sure the drive is connected to the IDE bus properly, set as secondary and formatted with a single FAT16, FAT32 or exFAT partition.\n\nPress the Test button to view debug logs."
|
||||
"prompt": "Save the contents of the cartridge's EEPROM to a file on the IDE hard drive or CF card connected as secondary drive (if any)."
|
||||
},
|
||||
"hexdump": {
|
||||
"name": "View cartridge hexdump",
|
||||
"name": "[UNIMPLEMENTED] View cartridge hexdump",
|
||||
"prompt": "Display the raw contents of the cartridge's EEPROM."
|
||||
},
|
||||
"resetSystemID": {
|
||||
"name": "Reset system identifier (unpair cartridge)",
|
||||
"prompt": "Delete any previously saved system identifier, allowing the cartridge to be used to reinstall the game on any system."
|
||||
"name": "Reset system identifier (unpair cartridge)",
|
||||
"prompt": "Delete any previously saved system identifier, allowing the cartridge to be used to reinstall the game on any system.",
|
||||
"confirm": "The system identifier will be cleared, allowing the cartridge to be used on a system with any digital I/O board. The game will have to be reinstalled in order to pair the cartridge to the new board.\n\nDo you wish to proceed?"
|
||||
},
|
||||
"editSystemID": {
|
||||
"name": "Edit system identifier (pair to another 573)",
|
||||
"name": "[UNIMPLEMENTED] Edit system identifier",
|
||||
"prompt": "Edit the saved system identifier to allow the cartridge to be used on a specific system without having to reinstall the game first."
|
||||
},
|
||||
"reflash": {
|
||||
"name": "Erase and reflash cartridge",
|
||||
"name": "[UNIMPLEMENTED] Erase and convert to another game",
|
||||
"prompt": "Wipe all data and flash the cartridge with another game's identifiers. All cartridges can be converted for use with any other game that uses the same cartridge type."
|
||||
},
|
||||
"erase": {
|
||||
@ -85,6 +94,13 @@
|
||||
"locked": "{CLOSED_LOCK} locked, game key required",
|
||||
"unlocked": "{OPEN_LOCK} unlocked"
|
||||
},
|
||||
"pairing": {
|
||||
"unsupported": "This game does not pair to I/O boards",
|
||||
"unknown": "Unlock cartridge to view pairing status",
|
||||
"unpaired": "Not paired to any digital I/O board",
|
||||
"thisSystem": "Paired to this system's I/O board",
|
||||
"otherSystem": "Paired to %s (%s)"
|
||||
},
|
||||
"description": {
|
||||
"noCart": "No supported cartridge has been found.\n\nTurn off the system and insert a security cartridge in order to continue. DO NOT HOTPLUG CARTRIDGES; hotplugging may damage both the 573 and the cartridge.\n\nIf a cartridge is inserted but not detected, try cleaning its pins as well as the system's security cartridge connector.",
|
||||
"initError": "Failed to initialize and read unprotected data from this cartridge.\n\nTurn off the system and make sure the cartridge is inserted correctly. If this issue persists, try using another cartridge of the same type.",
|
||||
@ -98,12 +114,6 @@
|
||||
"unidentified": "This cartridge contains data for an unsupported game.\n\nThe system identifier (if any) cannot be reset or edited, however you may still dump the cartridge's contents or reflash it for use with a supported game.",
|
||||
"identified": "This cartridge has been identified as:\n %s\n %s\n\nYou may now proceed to reset the system identifier, edit it or erase and reflash the cartridge for use with another game.",
|
||||
"blank": "This cartridge has been previously erased and is now blank.\n\nIt must be flashed and optionally initialized with a system identifier in order to be used with a supported game."
|
||||
},
|
||||
"pairing": {
|
||||
"unsupported": "This game does not pair to I/O boards",
|
||||
"unpaired": "Not paired to any digital I/O board",
|
||||
"thisSystem": "Paired to this system's I/O board",
|
||||
"otherSystem": "Paired to %s"
|
||||
}
|
||||
},
|
||||
"prompt": {
|
||||
@ -130,7 +140,7 @@
|
||||
},
|
||||
|
||||
"ConfirmScreen": {
|
||||
"title": "Confirm",
|
||||
"title": "Confirm operation",
|
||||
"no": "No, go back",
|
||||
"yes": "Yes, continue"
|
||||
},
|
||||
|
@ -13,8 +13,8 @@ public:
|
||||
void (CartActionsScreen::*target)(ui::Context &ctx);
|
||||
};
|
||||
|
||||
static constexpr int _NUM_IDENTIFIED_ACTIONS = 7;
|
||||
static constexpr int _NUM_UNIDENTIFIED_ACTIONS = 5;
|
||||
static constexpr int _NUM_SYSTEM_ID_ACTIONS = 7;
|
||||
static constexpr int _NUM_NO_SYSTEM_ID_ACTIONS = 5;
|
||||
|
||||
static const Action _ACTIONS[]{
|
||||
{
|
||||
@ -58,8 +58,6 @@ void CartActionsScreen::qrDump(ui::Context &ctx) {
|
||||
}
|
||||
|
||||
void CartActionsScreen::hddDump(ui::Context &ctx) {
|
||||
APP->_errorScreen.setMessage(*this, STR("CartActionsScreen.hddDump.error"));
|
||||
|
||||
APP->_setupWorker(&App::_hddDumpWorker);
|
||||
ctx.show(APP->_workerStatusScreen, false, true);
|
||||
}
|
||||
@ -74,8 +72,8 @@ void CartActionsScreen::erase(ui::Context &ctx) {
|
||||
APP->_confirmScreen.setMessage(
|
||||
*this,
|
||||
[](ui::Context &ctx) {
|
||||
//APP->_setupWorker(&App::_eraseWorker);
|
||||
//ctx.show(APP->_workerStatusScreen, false, true);
|
||||
APP->_setupWorker(&App::_cartEraseWorker);
|
||||
ctx.show(APP->_workerStatusScreen, false, true);
|
||||
},
|
||||
STR("CartActionsScreen.erase.confirm")
|
||||
);
|
||||
@ -84,6 +82,19 @@ void CartActionsScreen::erase(ui::Context &ctx) {
|
||||
}
|
||||
|
||||
void CartActionsScreen::resetSystemID(ui::Context &ctx) {
|
||||
APP->_confirmScreen.setMessage(
|
||||
*this,
|
||||
[](ui::Context &ctx) {
|
||||
APP->_parser->getIdentifiers()->systemID.clear();
|
||||
APP->_parser->flush();
|
||||
|
||||
APP->_setupWorker(&App::_cartWriteWorker);
|
||||
ctx.show(APP->_workerStatusScreen, false, true);
|
||||
},
|
||||
STR("CartActionsScreen.resetSystemID.confirm")
|
||||
);
|
||||
|
||||
ctx.show(APP->_confirmScreen, false, true);
|
||||
}
|
||||
|
||||
void CartActionsScreen::editSystemID(ui::Context &ctx) {
|
||||
@ -94,13 +105,12 @@ void CartActionsScreen::show(ui::Context &ctx, bool goBack) {
|
||||
_prompt = STRH(_ACTIONS[0].prompt);
|
||||
_itemPrompt = STR("CartActionsScreen.itemPrompt");
|
||||
|
||||
#if 0 // TODO
|
||||
_listLength = APP->_identified
|
||||
? _NUM_IDENTIFIED_ACTIONS
|
||||
: _NUM_UNIDENTIFIED_ACTIONS;
|
||||
#else
|
||||
_listLength = 2;
|
||||
#endif
|
||||
_listLength = _NUM_NO_SYSTEM_ID_ACTIONS;
|
||||
|
||||
if (APP->_identified) {
|
||||
if (APP->_identified->flags & cart::DATA_HAS_SYSTEM_ID)
|
||||
_listLength = _NUM_SYSTEM_ID_ACTIONS;
|
||||
}
|
||||
|
||||
ListScreen::show(ctx, goBack);
|
||||
}
|
||||
|
141
src/app/app.cpp
141
src/app/app.cpp
@ -16,27 +16,37 @@
|
||||
|
||||
void App::_unloadCartData(void) {
|
||||
if (_driver) {
|
||||
delete _driver;
|
||||
_driver = nullptr;
|
||||
//delete _driver;
|
||||
//_driver = nullptr;
|
||||
}
|
||||
if (_parser) {
|
||||
delete _parser;
|
||||
_parser = nullptr;
|
||||
}
|
||||
|
||||
_db.destroy();
|
||||
_dump.chipType = cart::NONE;
|
||||
_dump.clearIdentifiers();
|
||||
_dump.clearData();
|
||||
|
||||
_identified = nullptr;
|
||||
_db.destroy();
|
||||
}
|
||||
|
||||
void App::_setupWorker(void (App::* func)(void)) {
|
||||
LOG("starting thread, func=0x%08x", func);
|
||||
void App::_setupWorker(void (App::*func)(void)) {
|
||||
LOG("restarting worker, func=0x%08x", func);
|
||||
|
||||
auto mask = setInterruptMask(0);
|
||||
|
||||
_workerStatus.reset();
|
||||
_workerFunction = func;
|
||||
|
||||
initThread(
|
||||
// This is not how you implement delegates in C++.
|
||||
&_workerThread, util::forcedCast<ArgFunction>(func), this,
|
||||
&_workerThread, util::forcedCast<ArgFunction>(&App::_worker), this,
|
||||
&_workerStack[(WORKER_STACK_SIZE - 1) & ~7]
|
||||
);
|
||||
if (mask)
|
||||
setInterruptMask(mask);
|
||||
}
|
||||
|
||||
void App::_setupInterrupts(void) {
|
||||
@ -49,11 +59,6 @@ void App::_setupInterrupts(void) {
|
||||
|
||||
/* Worker functions */
|
||||
|
||||
void App::_dummyWorker(void) {
|
||||
for (;;)
|
||||
__asm__ volatile("");
|
||||
}
|
||||
|
||||
static const char *const _CARTDB_PATHS[cart::NUM_CHIP_TYPES]{
|
||||
nullptr,
|
||||
"data/x76f041.cartdb",
|
||||
@ -62,23 +67,25 @@ static const char *const _CARTDB_PATHS[cart::NUM_CHIP_TYPES]{
|
||||
};
|
||||
|
||||
void App::_cartDetectWorker(void) {
|
||||
_workerStatus.setNextScreen(_cartInfoScreen);
|
||||
_workerStatus.update(0, 4, WSTR("App.cartDetectWorker.identifyCart"));
|
||||
_unloadCartData();
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (
|
||||
_resourceProvider->loadStruct(_dump, "data/test.573")
|
||||
== sizeof(cart::Dump)
|
||||
) {
|
||||
LOG("using dummy cart driver");
|
||||
_driver = new cart::DummyDriver(_dump);
|
||||
_driver->readSystemID();
|
||||
} else {
|
||||
_driver = cart::newCartDriver(_dump);
|
||||
}
|
||||
if (!_driver) {
|
||||
#ifdef ENABLE_DUMMY_DRIVER
|
||||
if (
|
||||
_resourceProvider->loadStruct(_dump, "data/test.573")
|
||||
== sizeof(cart::Dump)
|
||||
) {
|
||||
LOG("using dummy cart driver");
|
||||
_driver = new cart::DummyDriver(_dump);
|
||||
} else {
|
||||
_driver = cart::newCartDriver(_dump);
|
||||
}
|
||||
#else
|
||||
_driver = cart::newCartDriver(_dump);
|
||||
_driver = cart::newCartDriver(_dump);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_dump.chipType) {
|
||||
LOG("cart dump @ 0x%08x", &_dump);
|
||||
@ -114,7 +121,7 @@ _cartInitDone:
|
||||
|
||||
if (!_resourceProvider->loadData(bitstream, "data/fpga.bit")) {
|
||||
LOG("bitstream unavailable");
|
||||
goto _initDone;
|
||||
return;
|
||||
}
|
||||
|
||||
ready = io::loadBitstream(bitstream.as<uint8_t>(), bitstream.length);
|
||||
@ -122,25 +129,27 @@ _cartInitDone:
|
||||
|
||||
if (!ready) {
|
||||
LOG("bitstream upload failed");
|
||||
goto _initDone;
|
||||
return;
|
||||
}
|
||||
|
||||
delayMicroseconds(5000); // Probably not necessary
|
||||
io::initKonamiBitstream();
|
||||
_driver->readSystemID();
|
||||
}
|
||||
|
||||
_initDone:
|
||||
_workerStatus.finish(_cartInfoScreen);
|
||||
_dummyWorker();
|
||||
// This must be outside of the if block above to make sure the system ID
|
||||
// gets read with the dummy driver.
|
||||
_driver->readSystemID();
|
||||
}
|
||||
|
||||
void App::_cartUnlockWorker(void) {
|
||||
_workerStatus.setNextScreen(_cartInfoScreen, true);
|
||||
_workerStatus.update(0, 2, WSTR("App.cartUnlockWorker.read"));
|
||||
|
||||
if (_driver->readPrivateData()) {
|
||||
_workerStatus.finish(_errorScreen);
|
||||
_dummyWorker();
|
||||
/*_errorScreen.setMessage(
|
||||
_cartInfoScreen, WSTR("App.cartUnlockWorker.error")
|
||||
);*/
|
||||
_workerStatus.setNextScreen(_errorScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -149,7 +158,7 @@ void App::_cartUnlockWorker(void) {
|
||||
|
||||
_parser = cart::newCartParser(_dump);
|
||||
if (!_parser)
|
||||
goto _unlockDone;
|
||||
return;
|
||||
|
||||
LOG("cart parser @ 0x%08x", _parser);
|
||||
_workerStatus.update(1, 2, WSTR("App.cartUnlockWorker.identifyGame"));
|
||||
@ -158,23 +167,17 @@ void App::_cartUnlockWorker(void) {
|
||||
|
||||
if (_parser->getCode(code) && _parser->getRegion(region))
|
||||
_identified = _db.lookup(code, region);
|
||||
|
||||
_unlockDone:
|
||||
_workerStatus.finish(_cartInfoScreen, true);
|
||||
_dummyWorker();
|
||||
}
|
||||
|
||||
void App::_qrCodeWorker(void) {
|
||||
char qrString[cart::MAX_QR_STRING_LENGTH];
|
||||
|
||||
_workerStatus.setNextScreen(_qrCodeScreen);
|
||||
_workerStatus.update(0, 2, WSTR("App.qrCodeWorker.compress"));
|
||||
_dump.toQRString(qrString);
|
||||
|
||||
_workerStatus.update(1, 2, WSTR("App.qrCodeWorker.generate"));
|
||||
_qrCodeScreen.generateCode(qrString);
|
||||
|
||||
_workerStatus.finish(_qrCodeScreen);
|
||||
_dummyWorker();
|
||||
}
|
||||
|
||||
void App::_hddDumpWorker(void) {
|
||||
@ -182,19 +185,52 @@ void App::_hddDumpWorker(void) {
|
||||
|
||||
char code[8], region[8], path[32];
|
||||
|
||||
if (_parser->getCode(code) && _parser->getRegion(region))
|
||||
if (_identified && _parser->getCode(code) && _parser->getRegion(region))
|
||||
snprintf(path, sizeof(path), "%s%s.573", code, region);
|
||||
else
|
||||
__builtin_strcpy(path, "unknown_cart.573");
|
||||
__builtin_strcpy(path, "unknown.573");
|
||||
|
||||
LOG("saving dump as %s", path);
|
||||
|
||||
if (_fileProvider->saveStruct(_dump, path) == sizeof(cart::Dump))
|
||||
_workerStatus.finish(_cartInfoScreen);
|
||||
else
|
||||
_workerStatus.finish(_errorScreen);
|
||||
if (_fileProvider->saveStruct(_dump, path) != sizeof(cart::Dump)) {
|
||||
_errorScreen.setMessage(
|
||||
_cartInfoScreen, WSTR("App.hddDumpWorker.error")
|
||||
);
|
||||
_workerStatus.setNextScreen(_errorScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
_dummyWorker();
|
||||
_workerStatus.setNextScreen(_cartInfoScreen);
|
||||
}
|
||||
|
||||
void App::_cartWriteWorker(void) {
|
||||
_workerStatus.update(0, 1, WSTR("App.cartWriteWorker.write"));
|
||||
|
||||
if (_driver->writeData()) {
|
||||
_errorScreen.setMessage(
|
||||
_cartInfoScreen, WSTR("App.cartWriteWorker.error")
|
||||
);
|
||||
_workerStatus.setNextScreen(_errorScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
_cartDetectWorker();
|
||||
_cartUnlockWorker();
|
||||
}
|
||||
|
||||
void App::_cartEraseWorker(void) {
|
||||
_workerStatus.update(0, 1, WSTR("App.cartEraseWorker.erase"));
|
||||
|
||||
if (_driver->erase()) {
|
||||
_errorScreen.setMessage(
|
||||
_cartInfoScreen, WSTR("App.cartEraseWorker.error")
|
||||
);
|
||||
_workerStatus.setNextScreen(_errorScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
_cartDetectWorker();
|
||||
_cartUnlockWorker();
|
||||
}
|
||||
|
||||
void App::_rebootWorker(void) {
|
||||
@ -219,6 +255,17 @@ void App::_rebootWorker(void) {
|
||||
|
||||
/* Misc. functions */
|
||||
|
||||
void App::_worker(void) {
|
||||
if (_workerFunction) {
|
||||
(this->*_workerFunction)();
|
||||
_workerStatus.finish();
|
||||
}
|
||||
|
||||
// Do nothing while waiting for vblank once the task is done.
|
||||
for (;;)
|
||||
__asm__ volatile("");
|
||||
}
|
||||
|
||||
void App::_interruptHandler(void) {
|
||||
if (acknowledgeInterrupt(IRQ_VBLANK)) {
|
||||
_ctx->tick();
|
||||
@ -251,7 +298,7 @@ void App::run(
|
||||
ctx.show(_buttonMappingScreen);
|
||||
#endif
|
||||
|
||||
_setupWorker(&App::_dummyWorker);
|
||||
_setupWorker(nullptr);
|
||||
_setupInterrupts();
|
||||
|
||||
for (;;) {
|
||||
|
@ -25,6 +25,10 @@ enum WorkerStatusType {
|
||||
// This class is used by the worker thread to report its current status back to
|
||||
// the main thread and the WorkerStatusScreen.
|
||||
class WorkerStatus {
|
||||
private:
|
||||
volatile bool _nextGoBack;
|
||||
ui::Screen *volatile _nextScreen;
|
||||
|
||||
public:
|
||||
volatile WorkerStatusType status;
|
||||
|
||||
@ -58,10 +62,18 @@ public:
|
||||
if (mask)
|
||||
setInterruptMask(mask);
|
||||
}
|
||||
inline void finish(ui::Screen &next, bool goBack = false) {
|
||||
inline void setNextScreen(ui::Screen &next, bool goBack = false) {
|
||||
auto mask = setInterruptMask(0);
|
||||
_nextGoBack = goBack;
|
||||
_nextScreen = &next;
|
||||
|
||||
if (mask)
|
||||
setInterruptMask(mask);
|
||||
}
|
||||
inline void finish(void) {
|
||||
auto mask = setInterruptMask(0);
|
||||
status = goBack ? WORKER_NEXT_BACK : WORKER_NEXT;
|
||||
nextScreen = &next;
|
||||
status = _nextGoBack ? WORKER_NEXT_BACK : WORKER_NEXT;
|
||||
nextScreen = _nextScreen;
|
||||
|
||||
if (mask)
|
||||
setInterruptMask(mask);
|
||||
@ -70,7 +82,7 @@ public:
|
||||
|
||||
/* App class */
|
||||
|
||||
static constexpr size_t WORKER_STACK_SIZE = 0x10000;
|
||||
static constexpr size_t WORKER_STACK_SIZE = 0x20000;
|
||||
|
||||
class App {
|
||||
friend class WorkerStatusScreen;
|
||||
@ -104,6 +116,7 @@ private:
|
||||
cart::CartDB _db;
|
||||
Thread _workerThread;
|
||||
WorkerStatus _workerStatus;
|
||||
void (App::*_workerFunction)(void);
|
||||
|
||||
uint8_t *_workerStack;
|
||||
cart::Driver *_driver;
|
||||
@ -113,16 +126,18 @@ private:
|
||||
bool _allowWatchdogClear;
|
||||
|
||||
void _unloadCartData(void);
|
||||
void _setupWorker(void (App::* func)(void));
|
||||
void _setupWorker(void (App::*func)(void));
|
||||
void _setupInterrupts(void);
|
||||
|
||||
void _dummyWorker(void);
|
||||
void _cartDetectWorker(void);
|
||||
void _cartUnlockWorker(void);
|
||||
void _qrCodeWorker(void);
|
||||
void _hddDumpWorker(void);
|
||||
void _cartWriteWorker(void);
|
||||
void _cartEraseWorker(void);
|
||||
void _rebootWorker(void);
|
||||
|
||||
void _worker(void);
|
||||
void _interruptHandler(void);
|
||||
|
||||
public:
|
||||
|
@ -77,7 +77,9 @@ void CartInfoScreen::show(ui::Context &ctx, bool goBack) {
|
||||
__builtin_strcpy(id2, id1);
|
||||
}
|
||||
|
||||
ptr += snprintf(ptr, end - ptr, STR("CartInfoScreen.digitalIOInfo"), id1, id2);
|
||||
ptr += snprintf(
|
||||
ptr, end - ptr, STR("CartInfoScreen.digitalIOInfo"), id1, id2
|
||||
);
|
||||
|
||||
// Cartridge info
|
||||
if (!dump.chipType) {
|
||||
@ -139,7 +141,37 @@ void CartInfoScreen::show(ui::Context &ctx, bool goBack) {
|
||||
if (APP->_identified) {
|
||||
state = IDENTIFIED;
|
||||
APP->_identified->getDisplayName(name, sizeof(name));
|
||||
pairStatus[0] = 0; // TODO
|
||||
|
||||
//
|
||||
|
||||
auto ids = APP->_parser->getIdentifiers();
|
||||
|
||||
if (!(APP->_identified->flags & cart::DATA_HAS_SYSTEM_ID)) {
|
||||
__builtin_strcpy(
|
||||
pairStatus, STR("CartInfoScreen.pairing.unsupported")
|
||||
);
|
||||
} else if (!ids || !(dump.flags & cart::DUMP_PRIVATE_DATA_OK)) {
|
||||
__builtin_strcpy(pairStatus, STR("CartInfoScreen.pairing.unknown"));
|
||||
} else {
|
||||
auto &id = ids->systemID;
|
||||
|
||||
id.toString(id1);
|
||||
id.toSerialNumber(id2);
|
||||
|
||||
if (!__builtin_memcmp(id.data, dump.systemID.data, sizeof(id.data)))
|
||||
__builtin_strcpy(
|
||||
pairStatus, STR("CartInfoScreen.pairing.thisSystem")
|
||||
);
|
||||
else if (id.isEmpty())
|
||||
__builtin_strcpy(
|
||||
pairStatus, STR("CartInfoScreen.pairing.unpaired")
|
||||
);
|
||||
else
|
||||
snprintf(
|
||||
pairStatus, sizeof(pairStatus),
|
||||
STR("CartInfoScreen.pairing.otherSystem"), id1, id2
|
||||
);
|
||||
}
|
||||
} else if (dump.flags & cart::DUMP_PUBLIC_DATA_OK) {
|
||||
state = APP->_dump.isReadableDataEmpty() ? BLANK_CART : UNIDENTIFIED;
|
||||
} else {
|
||||
|
21
src/cart.hpp
21
src/cart.hpp
@ -167,11 +167,26 @@ public:
|
||||
inline size_t getDumpLength(void) const {
|
||||
return (sizeof(Dump) - sizeof(data)) + getChipSize().dataLength;
|
||||
}
|
||||
inline void clear(void) {
|
||||
__builtin_memset(this, 0, sizeof(Dump));
|
||||
inline void clearIdentifiers(void) {
|
||||
__builtin_memset(&systemID, 0, sizeof(Identifier) * 3);
|
||||
}
|
||||
inline void copyDataFrom(const uint8_t *source) {
|
||||
__builtin_memcpy(data, source, getChipSize().dataLength);
|
||||
}
|
||||
inline void copyDataTo(uint8_t *dest) {
|
||||
__builtin_memcpy(dest, data, getChipSize().dataLength);
|
||||
}
|
||||
inline void clearData(void) {
|
||||
__builtin_memset(data, 0, getChipSize().dataLength);
|
||||
__builtin_memset(data, 0, sizeof(data));
|
||||
}
|
||||
inline void copyKeyFrom(const uint8_t *source) {
|
||||
__builtin_memcpy(dataKey, source, sizeof(dataKey));
|
||||
}
|
||||
inline void copyKeyTo(uint8_t *dest) {
|
||||
__builtin_memcpy(dest, dataKey, sizeof(dataKey));
|
||||
}
|
||||
inline void clearKey(void) {
|
||||
__builtin_memset(dataKey, 0, sizeof(dataKey));
|
||||
}
|
||||
|
||||
bool isPublicDataEmpty(void) const;
|
||||
|
@ -75,8 +75,8 @@ bool BasicParser::validate(void) {
|
||||
size_t ExtendedParser::getCode(char *output) const {
|
||||
auto header = _getHeader();
|
||||
|
||||
__builtin_memcpy(output, header->code, sizeof(header->code));
|
||||
output[sizeof(header->code)] = 0;
|
||||
__builtin_memcpy(output, header->code, sizeof(header->code) - 1);
|
||||
output[sizeof(header->code) - 1] = 0;
|
||||
|
||||
if (flags & DATA_GX706_WORKAROUND)
|
||||
output[1] = 'X';
|
||||
@ -102,14 +102,21 @@ IdentifierSet *ExtendedParser::getIdentifiers(void) {
|
||||
);
|
||||
}
|
||||
|
||||
PublicIdentifierSet *ExtendedParser::getPublicIdentifiers(void) {
|
||||
if (!(flags & DATA_HAS_PUBLIC_SECTION))
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<PublicIdentifierSet *>(
|
||||
&_getPublicData()[sizeof(ExtendedHeader)]
|
||||
);
|
||||
}
|
||||
|
||||
void ExtendedParser::flush(void) {
|
||||
// Copy over the private identifiers to the public data area. On X76F041
|
||||
// carts this area is in the last sector, while on ZS01 carts it is placed
|
||||
// in the first 32 bytes.
|
||||
auto pri = getIdentifiers();
|
||||
auto pub = reinterpret_cast<PublicIdentifierSet *>(
|
||||
&_getPublicData()[sizeof(ExtendedHeader)]
|
||||
);
|
||||
auto pub = getPublicIdentifiers();
|
||||
|
||||
pub->traceID.copyFrom(pri->traceID.data);
|
||||
pub->cartID.copyFrom(pri->cartID.data);
|
||||
|
@ -36,6 +36,7 @@ public:
|
||||
virtual size_t getCode(char *output) const { return 0; }
|
||||
virtual size_t getRegion(char *output) const { return 0; }
|
||||
virtual IdentifierSet *getIdentifiers(void) { return nullptr; }
|
||||
virtual PublicIdentifierSet *getPublicIdentifiers(void) { return nullptr; }
|
||||
virtual void flush(void) {}
|
||||
virtual bool validate(void);
|
||||
};
|
||||
@ -81,6 +82,7 @@ public:
|
||||
size_t getCode(char *output) const;
|
||||
size_t getRegion(char *output) const;
|
||||
IdentifierSet *getIdentifiers(void);
|
||||
PublicIdentifierSet *getPublicIdentifiers(void);
|
||||
void flush(void);
|
||||
bool validate(void);
|
||||
};
|
||||
|
@ -12,6 +12,7 @@ namespace cart {
|
||||
|
||||
DriverError DummyDriver::readSystemID(void) {
|
||||
if (_privateDump.flags & DUMP_SYSTEM_ID_OK) {
|
||||
_dump.systemID.copyFrom(_privateDump.systemID.data);
|
||||
_dump.flags |= DUMP_SYSTEM_ID_OK;
|
||||
return NO_ERROR;
|
||||
}
|
||||
@ -20,9 +21,12 @@ DriverError DummyDriver::readSystemID(void) {
|
||||
}
|
||||
|
||||
DriverError DummyDriver::readCartID(void) {
|
||||
if (_privateDump.flags & DUMP_ZS_ID_OK)
|
||||
if (_privateDump.flags & DUMP_ZS_ID_OK) {
|
||||
_dump.zsID.copyFrom(_privateDump.zsID.data);
|
||||
_dump.flags |= DUMP_ZS_ID_OK;
|
||||
}
|
||||
if (_privateDump.flags & DUMP_CART_ID_OK) {
|
||||
_dump.cartID.copyFrom(_privateDump.cartID.data);
|
||||
_dump.flags |= DUMP_CART_ID_OK;
|
||||
return NO_ERROR;
|
||||
}
|
||||
@ -32,6 +36,7 @@ DriverError DummyDriver::readCartID(void) {
|
||||
|
||||
DriverError DummyDriver::readPublicData(void) {
|
||||
if (_privateDump.flags & DUMP_PUBLIC_DATA_OK) {
|
||||
_dump.copyDataFrom(_privateDump.data);
|
||||
_dump.flags |= DUMP_PUBLIC_DATA_OK;
|
||||
return NO_ERROR;
|
||||
}
|
||||
@ -43,6 +48,7 @@ DriverError DummyDriver::readPrivateData(void) {
|
||||
if ((_privateDump.flags & DUMP_PRIVATE_DATA_OK) && !__builtin_memcmp(
|
||||
_dump.dataKey, _privateDump.dataKey, sizeof(_dump.dataKey)
|
||||
)) {
|
||||
_dump.copyDataFrom(_privateDump.data);
|
||||
_dump.flags |= DUMP_PRIVATE_DATA_OK;
|
||||
return NO_ERROR;
|
||||
}
|
||||
@ -54,7 +60,7 @@ DriverError DummyDriver::writeData(void) {
|
||||
if (!__builtin_memcmp(
|
||||
_dump.dataKey, _privateDump.dataKey, sizeof(_dump.dataKey)
|
||||
)) {
|
||||
__builtin_memcpy(_privateDump.data, _dump.data, sizeof(_dump.data));
|
||||
_privateDump.copyDataFrom(_dump.data);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@ -66,7 +72,10 @@ DriverError DummyDriver::erase(void) {
|
||||
_dump.dataKey, _privateDump.dataKey, sizeof(_dump.dataKey)
|
||||
)) {
|
||||
_privateDump.clearData();
|
||||
_privateDump.clearKey();
|
||||
// TODO: clear config registers as well
|
||||
|
||||
_dump.clearKey();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@ -74,9 +83,16 @@ DriverError DummyDriver::erase(void) {
|
||||
}
|
||||
|
||||
DriverError DummyDriver::setDataKey(const uint8_t *key) {
|
||||
// Update the data key stored in the dump.
|
||||
__builtin_memcpy(_dump.dataKey, key, sizeof(_dump.dataKey));
|
||||
return NO_ERROR;
|
||||
if (!__builtin_memcmp(
|
||||
_dump.dataKey, _privateDump.dataKey, sizeof(_dump.dataKey)
|
||||
)) {
|
||||
_privateDump.copyKeyFrom(key);
|
||||
|
||||
_dump.copyKeyFrom(key);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
return _getErrorCode();
|
||||
}
|
||||
|
||||
/* Functions common to all cartridge drivers */
|
||||
@ -290,6 +306,8 @@ DriverError X76F041Driver::erase(void) {
|
||||
return error;
|
||||
|
||||
io::i2cStopWithCS(_X76_WRITE_DELAY);
|
||||
|
||||
_dump.clearKey();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@ -312,8 +330,7 @@ DriverError X76F041Driver::setDataKey(const uint8_t *key) {
|
||||
|
||||
io::i2cStopWithCS(_X76_WRITE_DELAY);
|
||||
|
||||
// Update the data key stored in the dump.
|
||||
__builtin_memcpy(_dump.dataKey, key, sizeof(_dump.dataKey));
|
||||
_dump.copyKeyFrom(key);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@ -508,7 +525,12 @@ DriverError ZS01Driver::erase(void) {
|
||||
request.address = zs01::ADDR_ERASE;
|
||||
request.encodeWriteRequest(key, _encoderState);
|
||||
|
||||
return _transact(request, response);
|
||||
DriverError error = _transact(request, response);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
_dump.clearKey();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
DriverError ZS01Driver::setDataKey(const uint8_t *key) {
|
||||
@ -525,8 +547,7 @@ DriverError ZS01Driver::setDataKey(const uint8_t *key) {
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
// Update the data key stored in the dump.
|
||||
__builtin_memcpy(_dump.dataKey, key, sizeof(_dump.dataKey));
|
||||
_dump.copyKeyFrom(key);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
|
@ -51,8 +51,7 @@ private:
|
||||
public:
|
||||
inline DummyDriver(Dump &dump)
|
||||
: Driver(dump), _privateDump(dump) {
|
||||
_dump.flags = _privateDump.flags &
|
||||
(DUMP_HAS_SYSTEM_ID | DUMP_HAS_CART_ID);
|
||||
dump.flags &= DUMP_HAS_SYSTEM_ID | DUMP_HAS_CART_ID;
|
||||
}
|
||||
|
||||
DriverError readSystemID(void);
|
||||
@ -70,7 +69,9 @@ class CartDriver : public Driver {
|
||||
public:
|
||||
inline CartDriver(Dump &dump, ChipType chipType = NONE, uint8_t flags = 0)
|
||||
: Driver(dump) {
|
||||
dump.clear();
|
||||
dump.clearIdentifiers();
|
||||
dump.clearKey();
|
||||
dump.clearData();
|
||||
|
||||
dump.chipType = chipType;
|
||||
dump.flags = flags;
|
||||
|
17
src/gpu.cpp
17
src/gpu.cpp
@ -442,19 +442,26 @@ static void _loadQRCode(Image &output, int x, int y, const uint32_t *qrCode) {
|
||||
const uint32_t palette[8]{ 0x8000ffff };
|
||||
|
||||
rect.x = x;
|
||||
rect.y = y + size;
|
||||
rect.y = y + size + 2;
|
||||
rect.w = 16;
|
||||
rect.h = 1;
|
||||
upload(rect, palette, true);
|
||||
|
||||
rect.y = y;
|
||||
// Leave one pixel of margin on all sides as a workaround for GPU polygon
|
||||
// scaling artifacts.
|
||||
rect.x = x + 1;
|
||||
rect.y = y + 1;
|
||||
rect.w = qrcodegen_getStride(qrCode) * 2;
|
||||
rect.h = size;
|
||||
upload(rect, &qrCode[1], true);
|
||||
|
||||
output.initFromVRAMRect(rect, GP0_COLOR_4BPP);
|
||||
output.width = size;
|
||||
output.palette = gp0_clut(x / 16, y + size);
|
||||
output.u = (x & 0x3f) * 4 + 3;
|
||||
output.v = y & 0xff;
|
||||
output.width = size + 1;
|
||||
output.height = size + 1;
|
||||
output.texpage =
|
||||
gp0_page(x / 64, y / 256, GP0_BLEND_SEMITRANS, GP0_COLOR_4BPP);
|
||||
output.palette = gp0_clut(x / 16, y + size + 2);
|
||||
|
||||
LOG("loaded at (%d,%d), size=%d", x, y, size);
|
||||
}
|
||||
|
@ -18,20 +18,18 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct _JumpBuffer {
|
||||
typedef struct {
|
||||
uint32_t ra;
|
||||
uint32_t s0, s1, s2, s3, s4, s5, s6, s7;
|
||||
uint32_t gp, sp, fp;
|
||||
} JumpBuffer;
|
||||
|
||||
typedef JumpBuffer *jmp_buf;
|
||||
} jmp_buf;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int setjmp(jmp_buf env);
|
||||
void longjmp(jmp_buf env, int status);
|
||||
int setjmp(jmp_buf *env);
|
||||
void longjmp(jmp_buf *env, int status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -39,6 +39,9 @@ private:
|
||||
|
||||
protected:
|
||||
inline void _setProgress(Context &ctx, int part, int total) {
|
||||
if (!total)
|
||||
total = 1;
|
||||
|
||||
int totalWidth = _width - MODAL_PADDING * 2;
|
||||
int partWidth = (totalWidth * part) / total;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user