Misc. tweaks to cart drivers, more logging

This commit is contained in:
spicyjpeg 2023-06-09 10:15:15 +02:00
parent 9da9db5838
commit 493387187d
No known key found for this signature in database
GPG Key ID: 5CC87404C01DF393
11 changed files with 126 additions and 67 deletions

View File

@ -16,7 +16,7 @@ public:
static constexpr int _NUM_IDENTIFIED_ACTIONS = 6;
static constexpr int _NUM_UNIDENTIFIED_ACTIONS = 4;
static const Action _IDENTIFIED_ACTIONS[]{
static const Action _ACTIONS[]{
{
.name = "CartActionsScreen.qrDump.name"_h,
.prompt = "CartActionsScreen.qrDump.prompt"_h,
@ -25,6 +25,14 @@ static const Action _IDENTIFIED_ACTIONS[]{
.name = "CartActionsScreen.hexdump.name"_h,
.prompt = "CartActionsScreen.hexdump.prompt"_h,
.target = &CartActionsScreen::hexdump
}, {
.name = "CartActionsScreen.reflash.name"_h,
.prompt = "CartActionsScreen.reflash.prompt"_h,
.target = &CartActionsScreen::reflash
}, {
.name = "CartActionsScreen.erase.name"_h,
.prompt = "CartActionsScreen.erase.prompt"_h,
.target = &CartActionsScreen::erase
}, {
.name = "CartActionsScreen.resetSystemID.name"_h,
.prompt = "CartActionsScreen.resetSystemID.prompt"_h,
@ -33,39 +41,11 @@ static const Action _IDENTIFIED_ACTIONS[]{
.name = "CartActionsScreen.editSystemID.name"_h,
.prompt = "CartActionsScreen.editSystemID.prompt"_h,
.target = &CartActionsScreen::editSystemID
}, {
.name = "CartActionsScreen.reflash.name"_h,
.prompt = "CartActionsScreen.reflash.prompt"_h,
.target = &CartActionsScreen::reflash
}, {
.name = "CartActionsScreen.erase.name"_h,
.prompt = "CartActionsScreen.erase.prompt"_h,
.target = &CartActionsScreen::erase
}
};
static const Action _UNIDENTIFIED_ACTIONS[]{
{
.name = "CartActionsScreen.qrDump.name"_h,
.prompt = "CartActionsScreen.qrDump.prompt"_h,
.target = &CartActionsScreen::qrDump
}, {
.name = "CartActionsScreen.hexdump.name"_h,
.prompt = "CartActionsScreen.hexdump.prompt"_h,
.target = &CartActionsScreen::hexdump
}, {
.name = "CartActionsScreen.reflash.name"_h,
.prompt = "CartActionsScreen.reflash.prompt"_h,
.target = &CartActionsScreen::reflash
}, {
.name = "CartActionsScreen.erase.name"_h,
.prompt = "CartActionsScreen.erase.prompt"_h,
.target = &CartActionsScreen::erase
}
};
const char *CartActionsScreen::_getItemName(ui::Context &ctx, int index) const {
return STRH(_IDENTIFIED_ACTIONS[index].name);
return STRH(_ACTIONS[index].name);
}
void CartActionsScreen::qrDump(ui::Context &ctx) {
@ -77,39 +57,34 @@ void CartActionsScreen::hexdump(ui::Context &ctx) {
//ctx.show(APP->_hexdumpScreen, false, true);
}
void CartActionsScreen::resetSystemID(ui::Context &ctx) {
}
void CartActionsScreen::editSystemID(ui::Context &ctx) {
}
void CartActionsScreen::reflash(ui::Context &ctx) {
}
void CartActionsScreen::erase(ui::Context &ctx) {
}
void CartActionsScreen::resetSystemID(ui::Context &ctx) {
}
void CartActionsScreen::editSystemID(ui::Context &ctx) {
}
void CartActionsScreen::show(ui::Context &ctx, bool goBack) {
_title = STR("CartActionsScreen.title");
_prompt = STRH(_ACTIONS[0].prompt);
_itemPrompt = STR("CartActionsScreen.itemPrompt");
if (APP->_identified) {
_prompt = STRH(_IDENTIFIED_ACTIONS[0].prompt);
_listLength = _NUM_IDENTIFIED_ACTIONS;
} else {
_prompt = STRH(_UNIDENTIFIED_ACTIONS[0].prompt);
_listLength = _NUM_UNIDENTIFIED_ACTIONS;
}
_listLength = 1;
/*_listLength = APP->_identified
? _NUM_IDENTIFIED_ACTIONS
: _NUM_UNIDENTIFIED_ACTIONS;*/
ListScreen::show(ctx, goBack);
}
void CartActionsScreen::update(ui::Context &ctx) {
auto &action = APP->_identified
? _IDENTIFIED_ACTIONS[_activeItem]
: _UNIDENTIFIED_ACTIONS[_activeItem];
_prompt = STRH(action.prompt);
auto &action = _ACTIONS[_activeItem];
_prompt = STRH(action.prompt);
ListScreen::update(ctx);

View File

@ -16,10 +16,10 @@ protected:
public:
void qrDump(ui::Context &ctx);
void hexdump(ui::Context &ctx);
void resetSystemID(ui::Context &ctx);
void editSystemID(ui::Context &ctx);
void reflash(ui::Context &ctx);
void erase(ui::Context &ctx);
void resetSystemID(ui::Context &ctx);
void editSystemID(ui::Context &ctx);
void show(ui::Context &ctx, bool goBack = false);
void update(ui::Context &ctx);

View File

@ -83,8 +83,6 @@ void App::_cartDetectWorker(void) {
_driver->readCartID();
if (!_driver->readPublicData())
_parser = cart::newCartParser(_dump);
if (!_parser)
goto _cartInitDone;
LOG("cart parser @ 0x%08x", _parser);
_workerStatus.update(2, 4, WSTR("App.cartDetectWorker.identifyGame"));
@ -96,6 +94,8 @@ void App::_cartDetectWorker(void) {
char code[8], region[8];
if (!_parser)
goto _cartInitDone;
if (_parser->getCode(code) && _parser->getRegion(region))
_identified = _db.lookup(code, region);
}

View File

@ -39,6 +39,7 @@ static const CartType _CART_TYPES[cart::NUM_CHIP_TYPES]{
enum IdentifyState {
UNIDENTIFIED = 0,
IDENTIFIED = 1,
UNKNOWN = 2,
BLANK_CART = 2
};
@ -84,7 +85,12 @@ void CartInfoScreen::show(ui::Context &ctx, bool goBack) {
_prompt = STR("CartInfoScreen.prompt.error");
return;
} else if (!(dump.flags & cart::DUMP_PUBLIC_DATA_OK)) {
}
if (
//dump.getChipSize().publicDataLength &&
(dump.chipType == cart::ZS01) &&
!(dump.flags & cart::DUMP_PUBLIC_DATA_OK)
) {
memccpy(ptr, STR("CartInfoScreen.description.initError"), 0, end - ptr);
_prompt = STR("CartInfoScreen.prompt.error");
@ -133,8 +139,10 @@ void CartInfoScreen::show(ui::Context &ctx, bool goBack) {
if (APP->_identified) {
state = IDENTIFIED;
APP->_identified->getDisplayName(name, sizeof(name));
} else if (dump.flags & cart::DUMP_PUBLIC_DATA_OK) {
state = APP->_dump.isReadableDataEmpty() ? BLANK_CART : UNIDENTIFIED;
} else {
state = APP->_dump.isDataEmpty() ? BLANK_CART : UNIDENTIFIED;
state = UNKNOWN;
}
if (dump.flags & cart::DUMP_PRIVATE_DATA_OK) {

View File

@ -170,6 +170,16 @@ bool Dump::isDataEmpty(void) const {
return (!sum || (sum == (0xff * length)));
}
bool Dump::isReadableDataEmpty(void) const {
// This is more or less a hack. The "right" way to tell if this chip has any
// public data would be to use getChipSize().publicDataLength, but many
// X76F041 carts don't actually have a public data area.
if (chipType == ZS01)
return isPublicDataEmpty();
else
return isDataEmpty();
}
size_t Dump::toQRString(char *output) const {
uint8_t compressed[MAX_QR_STRING_LENGTH];
size_t uncompLength = getDumpLength();

View File

@ -173,6 +173,7 @@ public:
bool isPublicDataEmpty(void) const;
bool isDataEmpty(void) const;
bool isReadableDataEmpty(void) const;
size_t toQRString(char *output) const;
};

View File

@ -219,7 +219,8 @@ Parser *newCartParser(Dump &dump, FormatType formatType, uint8_t flags) {
return new ExtendedParser(dump, flags);
default:
return new Parser(dump, flags);
//return new Parser(dump, flags);
return nullptr;
}
}

View File

@ -80,7 +80,8 @@ DriverError DummyDriver::setDataKey(const uint8_t *key) {
/* Functions common to all cartridge drivers */
static constexpr int _X76_MAX_ACK_POLLS = 5;
static constexpr int _X76_WRITE_DELAY = 10000;
static constexpr int _X76_WRITE_DELAY = 12000;
static constexpr int _X76_PACKET_DELAY = 12000;
static constexpr int _ZS01_PACKET_DELAY = 30000;
DriverError CartDriver::readSystemID(void) {
@ -138,19 +139,20 @@ DriverError X76Driver::readCartID(void) {
DriverError X76Driver::_x76Command(
uint8_t cmd, uint8_t param, uint8_t pollByte
) const {
delayMicroseconds(_X76_PACKET_DELAY);
io::i2cStartWithCS();
io::i2cWriteByte(cmd);
if (!io::i2cGetACK()) {
io::i2cStopWithCS();
LOG("NACK while sending command");
LOG("NACK while sending cmd=0x%02x", cmd);
return X76_NACK;
}
io::i2cWriteByte(param);
if (!io::i2cGetACK()) {
io::i2cStopWithCS();
LOG("NACK while sending parameter");
LOG("NACK while sending param=0x%02x", param);
return X76_NACK;
}
@ -160,6 +162,13 @@ DriverError X76Driver::_x76Command(
return X76_NACK;
}
#ifdef ENABLE_I2C_LOGGING
char buffer[32];
util::hexToString(buffer, _dump.dataKey, sizeof(_dump.dataKey), ' ');
LOG("S: %02X %02X %s", cmd, param, buffer);
#endif
for (int i = _X76_MAX_ACK_POLLS; i; i--) {
delayMicroseconds(_X76_WRITE_DELAY);
io::i2cStart();
@ -203,8 +212,9 @@ DriverError X76F041Driver::readPrivateData(void) {
io::i2cStart();
io::i2cWriteByte(i & 0xff);
if (io::i2cGetACK()) {
LOG("NACK after resending address");
if (!io::i2cGetACK()) {
io::i2cStopWithCS();
LOG("NACK after resending addr=0x%02x", i & 0xff);
return X76_NACK;
}
@ -218,10 +228,20 @@ DriverError X76F041Driver::readPrivateData(void) {
if (error)
return error;
// TODO: this may need another "secure read setup"...
io::i2cReadByte();
io::i2cStart();
io::i2cWriteByte(0);
if (!io::i2cGetACK()) {
io::i2cStopWithCS();
LOG("NACK after resending dummy byte");
return X76_NACK;
}
io::i2cReadBytes(_dump.config, 5);
io::i2cStopWithCS();
_dump.flags |= DUMP_PRIVATE_DATA_OK;
return NO_ERROR;
}
@ -235,6 +255,7 @@ DriverError X76F041Driver::writeData(void) {
return error;
if (!io::i2cWriteBytes(&_dump.data[i], 8)) {
io::i2cStopWithCS(_X76_WRITE_DELAY);
LOG("NACK while sending data bytes");
return X76_NACK;
}
@ -249,6 +270,7 @@ DriverError X76F041Driver::writeData(void) {
return error;
if (!io::i2cWriteBytes(_dump.config, 8)) {
io::i2cStopWithCS(_X76_WRITE_DELAY);
LOG("NACK while sending data bytes");
return X76_NACK;
}
@ -280,7 +302,7 @@ DriverError X76F041Driver::setDataKey(const uint8_t *key) {
// gets received correctly.
for (int i = 2; i; i--) {
if (!io::i2cWriteBytes(key, sizeof(_dump.dataKey))) {
io::i2cStopWithCS();
io::i2cStopWithCS(_X76_WRITE_DELAY);
LOG("NACK while setting new data key");
return X76_NACK;
}
@ -327,7 +349,14 @@ DriverError ZS01Driver::_transact(
zs01::Packet &request, zs01::Packet &response
) {
io::i2cStart();
#ifdef ENABLE_I2C_LOGGING
char buffer[32];
util::hexToString(buffer, &request.command, sizeof(zs01::Packet), ' ');
LOG("S: %s", buffer);
#endif
if (!io::i2cWriteBytes(
&request.command, sizeof(zs01::Packet), _ZS01_PACKET_DELAY
)) {
@ -339,9 +368,19 @@ DriverError ZS01Driver::_transact(
io::i2cReadBytes(&response.command, sizeof(zs01::Packet));
io::i2cStop();
#ifdef ENABLE_I2C_LOGGING
util::hexToString(buffer, &response.command, sizeof(zs01::Packet), ' ');
LOG("R: %s", buffer);
#endif
if (!response.decodeResponse())
return ZS01_CRC_MISMATCH;
#ifdef ENABLE_I2C_LOGGING
util::hexToString(buffer, &response.command, sizeof(zs01::Packet), ' ');
LOG("D: %s", buffer);
#endif
_encoderState = response.address;
if (response.command != zs01::RESP_NO_ERROR) {

View File

@ -108,7 +108,7 @@ uint16_t zsCRC16(const uint8_t *data, size_t length) {
/* String manipulation */
static const char HEX_CHARSET[] = "0123456789ABCDEF";
static const char _HEX_CHARSET[] = "0123456789ABCDEF";
size_t hexToString(char *output, const uint8_t *input, size_t length, char sep) {
size_t outLength = 0;
@ -116,8 +116,8 @@ size_t hexToString(char *output, const uint8_t *input, size_t length, char sep)
for (; length; length--) {
uint8_t value = *(input++);
*(output++) = HEX_CHARSET[value >> 4];
*(output++) = HEX_CHARSET[value & 0xf];
*(output++) = _HEX_CHARSET[value >> 4];
*(output++) = _HEX_CHARSET[value & 0xf];
if (sep && (length > 1)) {
*(output++) = sep;
@ -137,6 +137,30 @@ size_t serialNumberToString(char *output, const uint8_t *input) {
return sprintf(output, "%04d-%04d", (value / 10000) % 10000, value % 10000);
}
// This format is used by Konami's tools to display trace IDs in the TID_81
// format.
static const char _TRACE_ID_CHECKSUM_CHARSET[] = "0X987654321";
size_t traceIDToString(char *output, const uint8_t *input) {
uint16_t high = (input[0] << 8) | input[1];
uint32_t low = (input[2] << 24) | (input[3] << 16) | (input[4] << 8) | input[5];
size_t length = sprintf(&output[1], "%02d-%04d", high % 100, low % 10000);
// The checksum is calculated in a very weird way:
// code = AB-CDEF
// checksum = (A*7 + B*6 + C*5 + D*4 + E*3 + F*2) % 11
int checksum = 0, multiplier = 7;
for (const char *ptr = &output[1]; *ptr; ptr++) {
if (*ptr != '-')
checksum += (*ptr - '0') * (multiplier--);
}
output[0] = _TRACE_ID_CHECKSUM_CHARSET[checksum % 11];
return length + 1;
}
// This encoding is similar to standard base45, but with some problematic
// characters (' ', '$', '%', '*') excluded.
static const char _BASE41_CHARSET[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./:";

View File

@ -223,6 +223,7 @@ uint16_t zsCRC16(const uint8_t *data, size_t length);
size_t hexToString(char *output, const uint8_t *input, size_t length, char sep = 0);
size_t serialNumberToString(char *output, const uint8_t *input);
size_t traceIDToString(char *output, const uint8_t *input);
size_t encodeBase41(char *output, const uint8_t *input, size_t length);
}

View File

@ -108,7 +108,7 @@ bool Packet::validateCRC(void) const {
uint16_t value = util::zsCRC16(&command, sizeof(Packet) - sizeof(crc));
if (value != _crc) {
LOG("CRC mismatch, exp=0x%04x, got=0x%04x", value, _crc);
LOG("mismatch, exp=0x%04x, got=0x%04x", value, _crc);
return false;
}