From 3b781c00e6422bd4a8813e84962cf903686152df Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 11 Apr 2021 16:08:39 -0700 Subject: [PATCH] GBA e-Reader: Initial error detection and retrying --- include/mgba/internal/gba/cart/ereader.h | 3 +- src/gba/cart/ereader.c | 97 ++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 7 deletions(-) diff --git a/include/mgba/internal/gba/cart/ereader.h b/include/mgba/internal/gba/cart/ereader.h index 437a767de..b86924634 100644 --- a/include/mgba/internal/gba/cart/ereader.h +++ b/include/mgba/internal/gba/cart/ereader.h @@ -119,7 +119,8 @@ void EReaderScanFilterAnchors(struct EReaderScan*); void EReaderScanConnectAnchors(struct EReaderScan*); void EReaderScanCreateBlocks(struct EReaderScan*); void EReaderScanDetectBlockThreshold(struct EReaderScan*, int block); -bool EReaderScanScanBlock(struct EReaderScan*, int block); +bool EReaderScanRecalibrateBlock(struct EReaderScan*, int block); +bool EReaderScanScanBlock(struct EReaderScan*, int block, bool strict); CXX_GUARD_END diff --git a/src/gba/cart/ereader.c b/src/gba/cart/ereader.c index 63c522d1f..86085c86b 100644 --- a/src/gba/cart/ereader.c +++ b/src/gba/cart/ereader.c @@ -778,6 +778,12 @@ struct EReaderBlock { uint8_t min; uint8_t max; + unsigned errors; + unsigned missing; + unsigned extra; + + bool hFlip; + bool vFlip; bool dots[36 * 36]; uint16_t id; @@ -1277,11 +1283,40 @@ void EReaderScanDetectBlockThreshold(struct EReaderScan* scan, int blockId) { block->threshold = offset / 2; } -bool EReaderScanScanBlock(struct EReaderScan* scan, int blockId) { +bool EReaderScanRecalibrateBlock(struct EReaderScan* scan, int blockId) { if (blockId < 0 || (unsigned) blockId >= EReaderBlockListSize(&scan->blocks)) { return false; } struct EReaderBlock* block = EReaderBlockListGetPointer(&scan->blocks, blockId); + if (block->missing && block->extra) { + return false; + } + int errors = block->errors; + if (block->missing) { + while (errors > 0) { + errors -= block->histogram[block->threshold]; + while (!block->histogram[block->threshold] && block->threshold < 254) { + ++block->threshold; + } + ++block->threshold; + if (block->threshold >= 255) { + return false; + } + } + } else { + return false; + } + return true; +} + +bool EReaderScanScanBlock(struct EReaderScan* scan, int blockId, bool strict) { + if (blockId < 0 || (unsigned) blockId >= EReaderBlockListSize(&scan->blocks)) { + return false; + } + struct EReaderBlock* block = EReaderBlockListGetPointer(&scan->blocks, blockId); + block->errors = 0; + block->missing = 0; + block->extra = 0; bool dots[36 * 36] = {0}; size_t y; @@ -1301,26 +1336,65 @@ bool EReaderScanScanBlock(struct EReaderScan* scan, int blockId) { } int horizontal = 0; int vertical = 0; + int hMissing = 0; + int hExtra = 0; + int vMissing = 0; + int vExtra = 0; static const bool alignment[36] = { 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 }; int i; for (i = 3; i < 33; ++i) { - if (horizontal && dots[i] != alignment[i]) { + if (dots[i] != alignment[i]) { ++horizontal; + if (alignment[i]) { + ++hMissing; + } else { + ++hExtra; + } } if (dots[i + 36 * 35] != alignment[i]) { ++horizontal; + if (alignment[i]) { + ++hMissing; + } else { + ++hExtra; + } } - if (horizontal && dots[i * 36] != alignment[i]) { + if (dots[i * 36] != alignment[i]) { ++vertical; + if (alignment[i]) { + ++vMissing; + } else { + ++vExtra; + } } if (dots[i * 36 + 35] != alignment[i]) { ++vertical; + if (alignment[i]) { + ++vMissing; + } else { + ++vExtra; + } } } - if (!!horizontal == !!vertical) { + int errors; + if (horizontal < vertical) { + errors = horizontal; + block->errors += horizontal; + block->extra += hExtra; + block->missing += hMissing; + horizontal = 0; + } else { + errors = vertical; + block->errors += vertical; + block->extra += vExtra; + block->missing += vMissing; + vertical = 0; + } + if (strict && errors) { return false; } + int sector[2] = {0}; if (!vertical) { for (i = 5; i < 30; ++i) { @@ -1338,9 +1412,12 @@ bool EReaderScanScanBlock(struct EReaderScan* scan, int blockId) { int yFlip = 1; int xBias = 0; int yBias = 0; + block->hFlip = false; + block->vFlip = false; if ((sector[0] & 0x1FF) == 1) { yFlip = -1; yBias = 35; + block->vFlip = true; int s0 = 0; int s1 = 0; for (i = 0; i < 16; ++i) { @@ -1355,6 +1432,7 @@ bool EReaderScanScanBlock(struct EReaderScan* scan, int blockId) { if (sector[1] < sector[0]) { xFlip = -1; xBias = 35; + block->hFlip = true; int sector0 = sector[0]; sector[0] = sector[1]; sector[1] = sector0; @@ -1402,8 +1480,15 @@ bool EReaderScanCard(struct EReaderScan* scan) { size_t i; for (i = 0; i < blocks; ++i) { EReaderScanDetectBlockThreshold(scan, i); - if (!EReaderScanScanBlock(scan, i)) { - return false; + int errors = 36 * 36; + while (!EReaderScanScanBlock(scan, i, true)) { + if (errors < EReaderBlockListGetPointer(&scan->blocks, i)->errors) { + return false; + } + errors = EReaderBlockListGetPointer(&scan->blocks, i)->errors; + if (!EReaderScanRecalibrateBlock(scan, i)) { + return false; + } } } qsort(EReaderBlockListGetPointer(&scan->blocks, 0), EReaderBlockListSize(&scan->blocks), sizeof(struct EReaderBlock), _compareBlocks);