mirror of
https://github.com/sanni/cartreader.git
synced 2024-11-10 23:15:08 +01:00
913 lines
21 KiB
C++
913 lines
21 KiB
C++
//******************************************
|
|
// FAIRCHILD CHANNEL F MODULE
|
|
//******************************************
|
|
#if defined(ENABLE_FAIRCHILD)
|
|
// Fairchild Channel F
|
|
// Cartridge Pinout
|
|
// 22P (27P Width) 2.54mm pitch connector
|
|
//
|
|
// TOP BOTTOM
|
|
// SIDE SIDE
|
|
// +-------+
|
|
// | == |
|
|
// | 1 |- GND
|
|
// | 2 |- GND
|
|
// | 3 |- D0
|
|
// | 4 |- D1
|
|
// | 5 |- /INTREQ
|
|
// | 6 |- ROMC0
|
|
// | 7 |- ROMC1
|
|
// | 8 |- ROMC2
|
|
// | 9 |- D2
|
|
// | 10 |- ROMC3
|
|
// | 11 |- D3
|
|
// | == |
|
|
// | == |
|
|
// | == |
|
|
// | 12 |- ROMC4
|
|
// | 13 |- PHI
|
|
// | 14 |- D4
|
|
// | 15 |- WRITE
|
|
// | 16 |- D5
|
|
// | 17 |- D6
|
|
// | 18 |- D7
|
|
// | 19 |- VDD(+5V)
|
|
// | 20 |- VDD(+5V)
|
|
// | 21 |- NC
|
|
// | 22 |- VGG(+12V)
|
|
// | == |
|
|
// +-------+
|
|
//
|
|
// TOP
|
|
// +----------------------------------------------------------------------------------+
|
|
// | |
|
|
// LEFT | | RIGHT
|
|
// | == 22 21 20 19 18 17 16 15 14 13 12 == == == 11 10 9 8 7 6 5 4 3 2 1 == |
|
|
// +----------------------------------------------------------------------------------+
|
|
// BOTTOM
|
|
//
|
|
|
|
// CONTROL PINS:
|
|
// PHI(PH3) - SNES /CS
|
|
// /INTREQ(PH4) - SNES /IRQ
|
|
// WRITE(PH5) - SNES /WR
|
|
// ROMC0(PF0) - SNES A0
|
|
// ROMC1(PF1) - SNES A1
|
|
// ROMC2(PF2) - SNES A2
|
|
// ROMC3(PF3) - SNES A3
|
|
// ROMC4(PF4) - SNES A4
|
|
|
|
/******************************************
|
|
Defines
|
|
*****************************************/
|
|
#define PHI_HI PORTH |= (1 << 3)
|
|
#define PHI_LOW PORTH &= ~(1 << 3)
|
|
#define WRITE_HI PORTH |= (1 << 5)
|
|
#define WRITE_LOW PORTH &= ~(1 << 5)
|
|
|
|
byte FAIRCHILD[] = { 2, 3, 4, 6 };
|
|
byte fairchildlo = 0; // Lowest Entry
|
|
byte fairchildhi = 3; // Highest Entry
|
|
|
|
byte fairchildsize;
|
|
byte newfairchildsize;
|
|
|
|
// EEPROM MAPPING
|
|
// 08 ROM SIZE
|
|
|
|
//******************************************
|
|
// Menu
|
|
//******************************************
|
|
// Base Menu
|
|
static const char fairchildMenuItem4[] PROGMEM = "Read 16K";
|
|
static const char* const menuOptionsFAIRCHILD[] PROGMEM = { FSTRING_SELECT_CART, FSTRING_READ_ROM, FSTRING_SET_SIZE, fairchildMenuItem4, FSTRING_RESET };
|
|
|
|
void setup_FAIRCHILD() {
|
|
// Request 5V
|
|
setVoltage(VOLTS_SET_5V);
|
|
|
|
// Set Address Pins to Output
|
|
// Channel F uses A0-A4 [A5-A23 UNUSED]
|
|
//A0-A7
|
|
DDRF = 0xFF;
|
|
//A8-A15
|
|
DDRK = 0xFF;
|
|
//A16-A23
|
|
DDRL = 0xFF;
|
|
|
|
// Set Control Pins to Output
|
|
// ---(PH0) ---(PH1) PHI(PH3) /INTREQ(PH4) WRITE(PH5) ---(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 Unused Control Pins to HIGH
|
|
// ---(PH0) ---(PH1) PHI(PH3) /INTREQ(PH4) WRITE(PH5) ---(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;
|
|
PORTK = 0xFF; // A8-A15
|
|
PORTL = 0xFF; // A16-A23
|
|
PORTJ |= (1 << 0); // TIME(PJ0)
|
|
|
|
checkStatus_FAIRCHILD();
|
|
strcpy(romName, "FAIRCHILD");
|
|
|
|
mode = CORE_FAIRCHILD;
|
|
}
|
|
|
|
void fairchildMenu() {
|
|
convertPgm(menuOptionsFAIRCHILD, 5);
|
|
uint8_t mainMenu = question_box(F("CHANNEL F MENU"), menuOptions, 5, 0);
|
|
|
|
switch (mainMenu) {
|
|
case 0:
|
|
// Select Cart
|
|
setCart_FAIRCHILD();
|
|
wait();
|
|
setup_FAIRCHILD();
|
|
break;
|
|
|
|
case 1:
|
|
// Read ROM
|
|
sd.chdir("/");
|
|
readROM_FAIRCHILD();
|
|
sd.chdir("/");
|
|
break;
|
|
|
|
case 2:
|
|
// Set Size
|
|
setROMSize_FAIRCHILD();
|
|
break;
|
|
|
|
case 3:
|
|
// Read 16K
|
|
sd.chdir("/");
|
|
read16K_FAIRCHILD();
|
|
sd.chdir("/");
|
|
break;
|
|
|
|
case 4:
|
|
// reset
|
|
resetArduino();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//******************************************
|
|
// READ CODE
|
|
//******************************************
|
|
|
|
// Sean Riddle Dumper Routine
|
|
// clear PC0 with ROMC state 8
|
|
// loop 256 times
|
|
// fetch 16 bytes into buffer with ROMC state 0
|
|
// dump buffer to serial port
|
|
// clear PC0
|
|
|
|
// Clear PC0
|
|
void clearRegister_FAIRCHILD() {
|
|
PHI_LOW;
|
|
WRITE_LOW;
|
|
PORTF = 0; // ROMC3 LOW
|
|
|
|
delay(2000);
|
|
|
|
PHI_HI;
|
|
WRITE_HI;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
WRITE_LOW;
|
|
PHI_HI;
|
|
PORTF = 0; // ROMC3 LOW
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
PORTF = 0; // ROMC3 LOW
|
|
PHI_HI;
|
|
PORTF = 0x8; // this puts us in ROMC state 8 - clear PC0
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
PORTF = 0x08; // ROMC3 HIGH
|
|
PHI_HI;
|
|
PORTF = 0x08; // ROMC3 HIGH
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
PHI_HI;
|
|
WRITE_HI;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
WRITE_LOW;
|
|
PHI_HI;
|
|
PORTF = 0; // ROMC3 LOW
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
WRITE_LOW;
|
|
PHI_HI;
|
|
PORTF = 0; // ROMC3 LOW
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
WRITE_LOW;
|
|
}
|
|
|
|
void setROMC_FAIRCHILD(uint8_t command) {
|
|
PHI_LOW;
|
|
WRITE_LOW;
|
|
NOP;
|
|
|
|
WRITE_HI;
|
|
PHI_HI;
|
|
NOP;
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
|
|
WRITE_LOW;
|
|
PHI_HI;
|
|
NOP;
|
|
NOP;
|
|
|
|
// PWs = 4 PHI Cycles
|
|
// PWl = 6 PHI Cycles
|
|
for (int x = 0; x < 2; x++) { // 2 PHI
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
PHI_HI;
|
|
NOP;
|
|
NOP;
|
|
}
|
|
PORTF = command; // ROMC3 = command
|
|
|
|
for (int x = 0; x < 3; x++) { // 4 PHI
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
PHI_HI;
|
|
NOP;
|
|
NOP;
|
|
}
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
|
|
PHI_HI;
|
|
WRITE_HI;
|
|
NOP;
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
|
|
PHI_HI;
|
|
WRITE_LOW;
|
|
NOP;
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
}
|
|
|
|
void setREAD_FAIRCHILD() {
|
|
PHI_LOW;
|
|
WRITE_LOW;
|
|
NOP;
|
|
|
|
WRITE_HI;
|
|
PHI_HI;
|
|
NOP;
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
|
|
WRITE_LOW;
|
|
PHI_HI;
|
|
NOP;
|
|
NOP;
|
|
|
|
// PWs = 4 PHI Cycles
|
|
// PWl = 6 PHI Cycles
|
|
for (int x = 0; x < 2; x++) { // 2 PHI
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
PHI_HI;
|
|
NOP;
|
|
NOP;
|
|
}
|
|
PORTF = 0; // ROMC3 = 0 = Fetch Data
|
|
}
|
|
|
|
uint8_t readData_FAIRCHILD() {
|
|
for (int x = 0; x < 3; x++) { // 4 PHI
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
PHI_HI;
|
|
NOP;
|
|
NOP;
|
|
}
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
|
|
PHI_HI;
|
|
WRITE_HI;
|
|
NOP;
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
|
|
PHI_HI;
|
|
WRITE_LOW;
|
|
NOP;
|
|
|
|
uint8_t ret = PINC; // read databus into buffer
|
|
|
|
PHI_LOW;
|
|
NOP;
|
|
NOP;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void readROM_FAIRCHILD() {
|
|
strcpy(fileName, romName);
|
|
strcat(fileName, ".bin");
|
|
|
|
// create a new folder for storing rom file
|
|
EEPROM_readAnything(0, foldern);
|
|
sprintf(folder, "FAIRCHILD/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_FatalError(create_file_STR);
|
|
}
|
|
|
|
// write new folder number back to EEPROM
|
|
foldern++;
|
|
EEPROM_writeAnything(0, foldern);
|
|
|
|
unsigned long cartsize = FAIRCHILD[fairchildsize] * 0x400;
|
|
uint8_t blocks = cartsize / 0x200;
|
|
setROMC_FAIRCHILD(0x8); // Clear PC0
|
|
setREAD_FAIRCHILD();
|
|
|
|
// ROM Start Bytes
|
|
// 0x55,0x08 - desert fox, muehle, space war, tic-tac-toe (all 2K)
|
|
// 0x55,0x2B - most carts
|
|
// 0x55,0xAA - alien invasion (4K)
|
|
// 0x55,0xBB - video whizball (3K)
|
|
for (int y = 0; y < 0x4800; y++) {
|
|
uint8_t startbyte = readData_FAIRCHILD();
|
|
if (startbyte == 0x55) { // Start Byte
|
|
sdBuffer[0] = startbyte;
|
|
startbyte = readData_FAIRCHILD();
|
|
if ((startbyte == 0x08) || (startbyte == 0x2B) || (startbyte == 0xAA) || (startbyte == 0xBB)) {
|
|
sdBuffer[1] = startbyte;
|
|
for (int w = 2; w < 512; w++) {
|
|
startbyte = readData_FAIRCHILD();
|
|
sdBuffer[w] = startbyte;
|
|
}
|
|
myFile.write(sdBuffer, 512);
|
|
delay(1); // Added delay
|
|
for (int z = 1; z < blocks; z++) {
|
|
if (cartsize == 0x0C00) { // 3K
|
|
// Skip SRAM Code for 3K Carts - Tested with Hangman 3K
|
|
// Hangman uses an F21022PC 1K SRAM Chip at 0x0400
|
|
// SRAM is NOT Battery Backed so contents change
|
|
// Chips are organized: 1K ROM + 1K SRAM + 1K ROM + 1K ROM
|
|
if (z == 2) {
|
|
for (int x = 0; x < 0x0A00; x++) { // Skip 1K SRAM at 0x0400
|
|
readData_FAIRCHILD();
|
|
}
|
|
}
|
|
} else if (cartsize == 0x1000) { // 4K
|
|
// Skip BIOS/Blocks Code for 4K Carts - Tested with Alien Invasion/Pro Football
|
|
// Alien Invasion/Pro Football both use a DM74LS02N (Quad 2-Input NOR Gate) with two 2K ROM Chips
|
|
uint16_t offset = z * 0x200;
|
|
for (int x = 0; x < 0x800 + offset; x++) { // Skip BIOS/Previous Blocks
|
|
readData_FAIRCHILD();
|
|
}
|
|
}
|
|
for (int w = 0; w < 512; w++) {
|
|
uint8_t temp = readData_FAIRCHILD();
|
|
sdBuffer[w] = temp;
|
|
}
|
|
myFile.write(sdBuffer, 512);
|
|
delay(1); // Added delay
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
myFile.close();
|
|
|
|
calcCRC(fileName, cartsize, NULL, 0);
|
|
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
print_STR(press_button_STR, 1);
|
|
display_Update();
|
|
wait();
|
|
}
|
|
|
|
void read16K_FAIRCHILD() // Read 16K Bytes
|
|
{
|
|
strcpy(fileName, romName);
|
|
strcat(fileName, ".bin");
|
|
|
|
// create a new folder for storing rom file
|
|
EEPROM_readAnything(0, foldern);
|
|
sprintf(folder, "FAIRCHILD/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_FatalError(create_file_STR);
|
|
}
|
|
|
|
// write new folder number back to EEPROM
|
|
foldern++;
|
|
EEPROM_writeAnything(0, foldern);
|
|
|
|
unsigned long cartsize = FAIRCHILD[fairchildsize] * 0x400;
|
|
for (int y = 0; y < 0x20; y++) {
|
|
if (cartsize == 0x1000) { // 4K
|
|
// Skip BIOS/Blocks Code for 4K Carts - Tested with Alien Invasion/Pro Football
|
|
// Alien Invasion/Pro Football both use a DM74LS02N (Quad 2-Input NOR Gate) with two 2K ROM Chips
|
|
// IF CASINO POKER DOES NOT DUMP PROPERLY USING READROM
|
|
// TEST BY SETTING ROM SIZE TO 2K AND 4K THEN COMPARE 16K DUMPS
|
|
uint16_t offset = y * 0x200;
|
|
for (int x = 0; x < 0x800 + offset; x++) { // Skip BIOS/Previous Blocks
|
|
readData_FAIRCHILD();
|
|
}
|
|
}
|
|
for (int w = 0; w < 512; w++) {
|
|
uint8_t temp = readData_FAIRCHILD();
|
|
sdBuffer[w] = temp;
|
|
}
|
|
myFile.write(sdBuffer, 512);
|
|
delay(1); // Added delay
|
|
}
|
|
myFile.close();
|
|
|
|
calcCRC(fileName, 0x4000, NULL, 0);
|
|
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
print_STR(press_button_STR, 1);
|
|
display_Update();
|
|
wait();
|
|
}
|
|
|
|
//******************************************
|
|
// ROM SIZE
|
|
//******************************************
|
|
|
|
void setROMSize_FAIRCHILD() {
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
display_Clear();
|
|
if (fairchildlo == fairchildhi)
|
|
newfairchildsize = fairchildlo;
|
|
else {
|
|
uint8_t b = 0;
|
|
int i = fairchildlo;
|
|
display_Clear();
|
|
print_Msg(F("ROM Size: "));
|
|
println_Msg(FAIRCHILD[i]);
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
#if defined(ENABLE_OLED)
|
|
print_STR(press_to_change_STR, 1);
|
|
print_STR(right_to_select_STR, 1);
|
|
#elif defined(ENABLE_LCD)
|
|
print_STR(rotate_to_change_STR, 1);
|
|
print_STR(press_to_select_STR, 1);
|
|
#endif
|
|
display_Update();
|
|
while (1) {
|
|
b = checkButton();
|
|
if (b == 2) { // Previous (doubleclick)
|
|
if (i == fairchildlo)
|
|
i = fairchildhi;
|
|
else
|
|
i--;
|
|
|
|
// Only update display after input because of slow LCD library
|
|
display_Clear();
|
|
print_Msg(F("ROM Size: "));
|
|
println_Msg(FAIRCHILD[i]);
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
#if defined(ENABLE_OLED)
|
|
print_STR(press_to_change_STR, 1);
|
|
print_STR(right_to_select_STR, 1);
|
|
#elif defined(ENABLE_LCD)
|
|
print_STR(rotate_to_change_STR, 1);
|
|
print_STR(press_to_select_STR, 1);
|
|
#endif
|
|
display_Update();
|
|
}
|
|
if (b == 1) { // Next (press)
|
|
if (i == fairchildhi)
|
|
i = fairchildlo;
|
|
else
|
|
i++;
|
|
// Only update display after input because of slow LCD library
|
|
display_Clear();
|
|
print_Msg(F("ROM Size: "));
|
|
println_Msg(FAIRCHILD[i]);
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
#if defined(ENABLE_OLED)
|
|
print_STR(press_to_change_STR, 1);
|
|
print_STR(right_to_select_STR, 1);
|
|
#elif defined(ENABLE_LCD)
|
|
print_STR(rotate_to_change_STR, 1);
|
|
print_STR(press_to_select_STR, 1);
|
|
#endif
|
|
display_Update();
|
|
}
|
|
if (b == 3) { // Long Press - Execute (hold)
|
|
newfairchildsize = i;
|
|
break;
|
|
}
|
|
}
|
|
display.setCursor(0, 56); // Display selection at bottom
|
|
}
|
|
print_Msg(F("ROM SIZE "));
|
|
print_Msg(FAIRCHILD[newfairchildsize]);
|
|
println_Msg(F("K"));
|
|
display_Update();
|
|
delay(1000);
|
|
#else
|
|
if (fairchildlo == fairchildhi)
|
|
newfairchildsize = fairchildlo;
|
|
else {
|
|
setrom:
|
|
String sizeROM;
|
|
for (int i = 0; i < (fairchildhi - fairchildlo + 1); i++) {
|
|
Serial.print(F("Select ROM Size: "));
|
|
Serial.print(i);
|
|
Serial.print(F(" = "));
|
|
Serial.print(FAIRCHILD[i + fairchildlo]);
|
|
Serial.println(F("K"));
|
|
}
|
|
Serial.print(F("Enter ROM Size: "));
|
|
while (Serial.available() == 0) {}
|
|
sizeROM = Serial.readStringUntil('\n');
|
|
Serial.println(sizeROM);
|
|
newfairchildsize = sizeROM.toInt() + fairchildlo;
|
|
if (newfairchildsize > fairchildhi) {
|
|
Serial.println(F("SIZE NOT SUPPORTED"));
|
|
Serial.println(FS(FSTRING_EMPTY));
|
|
goto setrom;
|
|
}
|
|
}
|
|
Serial.print(F("ROM Size = "));
|
|
Serial.print(FAIRCHILD[newfairchildsize]);
|
|
Serial.println(F("K"));
|
|
#endif
|
|
EEPROM_writeAnything(8, newfairchildsize);
|
|
fairchildsize = newfairchildsize;
|
|
}
|
|
|
|
void checkStatus_FAIRCHILD() {
|
|
EEPROM_readAnything(8, fairchildsize);
|
|
if (fairchildsize > 3) {
|
|
fairchildsize = 0;
|
|
EEPROM_writeAnything(8, fairchildsize);
|
|
}
|
|
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
display_Clear();
|
|
println_Msg(F("CHANNEL F READER"));
|
|
println_Msg(FS(FSTRING_CURRENT_SETTINGS));
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
print_Msg(F("ROM SIZE: "));
|
|
print_Msg(FAIRCHILD[fairchildsize]);
|
|
println_Msg(F("K"));
|
|
display_Update();
|
|
wait();
|
|
#else
|
|
Serial.print(F("CURRENT ROM SIZE: "));
|
|
Serial.print(FAIRCHILD[fairchildsize]);
|
|
Serial.println(F("K"));
|
|
Serial.println(FS(FSTRING_EMPTY));
|
|
#endif
|
|
}
|
|
|
|
//******************************************
|
|
// CART SELECT CODE
|
|
//******************************************
|
|
|
|
FsFile fairchildcsvFile;
|
|
char fairchildgame[33]; // title
|
|
char fairchildrr[3]; // romsize
|
|
char fairchildll[4]; // linelength (previous line)
|
|
unsigned long fairchildcsvpos; // CSV File Position
|
|
char fairchildcartCSV[] = "fairchildcart.txt"; // CSV List
|
|
char fairchildcsvEND[] = "EOF"; // CSV End Marker for scrolling
|
|
|
|
bool readLine_FAIRCHILD(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_FAIRCHILD(char* fairchildgame, char* fairchildrr, char* fairchildll) {
|
|
char line[39];
|
|
fairchildcsvpos = fairchildcsvFile.position();
|
|
if (!readLine_FAIRCHILD(fairchildcsvFile, line, sizeof(line))) {
|
|
return false; // EOF or too long
|
|
}
|
|
char* comma = strtok(line, ",");
|
|
int x = 0;
|
|
while (comma != NULL) {
|
|
if (x == 0)
|
|
strcpy(fairchildgame, comma);
|
|
else if (x == 1)
|
|
strcpy(fairchildrr, comma);
|
|
else if (x == 2)
|
|
strcpy(fairchildll, comma);
|
|
comma = strtok(NULL, ",");
|
|
x += 1;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool getCartListInfo_FAIRCHILD() {
|
|
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_FAIRCHILD(fairchildgame, fairchildrr, fairchildll)) {
|
|
if (strcmp(fairchildcsvEND, fairchildgame) == 0) {
|
|
fairchildcsvFile.seek(0); // Restart
|
|
} else {
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
display_Clear();
|
|
println_Msg(F("CART TITLE:"));
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
println_Msg(fairchildgame);
|
|
display_Update();
|
|
#else
|
|
Serial.print(F("CART TITLE:"));
|
|
Serial.println(fairchildgame);
|
|
#endif
|
|
#if defined(ENABLE_OLED)
|
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
|
#elif defined(ENABLE_LCD)
|
|
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)
|
|
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(FS(FSTRING_EMPTY));
|
|
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(FS(FSTRING_EMPTY));
|
|
#endif
|
|
while (readVals_FAIRCHILD(fairchildgame, fairchildrr, fairchildll)) {
|
|
if (strcmp(fairchildcsvEND, fairchildgame) == 0) {
|
|
fairchildcsvFile.seek(0); // Restart
|
|
} else {
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
display_Clear();
|
|
println_Msg(F("CART TITLE:"));
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
println_Msg(fairchildgame);
|
|
display.setCursor(0, 48);
|
|
#if defined(ENABLE_OLED)
|
|
print_STR(press_to_change_STR, 1);
|
|
print_STR(right_to_select_STR, 1);
|
|
#elif defined(ENABLE_LCD)
|
|
print_STR(rotate_to_change_STR, 1);
|
|
print_STR(press_to_select_STR, 1);
|
|
#endif
|
|
display_Update();
|
|
#else
|
|
Serial.print(F("CART TITLE:"));
|
|
Serial.println(fairchildgame);
|
|
#endif
|
|
while (1) { // Single Step
|
|
uint8_t b = checkButton();
|
|
if (b == 1) { // Continue (press)
|
|
break;
|
|
}
|
|
if (b == 2) { // Reset to Start of List (doubleclick)
|
|
byte prevline = strtol(fairchildll, NULL, 10);
|
|
fairchildcsvpos -= prevline;
|
|
fairchildcsvFile.seek(fairchildcsvpos);
|
|
break;
|
|
}
|
|
if (b == 3) { // Long Press - Select Cart (hold)
|
|
newfairchildsize = strtol(fairchildrr, NULL, 10);
|
|
EEPROM_writeAnything(8, newfairchildsize);
|
|
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(FS(FSTRING_EMPTY));
|
|
println_Msg(FS(FSTRING_END_OF_FILE));
|
|
display_Update();
|
|
#else
|
|
Serial.println(FS(FSTRING_END_OF_FILE));
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
void checkCSV_FAIRCHILD() {
|
|
if (getCartListInfo_FAIRCHILD()) {
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
display_Clear();
|
|
println_Msg(FS(FSTRING_CART_SELECTED));
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
println_Msg(fairchildgame);
|
|
display_Update();
|
|
// Display Settings
|
|
display.setCursor(0, 56);
|
|
print_Msg(F("CODE: R"));
|
|
println_Msg(newfairchildsize);
|
|
display_Update();
|
|
#else
|
|
Serial.println(FS(FSTRING_EMPTY));
|
|
Serial.println(FS(FSTRING_CART_SELECTED));
|
|
Serial.println(fairchildgame);
|
|
// Display Settings
|
|
Serial.print(F("CODE: R"));
|
|
Serial.println(newfairchildsize);
|
|
Serial.println(FS(FSTRING_EMPTY));
|
|
#endif
|
|
} else {
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
display.setCursor(0, 56);
|
|
println_Msg(FS(FSTRING_NO_SELECTION));
|
|
display_Update();
|
|
#else
|
|
Serial.println(FS(FSTRING_NO_SELECTION));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void setCart_FAIRCHILD() {
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
display_Clear();
|
|
println_Msg(fairchildcartCSV);
|
|
display_Update();
|
|
#endif
|
|
sd.chdir();
|
|
sprintf(folder, "FAIRCHILD/CSV");
|
|
sd.chdir(folder); // Switch Folder
|
|
fairchildcsvFile = sd.open(fairchildcartCSV, O_READ);
|
|
if (!fairchildcsvFile) {
|
|
#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_FAIRCHILD();
|
|
}
|
|
}
|
|
checkCSV_FAIRCHILD();
|
|
|
|
fairchildcsvFile.close();
|
|
}
|
|
#endif
|
|
//******************************************
|
|
// End of File
|
|
//******************************************
|