mirror of
https://github.com/spicyjpeg/573in1.git
synced 2025-01-22 19:52:05 +01:00
Misc. tweaks to cart drivers, more logging
This commit is contained in:
parent
9da9db5838
commit
493387187d
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
10
src/cart.cpp
10
src/cart.cpp
@ -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();
|
||||
|
@ -173,6 +173,7 @@ public:
|
||||
|
||||
bool isPublicDataEmpty(void) const;
|
||||
bool isDataEmpty(void) const;
|
||||
bool isReadableDataEmpty(void) const;
|
||||
size_t toQRString(char *output) const;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
30
src/util.cpp
30
src/util.cpp
@ -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+-./:";
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user