More cart identification bugfixes

This commit is contained in:
spicyjpeg 2023-06-26 08:39:50 +02:00
parent 912ecb8d8d
commit 25f5f67840
No known key found for this signature in database
GPG Key ID: 5CC87404C01DF393
12 changed files with 211 additions and 89 deletions

View File

@ -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)",

View File

@ -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<uint8_t>(), 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 */

View File

@ -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);

View File

@ -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)) ||

View File

@ -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 (

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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();