mirror of
https://github.com/sanni/cartreader.git
synced 2024-12-30 15:01:53 +01:00
1053 lines
25 KiB
C++
1053 lines
25 KiB
C++
//******************************************
|
|
// LEAP MODULE
|
|
//******************************************
|
|
#ifdef ENABLE_LEAP
|
|
// Leapster
|
|
// Cartridge pinout
|
|
// 60P 1.27mm pitch connector
|
|
//
|
|
// FRONT BACK
|
|
// SIDE SIDE
|
|
// +---------+
|
|
// VCC -| 1B 1A |- VCC
|
|
// nc -| 2B 2A |- GND
|
|
// D11 -| 3B 3A |- D4
|
|
// D3 -| 4B 4A |- D12
|
|
// D10 -| 5B 5A |- D5
|
|
// GND -| 6B 6A |- D2
|
|
// D13 -| 7B 7A |- D9
|
|
// nc -| 8B 8A |- nc
|
|
// D6 -| 9B 9A |- D1
|
|
// D14 -| 10B 10A |- D8
|
|
// |---------|
|
|
// D7 -| 11B 11A |- GND
|
|
// D0 -| 12B 12A |- D15
|
|
// BYTE -| 13B 13A |- OE
|
|
// nc -| 14B 14A |- A22
|
|
// FLA_CE -| 15B 15A |- A23
|
|
// CE -| 16B 16A |- A16
|
|
// A0 -| 17B 17A |- A15
|
|
// A1 -| 18B 18A |- A14
|
|
// A2 -| 19B 19A |- A13
|
|
// GND -| 20B 20A |- A3
|
|
// A12 -| 21B 21A |- A4
|
|
// A11 -| 22B 22A |- A5
|
|
// A10 -| 23B 23A |- A6
|
|
// A9 -| 24B 24A |- A7
|
|
// A8 -| 25B 25A |- A17
|
|
// A19 -| 26B 26A |- A18
|
|
// A20 -| 27B 27A |- A21
|
|
// WE -| 28B 28A |- GND
|
|
// EEP_SDA -| 29B 29A |- EEP_WP
|
|
// nc -| 30B 30A |- EEP_SCL
|
|
// +---------+
|
|
//
|
|
// CONTROL PINS:
|
|
// EEPROM WP (PH0) - SNES /RESET
|
|
// EEPROM SCL (PH1) - SNES CPUCLK
|
|
// EEPROM SDA (PH4) - SNES /IRQ
|
|
// OE (PH3) - SNES /CART
|
|
// WE (PH5) - SNES /WR
|
|
// CE (PH6) - SNES /RD
|
|
// BYTE (PE5) - SNES REFRESH
|
|
// FLASH CE (PJ0) - SNES /PARD
|
|
|
|
//******************************************
|
|
// DEFINES
|
|
//******************************************
|
|
// CONTROL PINS - OE/WE/CE
|
|
#define OE_HIGH PORTH |= (1<<3)
|
|
#define OE_LOW PORTH &= ~(1<<3)
|
|
#define WE_HIGH PORTH |= (1<<5)
|
|
#define WE_LOW PORTH &= ~(1<<5)
|
|
#define CE_HIGH PORTH |= (1<<6)
|
|
#define CE_LOW PORTH &= ~(1<<6)
|
|
|
|
// BYTE PIN IS A0 IN BYTE MODE - SHIFT ADDRESS >> 1
|
|
#define BYTE_HIGH PORTE |= (1<<5)
|
|
#define BYTE_LOW PORTE &= ~(1<<5)
|
|
|
|
// SERIAL I2C EEPROM PINS 24LC02B 2K
|
|
// PIN 5 - SDA
|
|
// PIN 6 - SCL
|
|
// PIN 7 - WP
|
|
// CART B30 = SDA
|
|
// CART A31 = SCL
|
|
// CART A30 = WP
|
|
#define WP_HIGH PORTH |= (1<<0)
|
|
#define WP_LOW PORTH &= ~(1<<0)
|
|
#define SCL_HIGH PORTH |= (1<<1)
|
|
#define SCL_LOW PORTH &= ~(1<<1)
|
|
#define SDA_HIGH PORTH |= (1<<4)
|
|
#define SDA_LOW PORTH &= ~(1<<4)
|
|
|
|
// FLASH 39VF040 512K
|
|
// CART B16 = CE#
|
|
#define FL_CE_HIGH PORTJ |= (1<<0)
|
|
#define FL_CE_LOW PORTJ &= ~(1<<0)
|
|
|
|
#define DATA_C_READ { DDRC = 0; PORTC = 0xFF; } // [INPUT PULLUP]
|
|
#define DATA_A_READ { DDRA = 0; PORTA = 0xFF; } // [INPUT PULLUP]
|
|
|
|
//******************************************
|
|
// VARIABLES
|
|
//******************************************
|
|
// ROM File = LEAP.bin
|
|
// RAM File = SAVE.eep
|
|
// FLASH File = SAVE.fla
|
|
|
|
byte LEAPSTER[] = {4,8,16};
|
|
byte leaplo = 0; // Lowest Entry
|
|
byte leaphi = 2; // Highest Entry
|
|
byte leapsize;
|
|
byte newleapsize;
|
|
|
|
byte tempbyte;
|
|
char tempword;
|
|
word ptrword;
|
|
word tempcheck;
|
|
|
|
// EEPROM MAPPING
|
|
// 08 ROM SIZE
|
|
|
|
//******************************************
|
|
// ROM STRUCTURE
|
|
//******************************************
|
|
char LEAP[] = {0x4C,0x45,0x41,0x50}; // "LEAP" MARKER AT 0x00 OR 0x144 (WORD 0xA2)
|
|
char TBL[] = {0x01,0x00,0x00,0x01}; // TABLE START
|
|
char TXT[] = {0x04,0x00,0x00,0x01}; // NEXT DWORD IS TEXT BLOCK [5 SENTENCES] START
|
|
char VER[] = {0x0A,0x00,0x00,0x01}; // NEXT DWORD IS ROM VERSION LOCATION
|
|
char TTL[] = {0x0B,0x00,0x00,0x01}; // NEXT DWORD IS ROM TITLE LOCATION
|
|
char END[] = {0x10,0x00,0x00,0x01}; // LAST BLOCK - END SEARCH
|
|
word sentenceAddr = 0; // Sentence Block Start Address
|
|
word versionAddr = 0; // Version Address
|
|
word titleAddr = 0; // Title Address
|
|
char ROMVersion[20]; // Fosters [20] "155-11172 152-11808"
|
|
char ROMTitle[50]; // "Mr. Pencils Learn to Draw and Write." [37]
|
|
// "Thomas and Friends Calling All Engines" [39]
|
|
// "The Letter Factory.v1.0 - Initial Release JBM3" [47]
|
|
|
|
//******************************************
|
|
// DATA INTEGRITY BLOCK
|
|
//******************************************
|
|
// 5 Sentences - 172 bytes
|
|
// Location not static between ROMs
|
|
|
|
static const unsigned char LeapCheck [] = {
|
|
0x4C,0x69,0x6C,0x20,0x64,0x75,0x63,0x6B,0x65,0x64,0x2E,0x20,0x20,0x54,0x68,0x65,
|
|
0x20,0x6A,0x65,0x74,0x20,0x7A,0x69,0x70,0x70,0x65,0x64,0x20,0x70,0x61,0x73,0x74,
|
|
0x20,0x68,0x65,0x72,0x20,0x68,0x65,0x61,0x64,0x2E,0x20,0x20,0x44,0x75,0x73,0x74,
|
|
0x20,0x66,0x6C,0x65,0x77,0x2C,0x20,0x4C,0x69,0x6C,0x20,0x73,0x6E,0x65,0x65,0x7A,
|
|
0x65,0x64,0x2C,0x20,0x61,0x6E,0x64,0x20,0x4C,0x65,0x61,0x70,0x20,0x74,0x75,0x72,
|
|
0x6E,0x65,0x64,0x20,0x72,0x65,0x64,0x2E,0x20,0x20,0x54,0x68,0x65,0x6E,0x20,0x4C,
|
|
0x69,0x6C,0x20,0x67,0x6F,0x74,0x20,0x75,0x70,0x2C,0x20,0x61,0x62,0x6F,0x75,0x74,
|
|
0x20,0x74,0x6F,0x20,0x79,0x65,0x6C,0x6C,0x2E,0x20,0x20,0x4C,0x65,0x61,0x70,0x20,
|
|
0x67,0x61,0x73,0x70,0x65,0x64,0x2C,0x20,0x22,0x4C,0x6F,0x6F,0x6B,0x2C,0x20,0x4C,
|
|
0x69,0x6C,0x21,0x20,0x20,0x59,0x6F,0x75,0x72,0x20,0x74,0x6F,0x6F,0x74,0x68,0x21,
|
|
0x20,0x20,0x49,0x74,0x20,0x66,0x65,0x6C,0x6C,0x21,0x22,0x00
|
|
};
|
|
|
|
//******************************************
|
|
// MENU
|
|
//******************************************
|
|
// Base Menu
|
|
static const char leapmenuItem4[] PROGMEM = "Read EEPROM";
|
|
static const char leapmenuItem5[] PROGMEM = "Write EEPROM";
|
|
static const char leapmenuItem6[] PROGMEM = "Read FLASH";
|
|
static const char leapmenuItem7[] PROGMEM = "Write FLASH";
|
|
static const char* const menuOptionsLEAP[] PROGMEM = { FSTRING_SELECT_CART, FSTRING_READ_ROM, FSTRING_SET_SIZE, leapmenuItem4, leapmenuItem5, leapmenuItem6, leapmenuItem7 };
|
|
|
|
void leapMenu()
|
|
{
|
|
convertPgm(menuOptionsLEAP, 7);
|
|
uint8_t mainMenu = question_box(F("LEAPSTER MENU"), menuOptions, 7, 0);
|
|
|
|
switch (mainMenu)
|
|
{
|
|
// Select Cart
|
|
case 0:
|
|
setCart_LEAP();
|
|
setup_LEAP();
|
|
break;
|
|
|
|
// Read ROM
|
|
case 1:
|
|
sd.chdir("/");
|
|
readROM_LEAP();
|
|
sd.chdir("/");
|
|
break;
|
|
|
|
// Set Size
|
|
case 2:
|
|
setROMSize_LEAP();
|
|
break;
|
|
|
|
// Read EEPROM
|
|
case 3:
|
|
sd.chdir("/");
|
|
readEEP_LEAP();
|
|
sd.chdir("/");
|
|
break;
|
|
|
|
// Write EEPROM
|
|
case 4:
|
|
writeEEP_LEAP();
|
|
break;
|
|
|
|
// Read FLASH
|
|
case 5:
|
|
idFLASH_LEAP();
|
|
if (strcmp(flashid_str, "BFD7") == 0) {
|
|
sd.chdir("/");
|
|
readFLASH_LEAP();
|
|
sd.chdir("/");
|
|
}
|
|
break;
|
|
|
|
// Write FLASH
|
|
case 6:
|
|
idFLASH_LEAP();
|
|
if (strcmp(flashid_str, "BFD7") == 0)
|
|
writeFLASH_LEAP();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//******************************************
|
|
// SETUP
|
|
//******************************************
|
|
|
|
void setup_LEAP()
|
|
{
|
|
// Request 3.3V
|
|
setVoltage(VOLTS_SET_3V3);
|
|
|
|
// Control Pins PH0..PH1, PH3..PH6 BYTE, OE, CE, WE
|
|
DDRH = 0x7B; // 0b01111011 - CE, WE, SDA, OE, SCL, WP [OUTPUT] - Unused Pins [INPUT]
|
|
PORTH = 0xFF; // 0b11111111 - CE, WE, SDA, OE, SCL, WP [HIGH] - Unused Pins [HIGH]
|
|
|
|
// Address Pins
|
|
DDRF = 0xFF; // Address A0-A7 [OUTPUT]
|
|
DDRK = 0xFF; // Address A8-A15 [OUTPUT]
|
|
DDRL = 0xFF; // Address A16-A23 [OUTPUT]
|
|
// Data Pins
|
|
DDRC = 0x00; // D0-D7 [INPUT]
|
|
DDRA = 0x00; // D8-D15 [INPUT]
|
|
// BYTE Pin PE5
|
|
DDRE = 0x20; // 0b00100000 BYTE [OUTPUT] - Unused Pins [INPUT]
|
|
PORTE = 0xFF; // 0b11111111 BYTE [HIGH] - Unused Pins [HIGH]
|
|
// Flash Pin PJ0
|
|
DDRJ = 0x01; // 0b00000001 - FLA_CE [OUTPUT] - Unused Pins [INPUT]
|
|
PORTJ = 0xFF; // 0b11111111 - FLA_CE [HIGH] - Unused Pins {HIGH]
|
|
|
|
// Check Start for "LEAP" marker
|
|
// Read ROM Version & Title
|
|
checkStart_LEAP();
|
|
|
|
// 39VF040 Flash Check
|
|
// idFLASH();
|
|
|
|
checkStatus_LEAP();
|
|
strncpy(romName, ROMTitle, 16); // Truncate ROMTitle to fit
|
|
|
|
mode = CORE_LEAP;
|
|
}
|
|
|
|
//******************************************
|
|
// READ FUNCTIONS
|
|
//******************************************
|
|
// Max ROM Size 0x1000000 (Highest Address = 0xFFFFFF) - FF FFFF
|
|
word read_rom_word_LEAP(unsigned long address) // OLD TIMING #1
|
|
{
|
|
PORTL = (address >> 16) & 0xFF;
|
|
PORTK = (address >> 8) & 0xFF;
|
|
PORTF = address & 0xFF;
|
|
CE_LOW;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
OE_LOW;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
unsigned char data1 = PINC;
|
|
unsigned char data2 = PINA;
|
|
word data = (data1 << 8) | (data2);
|
|
OE_HIGH;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
CE_HIGH;
|
|
|
|
return data;
|
|
}
|
|
|
|
byte read_flash_byte_LEAP(unsigned long address) // CE HIGH, OE LOW, FL_CE LOW
|
|
{
|
|
PORTL = (address >> 17) & 0x7F;
|
|
PORTK = (address >> 9) & 0xFF;
|
|
PORTF = (address >> 1) & 0xFF;
|
|
if (address & 0x1) // BYTE = A0
|
|
BYTE_HIGH;
|
|
else
|
|
BYTE_LOW;
|
|
CE_HIGH;
|
|
OE_LOW;
|
|
FL_CE_LOW;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
unsigned char data = PINC;
|
|
FL_CE_HIGH;
|
|
OE_HIGH;
|
|
|
|
return data;
|
|
}
|
|
|
|
//******************************************
|
|
// WRITE FUNCTION
|
|
//******************************************
|
|
|
|
void write_flash_byte_LEAP(unsigned long address, unsigned char data)
|
|
{
|
|
PORTL = (address >> 17) & 0x7F;
|
|
PORTK = (address >> 9) & 0xFF;
|
|
PORTF = (address >> 1) & 0xFF;
|
|
if (address & 0x1) // BYTE = A0
|
|
BYTE_HIGH;
|
|
else
|
|
BYTE_LOW;
|
|
OE_HIGH;
|
|
FL_CE_LOW;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
PORTC = data;
|
|
WE_LOW;
|
|
WE_HIGH;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
FL_CE_HIGH;
|
|
OE_LOW;
|
|
}
|
|
|
|
//******************************************
|
|
// DATA INTEGRITY FUNCTIONS
|
|
//******************************************
|
|
|
|
void checkStart_LEAP()
|
|
{
|
|
delay(500);
|
|
OE_LOW;
|
|
CE_LOW;
|
|
BYTE_HIGH;
|
|
tempword = read_rom_word_LEAP(0x0);
|
|
if ((LEAP[0] == ((tempword >> 0x8) & 0xFF)) && (LEAP[1] == (tempword & 0xFF))) {
|
|
tempword = read_rom_word_LEAP(0x1);
|
|
findTable_LEAP(0x4, 0xA2);
|
|
}
|
|
else {
|
|
delay(500);
|
|
tempword = read_rom_word_LEAP(0xA2);
|
|
if ((LEAP[0] == ((tempword >> 0x8) & 0xFF)) && (LEAP[1] == (tempword & 0xFF))) {
|
|
tempword = read_rom_word_LEAP(0xA3);
|
|
findTable_LEAP(0xA4, 0x146);
|
|
}
|
|
}
|
|
CE_HIGH;
|
|
OE_HIGH;
|
|
}
|
|
|
|
void findTable_LEAP(unsigned long startAddr, unsigned long endAddr)
|
|
{
|
|
delay(500);
|
|
CE_LOW;
|
|
for (unsigned long addr = startAddr; addr < endAddr; addr +=2) {
|
|
tempword = read_rom_word_LEAP(addr);
|
|
if ((TBL[0] == ((tempword >> 0x8) & 0xFF))&&(TBL[1] == (tempword & 0xFF))) {
|
|
tempword = read_rom_word_LEAP(addr + 1);
|
|
if ((TBL[2] == ((tempword >> 0x8) & 0xFF))&&(TBL[3] == (tempword & 0xFF))) {
|
|
readTable_LEAP(startAddr, endAddr);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CE_HIGH;
|
|
}
|
|
|
|
void readTable_LEAP(unsigned long startAddr, unsigned long endAddr)
|
|
{
|
|
delay(500);
|
|
CE_LOW;
|
|
for (unsigned long addr = startAddr; addr < endAddr; addr++) {
|
|
tempword = read_rom_word_LEAP(addr);
|
|
if ((TXT[0] == ((tempword >> 0x8) & 0xFF))&&(TXT[1] == (tempword & 0xFF))) {
|
|
tempword = read_rom_word_LEAP(addr + 1);
|
|
if ((TXT[2] == ((tempword >> 0x8) & 0xFF))&&(TXT[3] == (tempword & 0xFF))) { // Text Block Marker Found
|
|
ptrword = read_rom_word_LEAP(addr + 2);
|
|
sentenceAddr = (((ptrword >> 8) & 0xFF) | ((ptrword & 0xFF) << 8)); // Swap Byte Order
|
|
}
|
|
}
|
|
else if ((VER[0] == ((tempword >> 0x8) & 0xFF))&&(VER[1] == (tempword & 0xFF))) {
|
|
tempword = read_rom_word_LEAP(addr + 1);
|
|
if ((VER[2] == ((tempword >> 0x8) & 0xFF))&&(VER[3] == (tempword & 0xFF))) { // Version Marker Found
|
|
ptrword = read_rom_word_LEAP(addr + 2);
|
|
versionAddr = (((ptrword >> 8) & 0xFF) | ((ptrword & 0xFF) << 8)); // Swap Byte Order
|
|
}
|
|
}
|
|
else if ((TTL[0] == ((tempword >> 0x8) & 0xFF))&&(TTL[1] == (tempword & 0xFF))) {
|
|
tempword = read_rom_word_LEAP(addr + 1);
|
|
if ((TTL[2] == ((tempword >> 0x8) & 0xFF))&&(TTL[3] == (tempword & 0xFF))) { // Title Marker Found
|
|
ptrword = read_rom_word_LEAP(addr + 2);
|
|
titleAddr = (((ptrword >> 8) & 0xFF) | ((ptrword & 0xFF) << 8)); // Swap Byte Order
|
|
}
|
|
}
|
|
else if ((END[0] == ((tempword >> 0x8) & 0xFF))&&(END[1] == (tempword & 0xFF))) {
|
|
tempword = read_rom_word_LEAP(addr + 1);
|
|
if ((END[2] == ((tempword >> 0x8) & 0xFF))&&(END[3] == (tempword & 0xFF))) { // END OF TABLE
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CE_HIGH;
|
|
// print_Msg(F("Text Addr: "));
|
|
// println_Msg(sentenceAddr, HEX);
|
|
// print_Msg(F("Version Addr: "));
|
|
// println_Msg(versionAddr, HEX);
|
|
// print_Msg(F("Title Addr: "));
|
|
// println_Msg(titleAddr, HEX);
|
|
// display_Update();
|
|
|
|
delay(500);
|
|
CE_LOW;
|
|
for (int x = 0; x < 10; x++) {
|
|
tempword = read_rom_word_LEAP((versionAddr / 2) + x);
|
|
ROMVersion[x * 2] = (tempword >> 0x8) & 0xFF;
|
|
ROMVersion[(x * 2) + 1] = tempword & 0xFF;
|
|
}
|
|
|
|
delay(500);
|
|
CE_LOW;
|
|
for (int x = 0; x < 25; x++) {
|
|
tempword = read_rom_word_LEAP((titleAddr / 2) + x);
|
|
ROMTitle[x * 2] = (tempword >> 0x8) & 0xFF;
|
|
ROMTitle[(x * 2) + 1] = tempword & 0xFF;
|
|
}
|
|
}
|
|
|
|
//******************************************
|
|
// READ ROM
|
|
//******************************************
|
|
|
|
void readROM_LEAP()
|
|
{
|
|
createFolderAndOpenFile("LEAP", "ROM", romName, "bin");
|
|
|
|
for (unsigned long address = 0; address < 0x200000; address += 256) { // 4MB
|
|
for (unsigned int x = 0; x < 256; x++) {
|
|
tempword = read_rom_word_LEAP(address + x);
|
|
sdBuffer[x * 2] = (tempword >> 0x8) & 0xFF;
|
|
sdBuffer[(x * 2) + 1] = tempword & 0xFF;
|
|
}
|
|
myFile.write(sdBuffer, 512);
|
|
}
|
|
if (leapsize > 0) {
|
|
for (unsigned long address = 0x200000; address < 0x400000; address += 256) { // +4MB = 8MB
|
|
for (unsigned int x = 0; x < 256; x++) {
|
|
tempword = read_rom_word_LEAP(address + x);
|
|
sdBuffer[x * 2] = (tempword >> 0x8) & 0xFF;
|
|
sdBuffer[(x * 2) + 1] = tempword & 0xFF;
|
|
}
|
|
myFile.write(sdBuffer, 512);
|
|
}
|
|
if (leapsize > 1) {
|
|
for (unsigned long address = 0x400000; address < 0x800000; address += 256) { // +8MB = 16MB
|
|
for (unsigned int x = 0; x < 256; x++) {
|
|
tempword = read_rom_word_LEAP(address + x);
|
|
sdBuffer[x * 2] = (tempword >> 0x8) & 0xFF;
|
|
sdBuffer[(x * 2) + 1] = tempword & 0xFF;
|
|
}
|
|
myFile.write(sdBuffer, 512);
|
|
}
|
|
}
|
|
}
|
|
myFile.close();
|
|
|
|
printCRC(fileName, NULL, 0);
|
|
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
print_STR(press_button_STR, 1);
|
|
display_Update();
|
|
wait();
|
|
}
|
|
|
|
//******************************************
|
|
// ROM SIZE
|
|
//******************************************
|
|
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
void printRomSize_LEAP(int index)
|
|
{
|
|
display_Clear();
|
|
print_Msg(FS(FSTRING_ROM_SIZE));
|
|
println_Msg(LEAPSTER[index]);
|
|
}
|
|
#endif
|
|
|
|
void setROMSize_LEAP()
|
|
{
|
|
byte newleapsize;
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
display_Clear();
|
|
if (leaplo == leaphi)
|
|
newleapsize = leaplo;
|
|
else {
|
|
newleapsize = navigateMenu(leaplo, leaphi, &printRomSize_LEAP);
|
|
|
|
display.setCursor(0, 56); // Display selection at bottom
|
|
}
|
|
print_Msg(FS(FSTRING_ROM_SIZE));
|
|
print_Msg(LEAPSTER[newleapsize]);
|
|
println_Msg(F("KB"));
|
|
display_Update();
|
|
delay(1000);
|
|
#else
|
|
if (leaplo == leaphi)
|
|
newleapsize = leaplo;
|
|
else {
|
|
setrom:
|
|
String sizeROM;
|
|
for (int i = 0; i < (leaphi - leaplo + 1); i++) {
|
|
Serial.print(F("Select ROM Size: "));
|
|
Serial.print(i);
|
|
Serial.print(F(" = "));
|
|
Serial.print(LEAPSTER[i + leaplo]);
|
|
Serial.println(F("KB"));
|
|
}
|
|
Serial.print(F("Enter ROM Size: "));
|
|
while (Serial.available() == 0) {}
|
|
sizeROM = Serial.readStringUntil('\n');
|
|
Serial.println(sizeROM);
|
|
newleapsize = sizeROM.toInt() + leaplo;
|
|
if (newleapsize > leaphi) {
|
|
Serial.println(F("SIZE NOT SUPPORTED"));
|
|
Serial.println(FS(FSTRING_EMPTY));
|
|
goto setrom;
|
|
}
|
|
}
|
|
Serial.print(F("ROM Size = "));
|
|
Serial.print(LEAPSTER[newleapsize]);
|
|
Serial.println(F("KB"));
|
|
#endif
|
|
EEPROM_writeAnything(8, newleapsize);
|
|
leapsize = newleapsize;
|
|
}
|
|
|
|
void checkStatus_LEAP()
|
|
{
|
|
EEPROM_readAnything(8, leapsize);
|
|
if (leapsize > leaphi) {
|
|
leapsize = 1; // default 8M
|
|
EEPROM_writeAnything(8, leapsize);
|
|
}
|
|
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
display_Clear();
|
|
println_Msg(F("LEAPSTER READER"));
|
|
println_Msg(FS(FSTRING_CURRENT_SETTINGS));
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
print_Msg(F("TITLE: "));
|
|
println_Msg(ROMTitle);
|
|
print_Msg(F("VER: "));
|
|
println_Msg(ROMVersion);
|
|
print_Msg(FS(FSTRING_ROM_SIZE));
|
|
print_Msg(LEAPSTER[leapsize]);
|
|
println_Msg(F("MB"));
|
|
display_Update();
|
|
wait();
|
|
#else
|
|
Serial.print(F("TITLE: "));
|
|
Serial.println(ROMTitle);
|
|
Serial.print(F("VER: "));
|
|
Serial.println(ROMVersion);
|
|
Serial.print(FS(FSTRING_ROM_SIZE));
|
|
Serial.print(LEAPSTER[leapsize]);
|
|
Serial.println(F("MB"));
|
|
Serial.println(FS(FSTRING_EMPTY));
|
|
#endif
|
|
}
|
|
|
|
//******************************************
|
|
// FLASH SAVES
|
|
//******************************************
|
|
// FLASH 39VF040
|
|
// MR. PENCIL'S LEARN TO DRAW & WRITE
|
|
// TOP SECRET - PERSONAL BEESWAX
|
|
// FLASH IS BYTE MODE
|
|
// BYTE PIN IS A0 - SHIFT ADDRESS >> 1
|
|
|
|
void dataOut_LEAP()
|
|
{
|
|
DDRC = 0xFF;
|
|
DDRA = 0xFF;
|
|
}
|
|
|
|
void dataIn_LEAP()
|
|
{
|
|
DDRC = 0x00;
|
|
DDRA = 0x00;
|
|
}
|
|
|
|
void idFLASH_LEAP() // "BFD7" = 39VF040
|
|
{
|
|
int ID1 = 0;
|
|
int ID2 = 0;
|
|
dataOut_LEAP();
|
|
resetFLASH_LEAP();
|
|
write_flash_byte_LEAP(0x5555, 0xAA);
|
|
write_flash_byte_LEAP(0x2AAA, 0x55);
|
|
write_flash_byte_LEAP(0x5555, 0x90);
|
|
dataIn_LEAP();
|
|
ID1 = read_flash_byte_LEAP(0x0000);
|
|
ID2 = read_flash_byte_LEAP(0x0001);
|
|
dataOut_LEAP();
|
|
resetFLASH_LEAP();
|
|
dataIn_LEAP();
|
|
sprintf(flashid_str, "%02X%02X", ID1, ID2);
|
|
display_Clear();
|
|
print_Msg(F("Flash ID: "));
|
|
println_Msg(flashid_str);
|
|
display_Update();
|
|
}
|
|
|
|
void resetFLASH_LEAP()
|
|
{
|
|
write_flash_byte_LEAP(0x5555, 0xF0);
|
|
}
|
|
|
|
void eraseFLASH_LEAP()
|
|
{
|
|
write_flash_byte_LEAP(0x5555, 0xAA);
|
|
write_flash_byte_LEAP(0x2AAA, 0x55);
|
|
write_flash_byte_LEAP(0x5555, 0x80);
|
|
write_flash_byte_LEAP(0x5555, 0xAA);
|
|
write_flash_byte_LEAP(0x2AAA, 0x55);
|
|
write_flash_byte_LEAP(0x5555, 0x10);
|
|
}
|
|
|
|
void programFLASH_LEAP()
|
|
{
|
|
write_flash_byte_LEAP(0x5555, 0xAA);
|
|
write_flash_byte_LEAP(0x2AAA, 0x55);
|
|
write_flash_byte_LEAP(0x5555, 0xA0);
|
|
}
|
|
|
|
void statusFLASH_LEAP()
|
|
{
|
|
byte flashStatus = 1;
|
|
do {
|
|
flashStatus = ((PORTA & 0x80) >> 7); // D7 = PORTA7
|
|
_delay_us(4);
|
|
}
|
|
while (flashStatus == 1);
|
|
}
|
|
|
|
void readFLASH_LEAP()
|
|
{
|
|
createFolderAndOpenFile("LEAP", "SAVE", romName, "fla");
|
|
|
|
if(myFile) {
|
|
CE_HIGH;
|
|
OE_LOW;
|
|
FL_CE_LOW;
|
|
for (unsigned long address = 0x0; address < 0x80000; address += 512) { // 512K
|
|
if ((address % 0x8000) == 0) {
|
|
print_Msg(F("*"));
|
|
display_Update();
|
|
}
|
|
for (unsigned int x = 0; x < 512; x++) {
|
|
// CONSOLE READS ADDRESS 4X
|
|
do {
|
|
tempbyte = read_flash_byte_LEAP(address + x);
|
|
tempcheck = read_flash_byte_LEAP(address + x);
|
|
}
|
|
while (tempbyte != tempcheck);
|
|
sdBuffer[x] = tempbyte;
|
|
}
|
|
myFile.write(sdBuffer, 512);
|
|
}
|
|
myFile.flush();
|
|
myFile.close();
|
|
FL_CE_HIGH;
|
|
OE_HIGH;
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
printCRC(fileName, NULL, 0); // 512K
|
|
}
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
print_STR(press_button_STR, 1);
|
|
display_Update();
|
|
wait();
|
|
}
|
|
|
|
void writeFLASH_LEAP()
|
|
{
|
|
fileBrowser(F("Select FLASH File"));
|
|
sd.chdir();
|
|
sprintf(filePath, "%s/%s", filePath, fileName);
|
|
|
|
display_Clear();
|
|
println_Msg(F("Writing File: "));
|
|
println_Msg(filePath);
|
|
println_Msg(fileName);
|
|
display_Update();
|
|
|
|
//open file on sd card
|
|
if (myFile.open(filePath, O_READ)) {
|
|
CE_HIGH;
|
|
dataOut_LEAP();
|
|
eraseFLASH_LEAP();
|
|
statusFLASH_LEAP();
|
|
delay(100); // WORKS ~75 OK
|
|
for (unsigned long address = 0x0; address < 0x80000; address += 512) { // 512K
|
|
myFile.read(sdBuffer, 512);
|
|
if ((address % 0x10000) == 0) {
|
|
print_Msg(F("*"));
|
|
display_Update();
|
|
}
|
|
for (unsigned int x = 0; x < 512; x++) {
|
|
programFLASH_LEAP();
|
|
write_flash_byte_LEAP(address + x, sdBuffer[x]);
|
|
}
|
|
}
|
|
dataIn_LEAP();
|
|
myFile.close();
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
println_Msg(F("FLASH FILE WRITTEN!"));
|
|
display_Update();
|
|
}
|
|
else {
|
|
println_Msg(F("SD ERROR"));
|
|
display_Update();
|
|
}
|
|
sd.chdir(); // root
|
|
filePath[0] = '\0'; // Reset filePath
|
|
}
|
|
|
|
//******************************************
|
|
// EEPROM SAVES
|
|
//******************************************
|
|
// EEPROM 24LC02/24LC16
|
|
// 24LC02B = 256 BYTES
|
|
// 24LC16B = 2048 BYTES
|
|
// DORA THE EXPLORER - WILDLIFE RESCUE 24LC16B
|
|
// SCHOLASTIC MATH MISSIONS 24LC16B
|
|
|
|
// MODIFIED FOR COMPATIBILITY WITH ISSI EEPROM
|
|
// PET PALS ISSI 416A-2GLI = 24C16A
|
|
|
|
// START - SDA HIGH TO LOW WHEN SCL HIGH
|
|
void eepromStart_LEAP()
|
|
{
|
|
SCL_LOW;
|
|
SDA_LOW;
|
|
SCL_HIGH;
|
|
_delay_us(2);
|
|
SDA_HIGH;
|
|
_delay_us(2);
|
|
SDA_LOW;
|
|
_delay_us(2);
|
|
SCL_LOW;
|
|
_delay_us(2);
|
|
}
|
|
|
|
void eepromSet0_LEAP()
|
|
{
|
|
SCL_LOW;
|
|
SDA_LOW;
|
|
_delay_us(2);
|
|
SCL_HIGH;
|
|
_delay_us(5);
|
|
SCL_LOW;
|
|
_delay_us(2);
|
|
}
|
|
|
|
void eepromSet1_LEAP()
|
|
{
|
|
SCL_LOW;
|
|
SDA_LOW;
|
|
_delay_us(2);
|
|
SDA_HIGH;
|
|
_delay_us(2);
|
|
SCL_HIGH;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP; // ~500ns
|
|
SCL_LOW;
|
|
SDA_LOW;
|
|
_delay_us(2);
|
|
}
|
|
|
|
void eepromDevice_LEAP()
|
|
{
|
|
eepromSet1_LEAP();
|
|
eepromSet0_LEAP();
|
|
eepromSet1_LEAP();
|
|
eepromSet0_LEAP();
|
|
}
|
|
|
|
void eepromSetDeviceAddress_LEAP(unsigned long addrhi)
|
|
{
|
|
for (int i = 0; i < 3; i++) {
|
|
if ((addrhi >> 2) & 0x1) // Bit is HIGH
|
|
eepromSet1_LEAP();
|
|
else // Bit is LOW
|
|
eepromSet0_LEAP();
|
|
addrhi <<= 1; // rotate to the next bit
|
|
}
|
|
}
|
|
|
|
void eepromStatus_LEAP() // ACK
|
|
{
|
|
byte eepStatus = 1;
|
|
DDRH &= ~(1 << 4); // SDA to INPUT
|
|
SCL_LOW;
|
|
_delay_us(2);
|
|
SCL_HIGH;
|
|
_delay_us(5);
|
|
SCL_LOW;
|
|
do {
|
|
eepStatus = ((PINH & 0x10) >> 4); // SDA = PORTH4
|
|
}
|
|
while (eepStatus == 1);
|
|
DDRH |= (1 << 4); // SDA to OUTPUT
|
|
}
|
|
|
|
void eepromReadMode_LEAP()
|
|
{
|
|
eepromSet1_LEAP(); // READ
|
|
eepromStatus_LEAP(); // ACK
|
|
}
|
|
|
|
void eepromWriteMode_LEAP()
|
|
{
|
|
eepromSet0_LEAP(); // WRITE
|
|
eepromStatus_LEAP(); // ACK
|
|
}
|
|
|
|
void eepromReadData_LEAP()
|
|
{
|
|
DDRH &= ~(1 << 4); // SDA to INPUT
|
|
for (int i = 0; i < 8; i++) {
|
|
SCL_LOW;
|
|
SDA_LOW;
|
|
_delay_us(2);
|
|
SCL_HIGH;
|
|
eepbit[i] = ((PINH & 0x10) >> 4); // SDA = PORTH4
|
|
if (eepbit[i] == 1) {
|
|
SCL_LOW;
|
|
_delay_us(4);
|
|
}
|
|
else {
|
|
_delay_us(4);
|
|
SCL_LOW;
|
|
}
|
|
_delay_us(2);
|
|
}
|
|
DDRH |= (1 << 4); // SDA to OUTPUT
|
|
}
|
|
|
|
void eepromWriteData_LEAP(byte data)
|
|
{
|
|
for (int i = 0; i < 8; i++) {
|
|
if ((data >> 7) & 0x1) // Bit is HIGH
|
|
eepromSet1_LEAP();
|
|
else // Bit is LOW
|
|
eepromSet0_LEAP();
|
|
data <<= 1; // rotate to the next bit
|
|
}
|
|
eepromStatus_LEAP(); // ACK
|
|
}
|
|
|
|
// STOP - SDA LOW TO HIGH WHEN SCL HIGH
|
|
void eepromStop_LEAP()
|
|
{
|
|
SCL_LOW;
|
|
SDA_LOW;
|
|
_delay_us(1);
|
|
SCL_HIGH;
|
|
_delay_us(2);
|
|
SDA_HIGH;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
NOP; // ~500nS
|
|
SCL_LOW;
|
|
SDA_LOW;
|
|
}
|
|
|
|
void eepromSetAddress_LEAP(word address)
|
|
{
|
|
for (int i = 0; i < 8; i++) {
|
|
if ((address >> 7) & 0x1) // Bit is HIGH
|
|
eepromSet1_LEAP();
|
|
else // Bit is LOW
|
|
eepromSet0_LEAP();
|
|
address <<= 1; // rotate to the next bit
|
|
}
|
|
eepromStatus_LEAP(); // ACK
|
|
}
|
|
|
|
void readEepromByte_LEAP(word address)
|
|
{
|
|
word addrhi = address >> 8;
|
|
word addrlo = address & 0xFF;
|
|
eepromStart_LEAP(); // START
|
|
eepromDevice_LEAP(); // DEVICE [1010]
|
|
eepromSetDeviceAddress_LEAP(addrhi); // ADDR [A10..A8]
|
|
eepromWriteMode_LEAP();
|
|
eepromSetAddress_LEAP(addrlo);
|
|
eepromStart_LEAP(); // START
|
|
eepromDevice_LEAP(); // DEVICE [1010]
|
|
eepromSetDeviceAddress_LEAP(addrhi); // ADDR [A10..A8]
|
|
eepromReadMode_LEAP();
|
|
eepromReadData_LEAP();
|
|
eepromStop_LEAP(); // STOP
|
|
// OR 8 bits into byte
|
|
eeptemp = eepbit[0] << 7 | eepbit[1] << 6 | eepbit[2] << 5 | eepbit[3] << 4 | eepbit[4] << 3 | eepbit[5] << 2 | eepbit[6] << 1 | eepbit[7];
|
|
sdBuffer[addrlo] = eeptemp;
|
|
}
|
|
|
|
void writeEepromByte_LEAP(word address)
|
|
{
|
|
word addrhi = address >> 8;
|
|
word addrlo = address & 0xFF;
|
|
eeptemp = sdBuffer[addrlo];
|
|
eepromStart_LEAP(); // START
|
|
eepromDevice_LEAP(); // DEVICE [1010]
|
|
eepromSetDeviceAddress_LEAP(addrhi); // ADDR [A10-A8]
|
|
eepromWriteMode_LEAP(); // WRITE
|
|
eepromSetAddress_LEAP(addrlo);
|
|
eepromWriteData_LEAP(eeptemp);
|
|
eepromStop_LEAP(); // STOP
|
|
}
|
|
|
|
// Read EEPROM and save to the SD card
|
|
void readEEP_LEAP()
|
|
{
|
|
createFolderAndOpenFile("LEAP", "SAVE", romName, "eep");
|
|
|
|
if (myFile) {
|
|
for (word currByte = 0; currByte < 2048; currByte += 256) {
|
|
for (int i = 0; i < 256; i++) {
|
|
readEepromByte_LEAP(currByte + i);
|
|
}
|
|
myFile.write(sdBuffer, 256);
|
|
}
|
|
// 24LC02
|
|
// for (word currByte = 0; currByte < 256; currByte++) {
|
|
// readEepromByte_LEAP(currByte);
|
|
// }
|
|
// myFile.write(sdBuffer, 256);
|
|
myFile.close();
|
|
|
|
printCRC(fileName, NULL, 0); // 2048
|
|
}
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
print_STR(press_button_STR, 1);
|
|
display_Update();
|
|
wait();
|
|
}
|
|
|
|
void writeEEP_LEAP()
|
|
{
|
|
fileBrowser(F("Select EEPROM File"));
|
|
sd.chdir();
|
|
sprintf(filePath, "%s/%s", filePath, fileName);
|
|
|
|
display_Clear();
|
|
println_Msg(F("Writing File: "));
|
|
// println_Msg(filePath);
|
|
println_Msg(fileName);
|
|
display_Update();
|
|
|
|
//open file on sd card
|
|
if (myFile.open(filePath, O_READ)) {
|
|
WP_LOW;
|
|
for (word currByte = 0; currByte < 2048; currByte += 256) {
|
|
myFile.read(sdBuffer, 256);
|
|
for (int i = 0; i < 256; i++) {
|
|
writeEepromByte_LEAP(currByte + i);
|
|
delay(50);
|
|
}
|
|
print_Msg(F("*"));
|
|
display_Update();
|
|
}
|
|
WP_HIGH;
|
|
myFile.close();
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
println_Msg(F("EEPROM FILE WRITTEN!"));
|
|
display_Update();
|
|
}
|
|
else {
|
|
println_Msg(F("SD ERROR"));
|
|
display_Update();
|
|
}
|
|
sd.chdir(); // root
|
|
filePath[0] = '\0'; // Reset filePath
|
|
}
|
|
|
|
//******************************************
|
|
// CART SELECT CODE
|
|
//******************************************
|
|
|
|
void setCart_LEAP()
|
|
{
|
|
//go to root
|
|
sd.chdir();
|
|
|
|
byte gameSize;
|
|
|
|
// Select starting letter
|
|
//byte myLetter = starting_letter();
|
|
|
|
// Open database
|
|
if (myFile.open("leapster.txt", O_READ)) {
|
|
// seek_first_letter_in_database(myFile, myLetter);
|
|
|
|
if(checkCartSelection(myFile, &readDataLineSingleDigit, &gameSize)) {
|
|
EEPROM_writeAnything(8, gameSize);
|
|
}
|
|
} else {
|
|
print_FatalError(FS(FSTRING_DATABASE_FILE_NOT_FOUND));
|
|
}
|
|
}
|
|
#endif
|