From 25f5f67840da9f0526c8c8c0e85549e2acc2175f Mon Sep 17 00:00:00 2001 From: spicyjpeg Date: Mon, 26 Jun 2023 08:39:50 +0200 Subject: [PATCH] More cart identification bugfixes --- assets/app.strings.json | 12 ++-- src/app/app.cpp | 136 ++++++++++++++++++++++++++-------------- src/app/app.hpp | 20 +++--- src/app/cartactions.cpp | 8 +-- src/app/cartunlock.cpp | 35 +++++++++-- src/cart.cpp | 21 +++++++ src/cart.hpp | 14 ++++- src/cartdata.cpp | 19 ++++-- src/cartio.cpp | 10 ++- src/uibase.hpp | 9 +-- src/uicommon.cpp | 4 +- src/zs01.cpp | 12 ++-- 12 files changed, 211 insertions(+), 89 deletions(-) diff --git a/assets/app.strings.json b/assets/app.strings.json index 6c9be1b..76e1816 100644 --- a/assets/app.strings.json +++ b/assets/app.strings.json @@ -7,7 +7,7 @@ "identifyGame": "Attempting to identify game..." }, "cartEraseWorker": { - "erase": "Performing cartridge erase...", + "erase": "Erasing cartridge...", "error": "An error occurred while erasing the cartridge's EEPROM. The unlocking key may or may not have been successfully changed.\n\nPress the Test button to view debug logs." }, "cartReflashWorker": { @@ -96,7 +96,7 @@ "CartInfoScreen": { "title": "{CART_ICON} Cartridge information", "digitalIOInfo": "Digital I/O ID:\t%s\nDigital I/O SN:\t%s\n\n", - "cartInfo": "Cartridge type:\t%s\nUnlock status:\t%s\nDS2401 identifier:\t%s\nZS01 identifier:\t%s\n\n", + "cartInfo": "Cartridge type:\t%s\nUnlock status:\t%s\nDS2401 identifier:\t%s\nZS01 identifier:\t%s\nConfiguration:\t%s\n\n", "id": { "error": "read failure", @@ -104,13 +104,17 @@ "noCartID": "cartridge has no DS2401", "noZSID": "not a ZS01 cartridge" }, + "config": { + "error": "read failure", + "locked": "unlock required" + }, "unlockStatus": { "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", + "unknown": "Unlock required 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)" @@ -201,7 +205,7 @@ "UnlockKeyScreen": { "title": "{CART_ICON} Select unlocking key", - "prompt": "If the cartridge has been converted before, select the game it was last converted to.", + "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 confirm, hold {LEFT_BUTTON} + {RIGHT_BUTTON} to go back", "autoUnlock": "Use key from identified game (recommended)", diff --git a/src/app/app.cpp b/src/app/app.cpp index f009b3d..0472226 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -28,11 +28,11 @@ void App::_unloadCartData(void) { _dump.clearIdentifiers(); _dump.clearData(); - _identified = nullptr; - _db.destroy(); + _identified = nullptr; + //_selectedEntry = nullptr; } -void App::_setupWorker(void (App::*func)(void)) { +void App::_setupWorker(bool (App::*func)(void)) { LOG("restarting worker, func=0x%08x", func); auto mask = setInterruptMask(0); @@ -66,7 +66,7 @@ static const char *const _CARTDB_PATHS[cart::NUM_CHIP_TYPES]{ "data/zs01.cartdb" }; -void App::_cartDetectWorker(void) { +bool App::_cartDetectWorker(void) { _workerStatus.setNextScreen(_cartInfoScreen); _workerStatus.update(0, 4, WSTR("App.cartDetectWorker.identifyCart")); _unloadCartData(); @@ -105,9 +105,13 @@ void App::_cartDetectWorker(void) { LOG("cart parser @ 0x%08x", _parser); _workerStatus.update(2, 4, WSTR("App.cartDetectWorker.identifyGame")); - if (!_resourceProvider->loadData(_db, _CARTDB_PATHS[_dump.chipType])) { - LOG("%s not found", _CARTDB_PATHS[_dump.chipType]); - goto _cartInitDone; + if (!_db.ptr) { + if (!_resourceProvider->loadData( + _db, _CARTDB_PATHS[_dump.chipType]) + ) { + LOG("%s not found", _CARTDB_PATHS[_dump.chipType]); + goto _cartInitDone; + } } char code[8], region[8]; @@ -116,6 +120,17 @@ void App::_cartDetectWorker(void) { goto _cartInitDone; if (_parser->getCode(code) && _parser->getRegion(region)) _identified = _db.lookup(code, region); + if (!_identified) + goto _cartInitDone; + + // Force the parser to use correct format for the game (to prevent + // ambiguity between different formats). + delete _parser; + _parser = cart::newCartParser( + _dump, _identified->formatType, _identified->flags + ); + + LOG("new cart parser @ 0x%08x", _parser); } _cartInitDone: @@ -127,7 +142,7 @@ _cartInitDone: if (!_resourceProvider->loadData(bitstream, "data/fpga.bit")) { LOG("bitstream unavailable"); - return; + return true; } ready = io::loadBitstream(bitstream.as(), bitstream.length); @@ -135,7 +150,7 @@ _cartInitDone: if (!ready) { LOG("bitstream upload failed"); - return; + return true; } delayMicroseconds(5000); // Probably not necessary @@ -148,9 +163,11 @@ _cartInitDone: if (error) LOG("system ID error, code=%d", error); + + return true; } -void App::_cartUnlockWorker(void) { +bool App::_cartUnlockWorker(void) { _workerStatus.setNextScreen(_cartInfoScreen, true); _workerStatus.update(0, 2, WSTR("App.cartUnlockWorker.read")); @@ -163,7 +180,7 @@ void App::_cartUnlockWorker(void) { _cartInfoScreen, WSTR("App.cartUnlockWorker.error") );*/ _workerStatus.setNextScreen(_errorScreen); - return; + return false; } if (_parser) @@ -172,7 +189,7 @@ void App::_cartUnlockWorker(void) { _parser = cart::newCartParser(_dump); if (!_parser) - return; + return true; LOG("cart parser @ 0x%08x", _parser); _workerStatus.update(1, 2, WSTR("App.cartUnlockWorker.identifyGame")); @@ -181,9 +198,28 @@ void App::_cartUnlockWorker(void) { if (_parser->getCode(code) && _parser->getRegion(region)) _identified = _db.lookup(code, region); + + // If auto-identification failed (e.g. because the format has no game code), + // use the game whose unlocking key was selected as a hint. + if (!_identified) { + if (_selectedEntry) { + LOG("identify failed, using key as hint"); + _identified = _selectedEntry; + } else { + return true; + } + } + + delete _parser; + _parser = cart::newCartParser( + _dump, _identified->formatType, _identified->flags + ); + + LOG("new cart parser @ 0x%08x", _parser); + return true; } -void App::_qrCodeWorker(void) { +bool App::_qrCodeWorker(void) { char qrString[cart::MAX_QR_STRING_LENGTH]; _workerStatus.setNextScreen(_qrCodeScreen); @@ -192,9 +228,11 @@ void App::_qrCodeWorker(void) { _workerStatus.update(1, 2, WSTR("App.qrCodeWorker.generate")); _qrCodeScreen.generateCode(qrString); + + return true; } -void App::_hddDumpWorker(void) { +bool App::_hddDumpWorker(void) { _workerStatus.update(0, 1, WSTR("App.hddDumpWorker.save")); char code[8], region[8], path[32]; @@ -211,24 +249,24 @@ void App::_hddDumpWorker(void) { _cartInfoScreen, WSTR("App.hddDumpWorker.error") ); _workerStatus.setNextScreen(_errorScreen); - return; + return false; } _workerStatus.setNextScreen(_cartInfoScreen); + return true; } -void App::_cartWriteWorker(void) { +bool App::_cartWriteWorker(void) { _workerStatus.update(0, 1, WSTR("App.cartWriteWorker.write")); - auto error = _driver->writeData(); + uint8_t key[8]; + auto error = _driver->writeData(); + + if (!error) + _identified->copyKeyTo(key); _cartDetectWorker(); - if (!error && _identified) { - _identified->copyKeyTo(_dump.dataKey); - _cartUnlockWorker(); - } - if (error) { LOG("write error, code=%d", error); @@ -236,60 +274,63 @@ void App::_cartWriteWorker(void) { _cartInfoScreen, WSTR("App.cartWriteWorker.error") ); _workerStatus.setNextScreen(_errorScreen); + return false; } + + _dump.copyKeyFrom(key); + return _cartUnlockWorker(); } -void App::_cartReflashWorker(void) { - _workerStatus.update(0, 1, WSTR("App.cartWriteWorker.flash")); +bool App::_cartReflashWorker(void) { + if (!_cartEraseWorker()) + return false; + + _workerStatus.update(1, 2, WSTR("App.cartReflashWorker.flash")); if (_parser) delete _parser; _parser = cart::newCartParser( - _dump, _reflashEntry->formatType, _reflashEntry->flags + _dump, _selectedEntry->formatType, _selectedEntry->flags ); auto pri = _parser->getIdentifiers(); auto pub = _parser->getPublicIdentifiers(); _dump.clearData(); + _dump.initConfig(9, _selectedEntry->flags & cart::DATA_HAS_PUBLIC_SECTION); if (pri) { - if (_reflashEntry->flags & cart::DATA_HAS_CART_ID) + if (_selectedEntry->flags & cart::DATA_HAS_CART_ID) pri->cartID.copyFrom(_dump.cartID.data); - if (_reflashEntry->flags & cart::DATA_HAS_TRACE_ID) + if (_selectedEntry->flags & cart::DATA_HAS_TRACE_ID) pri->updateTraceID( - _reflashEntry->traceIDType, _reflashEntry->traceIDParam + _selectedEntry->traceIDType, _selectedEntry->traceIDParam ); - if (_reflashEntry->flags & cart::DATA_HAS_INSTALL_ID) { + if (_selectedEntry->flags & cart::DATA_HAS_INSTALL_ID) { // The private installation ID seems to be unused on carts with a // public data section. if (pub) - pub->setInstallID(_reflashEntry->installIDPrefix); + pub->setInstallID(_selectedEntry->installIDPrefix); else - pri->setInstallID(_reflashEntry->installIDPrefix); + pri->setInstallID(_selectedEntry->installIDPrefix); } } - _parser->setCode(_reflashEntry->code); - _parser->setRegion(_reflashEntry->region); - _parser->setYear(_reflashEntry->year); + _parser->setCode(_selectedEntry->code); + _parser->setRegion(_selectedEntry->region); + _parser->setYear(_selectedEntry->year); _parser->flush(); uint8_t key[8]; auto error = _driver->writeData(); if (!error) { - _reflashEntry->copyKeyTo(key); + _selectedEntry->copyKeyTo(key); error = _driver->setDataKey(key); } _cartDetectWorker(); - if (!error) { - _dump.copyKeyFrom(key); - _cartUnlockWorker(); - } - if (error) { LOG("write error, code=%d", error); @@ -297,21 +338,20 @@ void App::_cartReflashWorker(void) { _cartInfoScreen, WSTR("App.cartReflashWorker.error") ); _workerStatus.setNextScreen(_errorScreen); + return false; } + + _dump.copyKeyFrom(key); + return _cartUnlockWorker(); } -void App::_cartEraseWorker(void) { +bool App::_cartEraseWorker(void) { _workerStatus.update(0, 1, WSTR("App.cartEraseWorker.erase")); auto error = _driver->erase(); _cartDetectWorker(); - if (!error) { - _dump.clearKey(); - _cartUnlockWorker(); - } - if (error) { LOG("erase error, code=%d", error); @@ -319,7 +359,11 @@ void App::_cartEraseWorker(void) { _cartInfoScreen, WSTR("App.cartEraseWorker.error") ); _workerStatus.setNextScreen(_errorScreen); + return false; } + + _dump.clearKey(); + return _cartUnlockWorker(); } /* Misc. functions */ diff --git a/src/app/app.hpp b/src/app/app.hpp index 07a1313..27d86de 100644 --- a/src/app/app.hpp +++ b/src/app/app.hpp @@ -122,24 +122,24 @@ private: cart::CartDB _db; Thread _workerThread; WorkerStatus _workerStatus; - void (App::*_workerFunction)(void); + bool (App::*_workerFunction)(void); uint8_t *_workerStack; cart::Driver *_driver; cart::Parser *_parser; - const cart::DBEntry *_identified, *_reflashEntry; + const cart::DBEntry *_identified, *_selectedEntry; void _unloadCartData(void); - void _setupWorker(void (App::*func)(void)); + void _setupWorker(bool (App::*func)(void)); void _setupInterrupts(void); - void _cartDetectWorker(void); - void _cartUnlockWorker(void); - void _qrCodeWorker(void); - void _hddDumpWorker(void); - void _cartWriteWorker(void); - void _cartReflashWorker(void); - void _cartEraseWorker(void); + bool _cartDetectWorker(void); + bool _cartUnlockWorker(void); + bool _qrCodeWorker(void); + bool _hddDumpWorker(void); + bool _cartWriteWorker(void); + bool _cartReflashWorker(void); + bool _cartEraseWorker(void); void _worker(void); void _interruptHandler(void); diff --git a/src/app/cartactions.cpp b/src/app/cartactions.cpp index 6307eba..d2dd3e2 100644 --- a/src/app/cartactions.cpp +++ b/src/app/cartactions.cpp @@ -163,8 +163,8 @@ void CartActionsScreen::show(ui::Context &ctx, bool goBack) { _listLength = _NUM_NO_SYSTEM_ID_ACTIONS; - if (APP->_identified) { - if (APP->_identified->flags & cart::DATA_HAS_SYSTEM_ID) + if (APP->_parser) { + if (APP->_parser->flags & cart::DATA_HAS_SYSTEM_ID) _listLength = _NUM_SYSTEM_ID_ACTIONS; } @@ -214,7 +214,7 @@ void HexdumpScreen::show(ui::Context &ctx, bool goBack) { char *ptr = _bodyText, *end = &_bodyText[sizeof(_bodyText)]; for (size_t i = 0; i < length; i += 16) { - ptr += snprintf(ptr, end - ptr, "%04x: ", i); + ptr += snprintf(ptr, end - ptr, "%04X: ", i); ptr += util::hexToString(ptr, &APP->_dump.data[i], 16, ' '); *(ptr++) = '\n'; @@ -258,7 +258,7 @@ void ReflashGameScreen::update(ui::Context &ctx) { STR("CartActionsScreen.reflash.confirm") ); - APP->_reflashEntry = APP->_db.get(_activeItem); + APP->_selectedEntry = APP->_db.get(_activeItem); ctx.show(APP->_confirmScreen, false, true); } else if ( (ctx.buttons.held(ui::BTN_LEFT) && ctx.buttons.pressed(ui::BTN_RIGHT)) || diff --git a/src/app/cartunlock.cpp b/src/app/cartunlock.cpp index ba39bbd..7e44e0a 100644 --- a/src/app/cartunlock.cpp +++ b/src/app/cartunlock.cpp @@ -62,7 +62,7 @@ void CartInfoScreen::show(ui::Context &ctx, bool goBack) { auto &dump = APP->_dump; - char id1[32], id2[32]; + char id1[32], id2[32], config[32]; char *ptr = _bodyText, *end = &_bodyText[sizeof(_bodyText)]; // Digital I/O board info @@ -113,25 +113,36 @@ void CartInfoScreen::show(ui::Context &ctx, bool goBack) { else __builtin_strcpy(id2, STR("CartInfoScreen.id.noZSID")); + if (dump.flags & cart::DUMP_CONFIG_OK) + util::hexToString(config, dump.config, sizeof(dump.config), '-'); + else if (dump.flags & cart::DUMP_PRIVATE_DATA_OK) + __builtin_strcpy(config, STR("CartInfoScreen.config.error")); + else + __builtin_strcpy(config, STR("CartInfoScreen.config.locked")); + auto unlockStatus = (dump.flags & cart::DUMP_PRIVATE_DATA_OK) ? STR("CartInfoScreen.unlockStatus.unlocked") : STR("CartInfoScreen.unlockStatus.locked"); ptr += snprintf( ptr, end - ptr, STR("CartInfoScreen.cartInfo"), - STRH(_CART_TYPES[dump.chipType].name), unlockStatus, id1, id2 + STRH(_CART_TYPES[dump.chipType].name), unlockStatus, id1, id2, config ); - // At this point the cartridge can be in one of 6 states: + // At this point the cartridge can be in one of 8 states: // - locked, identified // => unlock required, auto unlock available - // - locked, unidentified + // - locked, parsed but unidentified + // => unlock required + // - locked, parsing failed // => unlock required // - locked, blank or no public data // => unlock required // - unlocked, identified // => all actions available - // - unlocked, no private data, unidentified + // - unlocked, no private data, parsed but unidentified + // => all actions available (not implemented yet) + // - unlocked, no private data, parsing failed // => only dumping/flashing available // - unlocked, no private data, blank // => only dumping/flashing available @@ -170,7 +181,9 @@ void CartInfoScreen::show(ui::Context &ctx, bool goBack) { STR("CartInfoScreen.pairing.otherSystem"), id1, id2 ); } - } else if (dump.flags & cart::DUMP_PUBLIC_DATA_OK) { + } else if ( + dump.flags & (cart::DUMP_PUBLIC_DATA_OK | cart::DUMP_PRIVATE_DATA_OK) + ) { state = APP->_dump.isReadableDataEmpty() ? BLANK_CART : UNIDENTIFIED; } else { state = UNKNOWN; @@ -258,10 +271,14 @@ void UnlockKeyScreen::autoUnlock(ui::Context &ctx) { APP->_dump.dataKey, APP->_identified->dataKey, sizeof(APP->_dump.dataKey) ); + + //APP->_selectedEntry = APP->_identified; + APP->_selectedEntry = nullptr; ctx.show(APP->_confirmScreen, false, true); } void UnlockKeyScreen::useCustomKey(ui::Context &ctx) { + APP->_selectedEntry = nullptr; ctx.show(APP->_keyEntryScreen, false, true); } @@ -269,6 +286,8 @@ void UnlockKeyScreen::use00Key(ui::Context &ctx) { __builtin_memset( APP->_dump.dataKey, 0x00, sizeof(APP->_dump.dataKey) ); + + APP->_selectedEntry = nullptr; ctx.show(APP->_confirmScreen, false, true); } @@ -276,6 +295,8 @@ void UnlockKeyScreen::useFFKey(ui::Context &ctx) { __builtin_memset( APP->_dump.dataKey, 0xff, sizeof(APP->_dump.dataKey) ); + + APP->_selectedEntry = nullptr; ctx.show(APP->_confirmScreen, false, true); } @@ -316,6 +337,8 @@ void UnlockKeyScreen::update(ui::Context &ctx) { APP->_dump.dataKey, APP->_db.get(index)->dataKey, sizeof(APP->_dump.dataKey) ); + + APP->_selectedEntry = APP->_db.get(index); ctx.show(APP->_confirmScreen, false, true); } } else if ( diff --git a/src/cart.cpp b/src/cart.cpp index 3ceb55b..c44ace9 100644 --- a/src/cart.cpp +++ b/src/cart.cpp @@ -176,6 +176,27 @@ const ChipSize CHIP_SIZES[NUM_CHIP_TYPES]{ { .dataLength = 112, .publicDataOffset = 0, .publicDataLength = 32 } }; +void Dump::initConfig(uint8_t maxAttempts, bool hasPublicSection) { + clearConfig(); + + switch (chipType) { + case X76F041: + config[0] = 0xff; + config[1] = hasPublicSection ? 0xaf : 0xff; + config[2] = 0x20; // Disable retry counter + config[3] = maxAttempts; + break; + + case ZS01: + //assert(hasPublicSection); + config[4] = maxAttempts; + break; + + default: + break; + } +} + bool Dump::isPublicDataEmpty(void) const { if (!(flags & DUMP_PUBLIC_DATA_OK)) return false; diff --git a/src/cart.hpp b/src/cart.hpp index f3f84e2..59dbcc3 100644 --- a/src/cart.hpp +++ b/src/cart.hpp @@ -171,7 +171,9 @@ public: return (sizeof(Dump) - sizeof(data)) + getChipSize().dataLength; } inline void clearIdentifiers(void) { - __builtin_memset(&systemID, 0, sizeof(Identifier) * 3); + systemID.clear(); + cartID.clear(); + zsID.clear(); } inline void copyDataFrom(const uint8_t *source) { __builtin_memcpy(data, source, getChipSize().dataLength); @@ -191,7 +193,17 @@ public: inline void clearKey(void) { __builtin_memset(dataKey, 0, sizeof(dataKey)); } + inline void copyConfigFrom(const uint8_t *source) { + __builtin_memcpy(config, source, sizeof(config)); + } + inline void copyConfigTo(uint8_t *dest) const { + __builtin_memcpy(dest, config, sizeof(config)); + } + inline void clearConfig(void) { + __builtin_memset(config, 0, sizeof(config)); + } + void initConfig(uint8_t maxAttempts, bool hasPublicSection = false); bool isPublicDataEmpty(void) const; bool isDataEmpty(void) const; bool isReadableDataEmpty(void) const; diff --git a/src/cartdata.cpp b/src/cartdata.cpp index 9912e0e..cab5d59 100644 --- a/src/cartdata.cpp +++ b/src/cartdata.cpp @@ -117,7 +117,7 @@ void ExtendedParser::setCode(const char *input) { __builtin_strncpy(header->code, input, sizeof(header->code)); if (flags & DATA_GX706_WORKAROUND) - header->region[1] = 'E'; + header->code[1] = 'E'; } size_t ExtendedParser::getRegion(char *output) const { @@ -172,7 +172,16 @@ void ExtendedParser::flush(void) { //pub->installID.copyFrom(pri->installID.data); pub->systemID.copyFrom(pri->systemID.data); - _getHeader()->updateChecksum(flags & DATA_CHECKSUM_INVERTED); + auto header = _getHeader(); + char code = header->code[1]; + + if (flags & DATA_GX706_WORKAROUND) + header->code[1] = 'X'; + + header->updateChecksum(flags & DATA_CHECKSUM_INVERTED); + + if (flags & DATA_GX706_WORKAROUND) + header->code[1] = code; } bool ExtendedParser::validate(void) { @@ -180,15 +189,15 @@ bool ExtendedParser::validate(void) { return false; auto header = _getHeader(); - char region = header->region[1]; + char code = header->code[1]; if (flags & DATA_GX706_WORKAROUND) - header->region[1] = 'X'; + header->code[1] = 'X'; bool valid = header->validateChecksum(flags & DATA_CHECKSUM_INVERTED); if (flags & DATA_GX706_WORKAROUND) - header->region[1] = region; + header->code[1] = code; return valid; } diff --git a/src/cartio.cpp b/src/cartio.cpp index c260862..e19018b 100644 --- a/src/cartio.cpp +++ b/src/cartio.cpp @@ -45,6 +45,9 @@ DriverError DummyDriver::readCartID(void) { } DriverError DummyDriver::readPublicData(void) { + if (_dummyDump.chipType != ZS01) + return UNSUPPORTED_OP; + if (_dummyDump.flags & DUMP_PUBLIC_DATA_OK) { _dump.copyDataFrom(_dummyDump.data); _dump.flags |= DUMP_PUBLIC_DATA_OK; @@ -59,7 +62,8 @@ DriverError DummyDriver::readPrivateData(void) { _dump.dataKey, _dummyDump.dataKey, sizeof(_dump.dataKey) )) { _dump.copyDataFrom(_dummyDump.data); - _dump.flags |= DUMP_PRIVATE_DATA_OK; + _dump.copyConfigFrom(_dummyDump.config); + _dump.flags |= DUMP_PRIVATE_DATA_OK | DUMP_CONFIG_OK; return NO_ERROR; } @@ -411,8 +415,8 @@ DriverError ZS01Driver::_transact( LOG("D: %s", buffer); #endif - //if (!ok) - //return ZS01_CRC_MISMATCH; + if (!ok) + return ZS01_CRC_MISMATCH; _encoderState = response.address; diff --git a/src/uibase.hpp b/src/uibase.hpp index 1da2daa..54bed11 100644 --- a/src/uibase.hpp +++ b/src/uibase.hpp @@ -48,10 +48,11 @@ enum AnimationSpeed { SPEED_SLOW = 20 }; -static constexpr int SCREEN_MARGIN_X = 16; -static constexpr int SCREEN_MARGIN_Y = 20; -static constexpr int SCREEN_BLOCK_MARGIN = 6; -static constexpr int SCREEN_PROMPT_HEIGHT = 30; +static constexpr int SCREEN_MARGIN_X = 16; +static constexpr int SCREEN_MARGIN_Y = 20; +static constexpr int SCREEN_BLOCK_MARGIN = 6; +static constexpr int SCREEN_PROMPT_HEIGHT = 30; +static constexpr int SCREEN_PROMPT_HEIGHT_MIN = 10; static constexpr int LIST_BOX_PADDING = 4; static constexpr int LIST_ITEM_PADDING = 2; diff --git a/src/uicommon.cpp b/src/uicommon.cpp index 4158693..8107bbf 100644 --- a/src/uicommon.cpp +++ b/src/uicommon.cpp @@ -288,10 +288,10 @@ void TextScreen::draw(Context &ctx, bool active) const { ctx.font.draw(ctx.gpuCtx, _title, rect, COLOR_TITLE); rect.y1 = gpu::FONT_LINE_HEIGHT + SCREEN_BLOCK_MARGIN; - rect.y2 = screenHeight - SCREEN_PROMPT_HEIGHT; + rect.y2 = screenHeight - SCREEN_PROMPT_HEIGHT_MIN; ctx.font.draw(ctx.gpuCtx, _body, rect, COLOR_TEXT1, true); - rect.y1 = screenHeight - SCREEN_PROMPT_HEIGHT; + rect.y1 = screenHeight - SCREEN_PROMPT_HEIGHT_MIN; rect.y2 = screenHeight; ctx.font.draw(ctx.gpuCtx, _prompt, rect, COLOR_TEXT1, true); } diff --git a/src/zs01.cpp b/src/zs01.cpp index 4897641..96bf8d4 100644 --- a/src/zs01.cpp +++ b/src/zs01.cpp @@ -18,10 +18,8 @@ static const Key _COMMAND_KEY{ // Konami's driver generates a pseudorandom key for each transaction, but it can // be a fixed key as well. static const Key _RESPONSE_KEY{ - .add = { 237, 8, 16, 11, 6, 4, 8, 30 }, - .shift = { 0, 3, 2, 2, 6, 2, 2, 1 } - //.add = { 0, 0, 0, 0, 0, 0, 0, 0 }, - //.shift = { 0, 0, 0, 0, 0, 0, 0, 0 } + .add = { 0, 0, 0, 0, 0, 0, 0, 0 }, + .shift = { 0, 0, 0, 0, 0, 0, 0, 0 } }; /* Packet encoding/decoding */ @@ -118,6 +116,8 @@ bool Packet::validateCRC(void) const { } void Packet::encodeReadRequest(void) { + LOG("addr=0x%02x, public", address); + command = REQ_READ; _RESPONSE_KEY.packInto(data); updateCRC(); @@ -126,6 +126,8 @@ void Packet::encodeReadRequest(void) { } void Packet::encodeReadRequest(Key &dataKey, uint8_t state) { + LOG("addr=0x%02x, private", address); + command = REQ_READ | REQ_USE_DATA_KEY; _RESPONSE_KEY.packInto(data); updateCRC(); @@ -135,6 +137,8 @@ void Packet::encodeReadRequest(Key &dataKey, uint8_t state) { } void Packet::encodeWriteRequest(Key &dataKey, uint8_t state) { + LOG("addr=0x%02x", address); + command = REQ_WRITE | REQ_USE_DATA_KEY; updateCRC();