mirror of
https://github.com/sanni/cartreader.git
synced 2024-11-27 15:04:15 +01:00
V7.2 Alpha: Adds Coleco- and Intellivision (thx to skaman)
Untested and unfinished alpha version, will continue once I can get some cartridges.
This commit is contained in:
parent
ecfe42d5e4
commit
7b2d18c514
615
Cart_Reader/COLV.ino
Normal file
615
Cart_Reader/COLV.ino
Normal file
@ -0,0 +1,615 @@
|
||||
//******************************************
|
||||
// COLECOVISION MODULE
|
||||
//******************************************
|
||||
#ifdef enable_COLV
|
||||
|
||||
// Coleco Colecovision
|
||||
// Cartridge Pinout
|
||||
// 30P 2.54mm pitch connector
|
||||
//
|
||||
// FRONT SIDE BACK SIDE
|
||||
// (EVEN) (ODD)
|
||||
// +-------+
|
||||
// /C000 -| 2 1 |- D2
|
||||
// D3 -| 4 3 |- D1
|
||||
// D4 -| 6 5 |- D0
|
||||
// D5 -| 8 7 |- A0
|
||||
// D6 -| 10 9 |- A1
|
||||
// D7 -| 12 11 |- A2
|
||||
// A11 -| 14 13 |- GND (SHLD)
|
||||
// A10 -| 16 15 |- A3
|
||||
// /8000 -| 18 17 |- A4
|
||||
// A14 -| 20 19 |- A13
|
||||
// /A000 -| 22 21 |- A5
|
||||
// A12 -| 24 23 |- A6
|
||||
// A9 -| 26 25 |- A7
|
||||
// A8 -| 28 27 |- /E000
|
||||
// VCC(+5V) -| 30 29 |- GND
|
||||
// +-------+
|
||||
|
||||
// CONTROL PINS:
|
||||
// CHIP SELECT PINS
|
||||
// /8000(PH3) - CHIP 0 - SNES /CS
|
||||
// /A000(PH4) - CHIP 1 - SNES /IRQ
|
||||
// /C000(PH5) - CHIP 2 - SNES /WR
|
||||
// /E000(PH6) - CHIP 3 - SNES /RD
|
||||
|
||||
byte COL[] = {8, 12, 16, 20, 24, 32};
|
||||
byte collo = 0; // Lowest Entry
|
||||
byte colhi = 5; // Highest Entry
|
||||
|
||||
byte colsize;
|
||||
byte newcolsize;
|
||||
|
||||
// EEPROM MAPPING
|
||||
// 08 ROM SIZE
|
||||
|
||||
//******************************************
|
||||
// Menu
|
||||
//******************************************
|
||||
// Base Menu
|
||||
static const char colMenuItem1[] PROGMEM = "Select Cart";
|
||||
static const char colMenuItem2[] PROGMEM = "Read ROM";
|
||||
static const char colMenuItem3[] PROGMEM = "Set Size";
|
||||
static const char colMenuItem4[] PROGMEM = "Reset";
|
||||
static const char* const menuOptionsCOL[] PROGMEM = {colMenuItem1, colMenuItem2, colMenuItem3, colMenuItem4};
|
||||
|
||||
void setup_COL()
|
||||
{
|
||||
// Set Address Pins to Output
|
||||
// Colecovision uses A0-A14 [A15-A23 UNUSED]
|
||||
//A0-A7
|
||||
DDRF = 0xFF;
|
||||
//A8-A15
|
||||
DDRK = 0xFF;
|
||||
//A16-A23
|
||||
DDRL = 0xFF;
|
||||
|
||||
// Set Control Pins to Output
|
||||
// ---(PH0) ---(PH1) /8000(PH3) /A000(PH4) /C000(PH5) /E000(PH6)
|
||||
DDRH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||
|
||||
// Set TIME(PJ0) to Output (UNUSED)
|
||||
DDRJ |= (1 << 0);
|
||||
|
||||
// Set Pins (D0-D7) to Input
|
||||
DDRC = 0x00;
|
||||
|
||||
// Setting Control Pins to HIGH
|
||||
// ---(PH0) ---(PH1) /8000(PH3) /A000(PH4) /C000(PH5) /E000(PH6)
|
||||
PORTH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||
|
||||
// Set Unused Data Pins (PA0-PA7) to Output
|
||||
DDRA = 0xFF;
|
||||
|
||||
// Set Unused Pins HIGH
|
||||
PORTA = 0xFF;
|
||||
PORTL = 0xFF; // A16-A23
|
||||
PORTJ |= (1 << 0); // TIME(PJ0)
|
||||
|
||||
checkStatus_COL();
|
||||
strcpy(romName, "COLECO");
|
||||
|
||||
mode = mode_COL;
|
||||
}
|
||||
|
||||
void colMenu()
|
||||
{
|
||||
convertPgm(menuOptionsCOL, 4);
|
||||
uint8_t mainMenu = question_box(F("COLECOVISION MENU"), menuOptions, 4, 0);
|
||||
|
||||
switch (mainMenu)
|
||||
{
|
||||
case 0:
|
||||
// Select Cart
|
||||
setCart_COL();
|
||||
wait();
|
||||
setup_COL();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Read ROM
|
||||
sd.chdir("/");
|
||||
readROM_COL();
|
||||
sd.chdir("/");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Set Size
|
||||
setROMSize_COL();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// reset
|
||||
resetArduino();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//******************************************
|
||||
// READ CODE
|
||||
//******************************************
|
||||
// CHIP SELECT CONTROL PINS
|
||||
// /8000(PH3) - CHIP 0
|
||||
// /A000(PH4) - CHIP 1
|
||||
// /C000(PH5) - CHIP 2
|
||||
// /E000(PH6) - CHIP 3
|
||||
|
||||
uint8_t readData_COL(uint32_t addr)
|
||||
{
|
||||
// SELECT ROM CHIP - PULL /CE LOW
|
||||
uint8_t chipdecode = ((addr >> 13) & 0x3);
|
||||
if (chipdecode == 3) // CHIP 3
|
||||
PORTH &= ~(1 << 6); // /E000 LOW (ENABLE)
|
||||
else if (chipdecode == 2) // CHIP 2
|
||||
PORTH &= ~(1 << 5); // /C000 LOW (ENABLE)
|
||||
else if (chipdecode == 1) // CHIP 1
|
||||
PORTH &= ~(1 << 4); // /A000 LOW (ENABLE)
|
||||
else // CHIP 0
|
||||
PORTH &= ~(1 << 3); // /8000 LOW (ENABLE)
|
||||
|
||||
PORTF = addr & 0xFF; // A0-A7
|
||||
PORTK = (addr >> 8) & 0xFF; // A8-A15
|
||||
|
||||
// LATCH ADDRESS - PULL /CE HIGH
|
||||
PORTH |= (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6); // ALL /CE HIGH (DISABLE)
|
||||
|
||||
uint8_t ret = PINC;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void readSegment_COL(uint32_t startaddr, uint32_t endaddr)
|
||||
{
|
||||
for (uint32_t addr = startaddr; addr < endaddr; addr += 512) {
|
||||
for (int w = 0; w < 512; w++) {
|
||||
uint8_t temp = readData_COL(addr + w);
|
||||
sdBuffer[w] = temp;
|
||||
}
|
||||
myFile.write(sdBuffer, 512);
|
||||
}
|
||||
}
|
||||
|
||||
void readROM_COL()
|
||||
{
|
||||
strcpy(fileName, romName);
|
||||
strcat(fileName, ".col");
|
||||
|
||||
// create a new folder for storing rom file
|
||||
EEPROM_readAnything(0, foldern);
|
||||
// sprintf(folder, "COL/ROM/%s/%d", romName, foldern);
|
||||
sprintf(folder, "COL/ROM/%d", foldern);
|
||||
sd.mkdir(folder, true);
|
||||
sd.chdir(folder);
|
||||
|
||||
display_Clear();
|
||||
print_Msg(F("Saving to "));
|
||||
print_Msg(folder);
|
||||
println_Msg(F("/..."));
|
||||
display_Update();
|
||||
|
||||
// open file on sdcard
|
||||
if (!myFile.open(fileName, O_RDWR | O_CREAT))
|
||||
print_Error(F("Can't create file on SD"), true);
|
||||
|
||||
// write new folder number back to EEPROM
|
||||
foldern++;
|
||||
EEPROM_writeAnything(0, foldern);
|
||||
|
||||
// RESET ALL CS PINS HIGH (DISABLE)
|
||||
PORTH |= (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||
|
||||
readSegment_COL(0x8000, 0xA000); // 8K
|
||||
if (colsize > 0) {
|
||||
readSegment_COL(0xA000, 0xB000); // +4K = 12K
|
||||
if (colsize > 1) {
|
||||
readSegment_COL(0xB000, 0xC000); // +4K = 16K
|
||||
if (colsize > 2) {
|
||||
readSegment_COL(0xC000, 0xD000); // +4K = 20K
|
||||
if (colsize > 3) {
|
||||
readSegment_COL(0xD000, 0xE000); // +4K = 24K
|
||||
if (colsize > 4) {
|
||||
readSegment_COL(0xE000, 0x10000); // +8K = 32K
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
myFile.close();
|
||||
|
||||
// RESET ALL CS PINS HIGH (DISABLE)
|
||||
PORTH |= (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||
|
||||
// Compare CRC32 to database and rename ROM if found
|
||||
compareCRC("colv.txt", 0, 0);
|
||||
|
||||
println_Msg(F(""));
|
||||
println_Msg(F("Press Button..."));
|
||||
display_Update();
|
||||
wait();
|
||||
}
|
||||
|
||||
//******************************************
|
||||
// ROM SIZE
|
||||
//******************************************
|
||||
|
||||
void setROMSize_COL()
|
||||
{
|
||||
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||
display_Clear();
|
||||
if (collo == colhi)
|
||||
newcolsize = collo;
|
||||
else {
|
||||
int b = 0;
|
||||
int i = collo;
|
||||
|
||||
display_Clear();
|
||||
print_Msg(F("ROM Size: "));
|
||||
println_Msg(COL[i]);
|
||||
println_Msg(F(""));
|
||||
#if defined(enable_OLED)
|
||||
println_Msg(F("Press left to Change"));
|
||||
println_Msg(F("and right to Select"));
|
||||
#elif defined(enable_LCD)
|
||||
println_Msg(F("Rotate to Change"));
|
||||
println_Msg(F("Press to Select"));
|
||||
#endif
|
||||
display_Update();
|
||||
|
||||
while (1) {
|
||||
b = checkButton();
|
||||
if (b == 2) { // Previous (doubleclick)
|
||||
if (i == collo)
|
||||
i = colhi;
|
||||
else
|
||||
i--;
|
||||
|
||||
// Only update display after input because of slow LCD library
|
||||
display_Clear();
|
||||
print_Msg(F("ROM Size: "));
|
||||
println_Msg(COL[i]);
|
||||
println_Msg(F(""));
|
||||
#if defined(enable_OLED)
|
||||
println_Msg(F("Press left to Change"));
|
||||
println_Msg(F("and right to Select"));
|
||||
#elif defined(enable_LCD)
|
||||
println_Msg(F("Rotate to Change"));
|
||||
println_Msg(F("Press to Select"));
|
||||
#endif
|
||||
display_Update();
|
||||
}
|
||||
if (b == 1) { // Next (press)
|
||||
if (i == colhi)
|
||||
i = collo;
|
||||
else
|
||||
i++;
|
||||
|
||||
// Only update display after input because of slow LCD library
|
||||
display_Clear();
|
||||
print_Msg(F("ROM Size: "));
|
||||
println_Msg(COL[i]);
|
||||
println_Msg(F(""));
|
||||
#if defined(enable_OLED)
|
||||
println_Msg(F("Press left to Change"));
|
||||
println_Msg(F("and right to Select"));
|
||||
#elif defined(enable_LCD)
|
||||
println_Msg(F("Rotate to Change"));
|
||||
println_Msg(F("Press to Select"));
|
||||
#endif
|
||||
display_Update();
|
||||
}
|
||||
if (b == 3) { // Long Press - Execute (hold)
|
||||
newcolsize = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
display.setCursor(0, 56); // Display selection at bottom
|
||||
}
|
||||
print_Msg(F("ROM SIZE "));
|
||||
print_Msg(COL[newcolsize]);
|
||||
println_Msg(F("K"));
|
||||
display_Update();
|
||||
delay(1000);
|
||||
#else
|
||||
if (collo == colhi)
|
||||
newcolsize = collo;
|
||||
else {
|
||||
setrom:
|
||||
String sizeROM;
|
||||
for (int i = 0; i < (colhi - collo + 1); i++) {
|
||||
Serial.print(F("Select ROM Size: "));
|
||||
Serial.print(i);
|
||||
Serial.print(F(" = "));
|
||||
Serial.print(COL[i + collo]);
|
||||
Serial.println(F("K"));
|
||||
}
|
||||
Serial.print(F("Enter ROM Size: "));
|
||||
while (Serial.available() == 0) {}
|
||||
sizeROM = Serial.readStringUntil('\n');
|
||||
Serial.println(sizeROM);
|
||||
newcolsize = sizeROM.toInt() + collo;
|
||||
if (newcolsize > colhi) {
|
||||
Serial.println(F("SIZE NOT SUPPORTED"));
|
||||
Serial.println(F(""));
|
||||
goto setrom;
|
||||
}
|
||||
}
|
||||
Serial.print(F("ROM Size = "));
|
||||
Serial.print(COL[newcolsize]);
|
||||
Serial.println(F("K"));
|
||||
#endif
|
||||
EEPROM_writeAnything(8, newcolsize);
|
||||
colsize = newcolsize;
|
||||
}
|
||||
|
||||
void checkStatus_COL()
|
||||
{
|
||||
EEPROM_readAnything(8, colsize);
|
||||
if (colsize > 5) {
|
||||
colsize = 0;
|
||||
EEPROM_writeAnything(8, colsize);
|
||||
}
|
||||
|
||||
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||
display_Clear();
|
||||
println_Msg(F("COLECOVISION READER"));
|
||||
println_Msg(F("CURRENT SETTINGS"));
|
||||
println_Msg(F(""));
|
||||
print_Msg(F("ROM SIZE: "));
|
||||
print_Msg(COL[colsize]);
|
||||
println_Msg(F("K"));
|
||||
display_Update();
|
||||
wait();
|
||||
#else
|
||||
Serial.print(F("CURRENT ROM SIZE: "));
|
||||
Serial.print(COL[colsize]);
|
||||
Serial.println(F("K"));
|
||||
Serial.println(F(""));
|
||||
#endif
|
||||
}
|
||||
|
||||
//******************************************
|
||||
// CART SELECT CODE
|
||||
//******************************************
|
||||
|
||||
FsFile colcsvFile;
|
||||
char colgame[36]; // title
|
||||
char colrr[3]; // romsize
|
||||
char colll[4]; // linelength (previous line)
|
||||
unsigned long colcsvpos; // CSV File Position
|
||||
char colcartCSV[] = "colcart.txt"; // CSV List
|
||||
char colcsvEND[] = "EOF"; // CSV End Marker for scrolling
|
||||
|
||||
bool readLine_COL(FsFile &f, char* line, size_t maxLen)
|
||||
{
|
||||
for (size_t n = 0; n < maxLen; n++) {
|
||||
int c = f.read();
|
||||
if ( c < 0 && n == 0) return false; // EOF
|
||||
if (c < 0 || c == '\n') {
|
||||
line[n] = 0;
|
||||
return true;
|
||||
}
|
||||
line[n] = c;
|
||||
}
|
||||
return false; // line too long
|
||||
}
|
||||
|
||||
bool readVals_COL(char* colgame, char* colrr, char* colll)
|
||||
{
|
||||
char line[42];
|
||||
colcsvpos = colcsvFile.position();
|
||||
if (!readLine_COL(colcsvFile, line, sizeof(line))) {
|
||||
return false; // EOF or too long
|
||||
}
|
||||
char* comma = strtok(line, ",");
|
||||
int x = 0;
|
||||
while (comma != NULL) {
|
||||
if (x == 0)
|
||||
strcpy(colgame, comma);
|
||||
else if (x == 1)
|
||||
strcpy(colrr, comma);
|
||||
else if (x == 2)
|
||||
strcpy(colll, comma);
|
||||
comma = strtok(NULL, ",");
|
||||
x += 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getCartListInfo_COL()
|
||||
{
|
||||
bool buttonreleased = 0;
|
||||
bool cartselected = 0;
|
||||
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||
display_Clear();
|
||||
println_Msg(F(" HOLD TO FAST CYCLE"));
|
||||
display_Update();
|
||||
#else
|
||||
Serial.println(F("HOLD BUTTON TO FAST CYCLE"));
|
||||
#endif
|
||||
delay(2000);
|
||||
#if defined(enable_OLED)
|
||||
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||
#elif defined(enable_LCD)
|
||||
boolean buttonVal1 = (PING & (1 << 2)); // PG2
|
||||
#endif
|
||||
if (buttonVal1 == LOW) { // Button Held - Fast Cycle
|
||||
while (1) { // Scroll Game List
|
||||
while (readVals_COL(colgame, colrr, colll)) {
|
||||
if (strcmp(colcsvEND, colgame) == 0) {
|
||||
colcsvFile.seek(0); // Restart
|
||||
}
|
||||
else {
|
||||
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||
display_Clear();
|
||||
println_Msg(F("CART TITLE:"));
|
||||
println_Msg(F(""));
|
||||
println_Msg(colgame);
|
||||
display_Update();
|
||||
#else
|
||||
Serial.print(F("CART TITLE:"));
|
||||
Serial.println(colgame);
|
||||
#endif
|
||||
#if defined(enable_OLED)
|
||||
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||
#elif defined(enable_LCD)
|
||||
boolean buttonVal1 = (PING & (1 << 2)); // PG2
|
||||
#endif
|
||||
if (buttonVal1 == HIGH) { // Button Released
|
||||
buttonreleased = 1;
|
||||
break;
|
||||
}
|
||||
if (buttonreleased) {
|
||||
buttonreleased = 0; // Reset Flag
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if defined(enable_OLED)
|
||||
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||
#elif defined(enable_LCD)
|
||||
boolean buttonVal1 = (PING & (1 << 2)); // PG2
|
||||
#endif
|
||||
if (buttonVal1 == HIGH) // Button Released
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||
display.setCursor(0, 56);
|
||||
println_Msg(F("FAST CYCLE OFF"));
|
||||
display_Update();
|
||||
#else
|
||||
Serial.println(F(""));
|
||||
Serial.println(F("FAST CYCLE OFF"));
|
||||
Serial.println(F("PRESS BUTTON TO STEP FORWARD"));
|
||||
Serial.println(F("DOUBLE CLICK TO STEP BACK"));
|
||||
Serial.println(F("HOLD TO SELECT"));
|
||||
Serial.println(F(""));
|
||||
#endif
|
||||
while (readVals_COL(colgame, colrr, colll)) {
|
||||
if (strcmp(colcsvEND, colgame) == 0) {
|
||||
colcsvFile.seek(0); // Restart
|
||||
}
|
||||
else {
|
||||
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||
display_Clear();
|
||||
println_Msg(F("CART TITLE:"));
|
||||
println_Msg(F(""));
|
||||
println_Msg(colgame);
|
||||
display.setCursor(0, 48);
|
||||
#if defined(enable_OLED)
|
||||
println_Msg(F("Press left to Change"));
|
||||
println_Msg(F("and right to Select"));
|
||||
#elif defined(enable_LCD)
|
||||
println_Msg(F("Rotate to Change"));
|
||||
println_Msg(F("Press to Select"));
|
||||
#endif
|
||||
display_Update();
|
||||
#else
|
||||
Serial.print(F("CART TITLE:"));
|
||||
Serial.println(colgame);
|
||||
#endif
|
||||
while (1) { // Single Step
|
||||
int b = checkButton();
|
||||
if (b == 1) { // Continue (press)
|
||||
break;
|
||||
}
|
||||
if (b == 2) { // Reset to Start of List (doubleclick)
|
||||
byte prevline = strtol(colll, NULL, 10);
|
||||
colcsvpos -= prevline;
|
||||
colcsvFile.seek(colcsvpos);
|
||||
break;
|
||||
}
|
||||
if (b == 3) { // Long Press - Select Cart (hold)
|
||||
newcolsize = strtol(colrr, NULL, 10);
|
||||
EEPROM_writeAnything(8, newcolsize);
|
||||
cartselected = 1; // SELECTION MADE
|
||||
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||
println_Msg(F("SELECTION MADE"));
|
||||
display_Update();
|
||||
#else
|
||||
Serial.println(F("SELECTION MADE"));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cartselected) {
|
||||
cartselected = 0; // Reset Flag
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||
println_Msg(F(""));
|
||||
println_Msg(F("END OF FILE"));
|
||||
display_Update();
|
||||
#else
|
||||
Serial.println(F("END OF FILE"));
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void checkCSV_COL()
|
||||
{
|
||||
if (getCartListInfo_COL()) {
|
||||
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||
display_Clear();
|
||||
println_Msg(F("CART SELECTED"));
|
||||
println_Msg(F(""));
|
||||
println_Msg(colgame);
|
||||
display_Update();
|
||||
// Display Settings
|
||||
display.setCursor(0, 56);
|
||||
print_Msg(F("CODE: R"));
|
||||
println_Msg(newcolsize);
|
||||
display_Update();
|
||||
#else
|
||||
Serial.println(F(""));
|
||||
Serial.println(F("CART SELECTED"));
|
||||
Serial.println(colgame);
|
||||
// Display Settings
|
||||
Serial.print(F("CODE: R"));
|
||||
Serial.println(newcolsize);
|
||||
Serial.println(F(""));
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||
display.setCursor(0, 56);
|
||||
println_Msg(F("NO SELECTION"));
|
||||
display_Update();
|
||||
#else
|
||||
Serial.println(F("NO SELECTION"));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void setCart_COL()
|
||||
{
|
||||
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||
display_Clear();
|
||||
println_Msg(colcartCSV);
|
||||
display_Update();
|
||||
#endif
|
||||
sd.chdir();
|
||||
sprintf(folder, "COL/CSV");
|
||||
sd.chdir(folder); // Switch Folder
|
||||
colcsvFile = sd.open(colcartCSV, O_READ);
|
||||
if (!colcsvFile) {
|
||||
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||
display_Clear();
|
||||
println_Msg(F("CSV FILE NOT FOUND!"));
|
||||
display_Update();
|
||||
#else
|
||||
Serial.println(F("CSV FILE NOT FOUND!"));
|
||||
#endif
|
||||
while (1) {
|
||||
if (checkButton() != 0)
|
||||
setup_COL();
|
||||
}
|
||||
}
|
||||
checkCSV_COL();
|
||||
|
||||
colcsvFile.close();
|
||||
}
|
||||
#endif
|
@ -4,8 +4,8 @@
|
||||
This project represents a community-driven effort to provide
|
||||
an easy to build and easy to modify cartridge dumper.
|
||||
|
||||
Date: 18.07.2022
|
||||
Version: 9.1
|
||||
Date: 23.07.2022
|
||||
Version: 9.2 Alpha
|
||||
|
||||
SD lib: https://github.com/greiman/SdFat
|
||||
OLED lib: https://github.com/adafruit/Adafruit_SSD1306
|
||||
@ -25,7 +25,7 @@
|
||||
MichlK - ROM Reader for Super Nintendo
|
||||
Jeff Saltzman - 4-Way Button
|
||||
Wayne and Layne - Video Game Shield menu
|
||||
skaman - Cart ROM READER SNES ENHANCED & Famicom Cart Dumper
|
||||
skaman - Cart ROM READER SNES ENHANCED, Famicom Cart Dumper, Coleco- and Intellivision modules
|
||||
Tamanegi_taro - PCE and Satellaview modules
|
||||
splash5 - GBSmart, Wonderswan and NGP modules
|
||||
hkz & themanbehindthecurtain - N64 flashram commands
|
||||
@ -40,7 +40,8 @@
|
||||
|
||||
And a special Thank You to all coders and contributors on Github and the Arduino forum:
|
||||
jiyunomegami, splash5, Kreeblah, ramapcsx2, PsyK0p4T, Dakkaron, majorpbx, Pickle, sdhizumi,
|
||||
Uzlopak, sakman55, Tombo89, scrap-a, Tombo89, borti4938, vogelfreiheit, CaitSith2, Modman, philenotfound
|
||||
Uzlopak, sakman55, Tombo89, scrap-a, Tombo89, borti4938, vogelfreiheit, CaitSith2, Modman,
|
||||
philenotfound, karimhadjsalem, nsx0r
|
||||
|
||||
And to nocash for figuring out the secrets of the SFC Nintendo Power cartridge.
|
||||
|
||||
@ -59,7 +60,7 @@
|
||||
|
||||
**********************************************************************************/
|
||||
|
||||
char ver[5] = "9.1";
|
||||
char ver[5] = "9.2A";
|
||||
|
||||
//******************************************
|
||||
// !!! CHOOSE HARDWARE VERSION !!!
|
||||
@ -81,7 +82,7 @@ char ver[5] = "9.1";
|
||||
//******************************************
|
||||
// remove // before #define to enable a module
|
||||
#define enable_SNES
|
||||
#define enable_NP
|
||||
#define enable_SFM
|
||||
#define enable_SV
|
||||
#define enable_MD
|
||||
#define enable_SMS
|
||||
@ -93,6 +94,9 @@ char ver[5] = "9.1";
|
||||
//#define enable_PCE
|
||||
//#define enable_WS
|
||||
//#define enable_NGP
|
||||
//#define enable_INTV
|
||||
//#define enable_COLV
|
||||
//#define enable_VBOY
|
||||
|
||||
//******************************************
|
||||
// HW CONFIGS
|
||||
@ -111,12 +115,14 @@ char ver[5] = "9.1";
|
||||
#if (defined(HW2) || defined(HW3))
|
||||
#define enable_OLED
|
||||
#define enable_Button2
|
||||
// #define clockgen_installed
|
||||
// #define fastcrc
|
||||
#define clockgen_installed
|
||||
#define fastcrc
|
||||
#endif
|
||||
|
||||
#if defined(HW1)
|
||||
#define enable_OLED
|
||||
// #define clockgen_installed
|
||||
// #define fastcrc
|
||||
#endif
|
||||
|
||||
#if defined(SERIAL_MONITOR)
|
||||
@ -296,6 +302,9 @@ bool i2c_found;
|
||||
#define mode_GB_GBSmart_Game 20
|
||||
#define mode_WS 21
|
||||
#define mode_NGP 22
|
||||
#define mode_INTV 23
|
||||
#define mode_COL 24
|
||||
#define mode_VBOY 25
|
||||
|
||||
// optimization-safe nop delay
|
||||
#define NOP __asm__ __volatile__ ("nop\n\t")
|
||||
@ -686,13 +695,16 @@ static const char modeItem6[] PROGMEM = "SMS/GG/MIII/SG-1000";
|
||||
static const char modeItem7[] PROGMEM = "PC Engine/TG16";
|
||||
static const char modeItem8[] PROGMEM = "WonderSwan";
|
||||
static const char modeItem9[] PROGMEM = "NeoGeo Pocket";
|
||||
static const char modeItem10[] PROGMEM = "Flashrom Programmer";
|
||||
static const char modeItem11[] PROGMEM = "About";
|
||||
static const char* const modeOptions[] PROGMEM = {modeItem1, modeItem2, modeItem3, modeItem4, modeItem5, modeItem6, modeItem7, modeItem8, modeItem9, modeItem10, modeItem11};
|
||||
static const char modeItem10[] PROGMEM = "Intellvision";
|
||||
static const char modeItem11[] PROGMEM = "Colecovision";
|
||||
static const char modeItem12[] PROGMEM = "Virtual Boy";
|
||||
static const char modeItem13[] PROGMEM = "Flashrom Programmer";
|
||||
static const char modeItem14[] PROGMEM = "About";
|
||||
static const char* const modeOptions[] PROGMEM = {modeItem1, modeItem2, modeItem3, modeItem4, modeItem5, modeItem6, modeItem7, modeItem8, modeItem9, modeItem10, modeItem11, modeItem12, modeItem13, modeItem14};
|
||||
|
||||
// All included slots
|
||||
void mainMenu() {
|
||||
// create menu with title and 11 options to choose from
|
||||
// create menu with title and 13 options to choose from
|
||||
unsigned char modeMenu;
|
||||
|
||||
// Main menu spans across two pages
|
||||
@ -708,8 +720,8 @@ void mainMenu() {
|
||||
}
|
||||
if (currPage == 2) {
|
||||
// Copy menuOptions out of progmem
|
||||
convertPgm(modeOptions, 7, 4);
|
||||
modeMenu = question_box(F("OPEN SOURCE CART READER"), menuOptions, 4, 0);
|
||||
convertPgm(modeOptions, 7, 7);
|
||||
modeMenu = question_box(F("OPEN SOURCE CART READER"), menuOptions, 7, 0);
|
||||
}
|
||||
if (numPages == 0) {
|
||||
// Execute choice
|
||||
@ -793,8 +805,29 @@ void mainMenu() {
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef enable_FLASH
|
||||
#ifdef enable_INTV
|
||||
case 9:
|
||||
setup_INTV();
|
||||
intvMenu();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef enable_COLV
|
||||
case 10:
|
||||
setup_COL();
|
||||
colMenu();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef enable_VBOY
|
||||
case 11:
|
||||
setup_VBOY();
|
||||
vboyMenu();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef enable_FLASH
|
||||
case 12:
|
||||
#ifdef enable_FLASH16
|
||||
flashMenu();
|
||||
#else
|
||||
@ -803,7 +836,7 @@ void mainMenu() {
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 10:
|
||||
case 13:
|
||||
aboutScreen();
|
||||
break;
|
||||
|
||||
@ -830,14 +863,27 @@ static const char modeItem7[] PROGMEM = "Reset";
|
||||
static const char* const modeOptions[] PROGMEM = {modeItem1, modeItem2, modeItem3, modeItem4, modeItem5, modeItem6, modeItem7};
|
||||
|
||||
// Add-ons submenu
|
||||
static const char addonsItem1[] PROGMEM = "NES/Famicom";
|
||||
static const char addonsItem2[] PROGMEM = "Flashrom Programmer";
|
||||
static const char addonsItem3[] PROGMEM = "PC Engine/TG16";
|
||||
static const char addonsItem4[] PROGMEM = "SMS/GG/MIII/SG-1000";
|
||||
static const char addonsItem5[] PROGMEM = "WonderSwan";
|
||||
static const char addonsItem6[] PROGMEM = "NeoGeo Pocket";
|
||||
static const char addonsItem7[] PROGMEM = "Reset";
|
||||
static const char* const addonsOptions[] PROGMEM = {addonsItem1, addonsItem2, addonsItem3, addonsItem4, addonsItem5, addonsItem6, addonsItem7};
|
||||
static const char addonsItem1[] PROGMEM = "Consoles";
|
||||
static const char addonsItem2[] PROGMEM = "Handhelds";
|
||||
static const char addonsItem3[] PROGMEM = "Flashrom Programmer";
|
||||
static const char addonsItem4[] PROGMEM = "Reset";
|
||||
static const char* const addonsOptions[] PROGMEM = {addonsItem1, addonsItem2, addonsItem3, addonsItem4};
|
||||
|
||||
// Consoles submenu
|
||||
static const char consolesItem1[] PROGMEM = "NES/Famicom";
|
||||
static const char consolesItem2[] PROGMEM = "PC Engine/TG16";
|
||||
static const char consolesItem3[] PROGMEM = "SMS/GG/MIII/SG-1000";
|
||||
static const char consolesItem4[] PROGMEM = "Intellivision";
|
||||
static const char consolesItem5[] PROGMEM = "Colecovision";
|
||||
static const char consolesItem6[] PROGMEM = "Reset";
|
||||
static const char* const consolesOptions[] PROGMEM = {consolesItem1, consolesItem2, consolesItem3, consolesItem4, consolesItem5, consolesItem6};
|
||||
|
||||
// Handhelds submenu
|
||||
static const char handheldsItem1[] PROGMEM = "Virtual Boy";
|
||||
static const char handheldsItem2[] PROGMEM = "WonderSwan";
|
||||
static const char handheldsItem3[] PROGMEM = "NeoGeo Pocket";
|
||||
static const char handheldsItem4[] PROGMEM = "Reset";
|
||||
static const char* const handheldsOptions[] PROGMEM = {handheldsItem1, handheldsItem2, handheldsItem3, handheldsItem4};
|
||||
|
||||
// All included slots
|
||||
void mainMenu() {
|
||||
@ -851,7 +897,7 @@ void mainMenu() {
|
||||
switch (modeMenu)
|
||||
{
|
||||
case 0:
|
||||
addonsMenu();
|
||||
addonMenu();
|
||||
break;
|
||||
|
||||
#ifdef enable_SNES
|
||||
@ -889,15 +935,54 @@ void mainMenu() {
|
||||
}
|
||||
|
||||
// Everything that needs an adapter
|
||||
void addonsMenu() {
|
||||
// create menu with title and 7 options to choose from
|
||||
void addonMenu() {
|
||||
// create menu with title and 4 options to choose from
|
||||
unsigned char addonsMenu;
|
||||
// Copy menuOptions out of progmem
|
||||
convertPgm(addonsOptions, 7);
|
||||
addonsMenu = question_box(F("Choose Adapter"), menuOptions, 7, 0);
|
||||
convertPgm(addonsOptions, 4);
|
||||
addonsMenu = question_box(F("Type"), menuOptions, 4, 0);
|
||||
|
||||
// wait for user choice to come back from the question box menu
|
||||
switch (addonsMenu)
|
||||
{
|
||||
// Consoles
|
||||
case 0:
|
||||
consoleMenu();
|
||||
break;
|
||||
|
||||
// Handhelds
|
||||
case 1:
|
||||
handheldMenu();
|
||||
break;
|
||||
|
||||
#ifdef enable_FLASH
|
||||
case 2:
|
||||
flashMenu();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 3:
|
||||
resetArduino();
|
||||
break;
|
||||
|
||||
default:
|
||||
display_Clear();
|
||||
println_Msg(F("Please enable module"));
|
||||
print_Error(F("in Cart_Reader.ino."), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Everything that needs an adapter
|
||||
void consoleMenu() {
|
||||
// create menu with title and 6 options to choose from
|
||||
unsigned char consolesMenu;
|
||||
// Copy menuOptions out of progmem
|
||||
convertPgm(consolesOptions, 6);
|
||||
consolesMenu = question_box(F("Choose Adapter"), menuOptions, 6, 0);
|
||||
|
||||
// wait for user choice to come back from the question box menu
|
||||
switch (consolesMenu)
|
||||
{
|
||||
#ifdef enable_NES
|
||||
case 0:
|
||||
@ -914,26 +999,66 @@ void addonsMenu() {
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef enable_FLASH
|
||||
case 1:
|
||||
flashMenu();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef enable_PCE
|
||||
case 2:
|
||||
case 1:
|
||||
pcsMenu();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef enable_SMS
|
||||
case 3:
|
||||
case 2:
|
||||
smsMenu();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef enable_WS
|
||||
#ifdef enable_INTV
|
||||
case 3:
|
||||
setup_INTV();
|
||||
intvMenu();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef enable_COLV
|
||||
case 4:
|
||||
setup_COL();
|
||||
colMenu();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 5:
|
||||
resetArduino();
|
||||
break;
|
||||
|
||||
default:
|
||||
display_Clear();
|
||||
println_Msg(F("Please enable module"));
|
||||
print_Error(F("in Cart_Reader.ino."), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Everything that needs an adapter
|
||||
void handheldMenu() {
|
||||
// create menu with title and 4 options to choose from
|
||||
unsigned char handheldsMenu;
|
||||
// Copy menuOptions out of progmem
|
||||
convertPgm(handheldsOptions, 4);
|
||||
handheldsMenu = question_box(F("Choose Adapter"), menuOptions, 4, 0);
|
||||
|
||||
// wait for user choice to come back from the question box menu
|
||||
switch (handheldsMenu)
|
||||
{
|
||||
#ifdef enable_VBOY
|
||||
case 0:
|
||||
mode = mode_VBOY;
|
||||
display_Clear();
|
||||
display_Update();
|
||||
setup_VBOY();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef enable_WS
|
||||
case 1:
|
||||
display_Clear();
|
||||
display_Update();
|
||||
setup_WS();
|
||||
@ -942,7 +1067,7 @@ void addonsMenu() {
|
||||
#endif
|
||||
|
||||
#ifdef enable_NGP
|
||||
case 5:
|
||||
case 2:
|
||||
display_Clear();
|
||||
display_Update();
|
||||
setup_NGP();
|
||||
@ -950,7 +1075,7 @@ void addonsMenu() {
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 6:
|
||||
case 3:
|
||||
resetArduino();
|
||||
break;
|
||||
|
||||
@ -2929,7 +3054,7 @@ void loop() {
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#ifdef enable_NP
|
||||
#ifdef enable_SFM
|
||||
else if (mode == mode_SFM) {
|
||||
sfmMenu();
|
||||
}
|
||||
@ -2942,7 +3067,7 @@ void loop() {
|
||||
gbaMenu();
|
||||
}
|
||||
#endif
|
||||
#ifdef enable_NP
|
||||
#ifdef enable_SFM
|
||||
#ifdef enable_FLASH
|
||||
else if (mode == mode_SFM_Flash) {
|
||||
sfmFlashMenu();
|
||||
@ -3007,6 +3132,21 @@ void loop() {
|
||||
else if (mode == mode_NGP) {
|
||||
ngpMenu();
|
||||
}
|
||||
#endif
|
||||
#ifdef enable_INTV
|
||||
else if (mode == mode_INTV) {
|
||||
intvMenu();
|
||||
}
|
||||
#endif
|
||||
#ifdef enable_COLV
|
||||
else if (mode == mode_COL) {
|
||||
colMenu();
|
||||
}
|
||||
#endif
|
||||
#ifdef enable_VBOY
|
||||
else if (mode == mode_VBOY) {
|
||||
vboyMenu();
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
display_Clear();
|
||||
|
File diff suppressed because it is too large
Load Diff
1018
Cart_Reader/INTV.ino
Normal file
1018
Cart_Reader/INTV.ino
Normal file
File diff suppressed because it is too large
Load Diff
@ -4759,7 +4759,10 @@ void flashGameshark_N64() {
|
||||
|
||||
if (writeErrors == 0) {
|
||||
println_Msg(F("OK"));
|
||||
println_Msg(F(""));
|
||||
println_Msg(F("Turn Cart Reader off now"));
|
||||
display_Update();
|
||||
while (1);
|
||||
}
|
||||
else {
|
||||
print_Msg(writeErrors);
|
||||
|
@ -55,6 +55,7 @@ static const byte PROGMEM mapsize [] = {
|
||||
37, 4, 4, 6, 6, 0, 0, // (super mario bros + tetris + world cup)
|
||||
47, 4, 4, 6, 6, 0, 0, // (super spike vball + world cup)
|
||||
48, 3, 4, 6, 6, 0, 0, // taito tc0690
|
||||
64, 2, 3, 4, 5, 0, 0, // tengen rambo-1
|
||||
65, 3, 4, 5, 6, 0, 0, // irem h-3001
|
||||
66, 2, 3, 2, 3, 0, 0, // gxrom/mhrom
|
||||
67, 3, 3, 5, 5, 0, 0, // sunsoft 3
|
||||
@ -89,6 +90,7 @@ static const byte PROGMEM mapsize [] = {
|
||||
153, 5, 5, 0, 0, 1, 1, // (famicom jump ii) [sram r/w]
|
||||
154, 3, 3, 5, 5, 0, 0, // namcot-3453 (devil man)
|
||||
155, 3, 3, 3, 5, 0, 1, // mmc1 variant [sram r/w]
|
||||
158, 3, 3, 5, 5, 0, 0, // tengen rambo-1 variant (alien syndrome (u))
|
||||
159, 3, 4, 5, 6, 1, 1, // bandai x24c01 [eep r/w]
|
||||
180, 3, 3, 0, 0, 0, 0, // unrom variant (crazy climber)
|
||||
184, 1, 1, 2, 3, 0, 0, // sunsoft 1
|
||||
@ -2366,8 +2368,10 @@ void readPRG(boolean readrom) {
|
||||
|
||||
case 4:
|
||||
case 47:
|
||||
case 64:
|
||||
case 118:
|
||||
case 119:
|
||||
case 158:
|
||||
banks = ((int_pow(2, prgsize) * 2)) - 2; // Set Number of Banks
|
||||
if (mapper == 47)
|
||||
write_prg_byte(0xA001, 0x80); // Block Register - PRG RAM Chip Enable, Writable
|
||||
@ -2386,6 +2390,10 @@ void readPRG(boolean readrom) {
|
||||
dumpPRG(base, address);
|
||||
}
|
||||
}
|
||||
if ((mapper == 64) || (mapper == 158)) {
|
||||
write_prg_byte(0x8000, 15); // PRG Bank 2 ($C000-$DFFF)
|
||||
write_prg_byte(0x8001, banks);
|
||||
}
|
||||
for (word address = 0x4000; address < 0x8000; address += 512) { // Final 2 Banks ($C000-$FFFF)
|
||||
dumpPRG(base, address);
|
||||
}
|
||||
@ -2870,8 +2878,10 @@ void readCHR(boolean readrom) {
|
||||
|
||||
case 4:
|
||||
case 47:
|
||||
case 64:
|
||||
case 118:
|
||||
case 119:
|
||||
case 158:
|
||||
banks = int_pow(2, chrsize) * 4;
|
||||
if (mapper == 47)
|
||||
write_prg_byte(0xA001, 0x80); // Block Register - PRG RAM Chip Enable, Writable
|
||||
@ -4012,7 +4022,7 @@ void NESmaker_ResetFlash() { // Reset Flash
|
||||
write_prg_byte(0xC000, 0x00);
|
||||
write_prg_byte(0xAAAA, 0x55);
|
||||
write_prg_byte(0xC000, 0x01);
|
||||
write_prg_byte(0x9555, 0xF0); // Reset
|
||||
write_prg_byte(0x9555, 0xFF); // Reset
|
||||
}
|
||||
|
||||
// SST 39SF040 Software ID
|
||||
@ -4027,7 +4037,12 @@ void NESmaker_ID() { // Read Flash ID
|
||||
unsigned char ID1 = read_prg_byte(0x8000);
|
||||
unsigned char ID2 = read_prg_byte(0x8001);
|
||||
sprintf(flashid, "%02X%02X", ID1, ID2);
|
||||
NESmaker_ResetFlash(); // Software ID Exit
|
||||
write_prg_byte(0xC000, 0x01);
|
||||
write_prg_byte(0x9555, 0xAA);
|
||||
write_prg_byte(0xC000, 0x00);
|
||||
write_prg_byte(0xAAAA, 0x55);
|
||||
write_prg_byte(0xC000, 0x01);
|
||||
write_prg_byte(0x9555, 0xF0); // Software ID Exit
|
||||
if (strcmp(flashid, "BFB7") == 0) // SST 39SF040
|
||||
flashfound = 1;
|
||||
}
|
||||
@ -4105,7 +4120,6 @@ void writeFLASH() {
|
||||
|
||||
//open file on sd card
|
||||
if (myFile.open(filePath, O_READ)) {
|
||||
myFile.seekSet(16);
|
||||
banks = int_pow(2, prgsize); // 256K/512K
|
||||
for (int i = 0; i < banks; i++) { // 16K Banks
|
||||
for (word sector = 0; sector < 0x4000; sector += 0x1000) { // 4K Sectors ($8000/$9000/$A000/$B000)
|
||||
|
@ -241,7 +241,7 @@ void readROM_NGP(char *outPathBuf, size_t bufferSize) {
|
||||
progress += 512;
|
||||
draw_progressbar(progress, cartSize);
|
||||
}
|
||||
|
||||
|
||||
myFile.close();
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
//******************************************
|
||||
// NINTENDO POWER SF MEMORY MODULE
|
||||
// SF MEMORY MODULE
|
||||
//******************************************
|
||||
#ifdef enable_NP
|
||||
#ifdef enable_SFM
|
||||
|
||||
/******************************************
|
||||
SF Memory Clock Source
|
@ -154,7 +154,7 @@ void snsMenu() {
|
||||
mode = mode_SNES;
|
||||
break;
|
||||
|
||||
#ifdef enable_NP
|
||||
#ifdef enable_SFM
|
||||
case 1:
|
||||
display_Clear();
|
||||
display_Update();
|
||||
|
Loading…
Reference in New Issue
Block a user