/******************************************
  SUPER FAMICOM SUFAMI TURBO MODULE
******************************************/
#if (defined(ENABLE_ST) && defined(ENABLE_SNES))

/******************************************
  Menu
*****************************************/
// Sufami Turbo menu items
static const char stMenuItem1[] PROGMEM = "Read cart in Slot A";
static const char stMenuItem2[] PROGMEM = "Read cart in Slot B";
static const char* const menuOptionsST[] PROGMEM = { stMenuItem1, stMenuItem2, FSTRING_RESET };

void stMenu() {
  // Create ST menu with title and 3 options to choose from
  unsigned char mainMenu;
  convertPgm(menuOptionsST, 3);
  mainMenu = question_box(F("Sufami Turbo"), menuOptions, 3, 0);

  // Wait for user choice to come back from the question box menu
  switch (mainMenu) {
    // Read cart in ST slot A
    case 0:
      readSlot(0);
      break;

    // Read cart in ST slot B
    case 1:
      readSlot(1);
      break;

    // Reset
    case 2:
      resetArduino();
      break;
  }
}

/******************************************
   Setup
 *****************************************/
void setup_ST() {
  // Request 5V
  setVoltage(VOLTS_SET_5V);

  // Set cicrstPin(PG1) to Output
  DDRG |= (1 << 1);
  // Output a high signal until we're ready to start
  PORTG |= (1 << 1);
  // Set cichstPin(PG0) to Input
  DDRG &= ~(1 << 0);

  // Set Address Pins to Output
  //A0-A7
  DDRF = 0xFF;
  //A8-A15
  DDRK = 0xFF;
  //BA0-BA7
  DDRL = 0xFF;
  //PA0-PA7
  DDRA = 0xFF;

  // Set Control Pins to Output RST(PH0) CS(PH3) WR(PH5) RD(PH6)
  DDRH |= (1 << 0) | (1 << 3) | (1 << 5) | (1 << 6);
  // Switch RST(PH0) and WR(PH5) to HIGH
  PORTH |= (1 << 0) | (1 << 5);
  // Switch CS(PH3) and RD(PH6) to LOW
  PORTH &= ~((1 << 3) | (1 << 6));
  // Set Refresh(PE5) to Output
  DDRE |= (1 << 5);
  // Switch Refresh(PE5) to LOW (needed for SA-1)
  PORTE &= ~(1 << 5);
  // Set CPU Clock(PH1) to Output
  DDRH |= (1 << 1);
  // Set IRQ(PH4) to Input
  DDRH &= ~(1 << 4);
  // Set expand(PG5) to Input
  DDRG &= ~(1 << 5);
  // Set Data Pins (D0-D7) to Input
  DDRC = 0x00;
  // Unused pins
  // Set wram(PE4) to Output
  DDRE |= (1 << 4);
  // Set pawr(PJ1) to Output
  DDRJ |= (1 << 1);
  // Set pard(PJ0) to Output
  DDRJ |= (1 << 0);

  //Check if Sufami Turbo adapter is inserted
  if (!getHeader(0)) {
    display_Clear();
    println_Msg(F("Sufami Turbo adapter"));
    println_Msg(F("was not found."));
    display_Update();
    wait();
    resetArduino();
  }
}

/******************************************
  ROM Functions
******************************************/
// Verify if 'BANDAI' header is present in specified bank
bool getHeader(unsigned int bank) {
  byte snesHeader[16];
  PORTL = bank;

  // Read first bytes
  for (uint16_t c = 0, currByte = 0; c < 16; c++, currByte++) {
    PORTF = (currByte & 0xFF);
    PORTK = ((currByte >> 8) & 0xFF);
    NOP;
    NOP;
    NOP;
    NOP;
    NOP;
    NOP;
    snesHeader[c] = PINC;
  }

  // Format internal name
  buildRomName(romName, &snesHeader[0], 14);

  // Check if 'BANDAI' header is present
  if (strncmp(romName, "BANDAI SFC-ADX", 14) == 0)
    return(1);
  else
    return(0);
} 

// Select the slot to use and detect cart size
void readSlot(bool cartSlot) {
  // Set control
  dataIn();
  controlIn_SNES();
  sd.chdir("/");
  display_Clear();

  if(!cartSlot) {            // Slot A was selected
    if (getHeader(32)) {     // Look for a cart in slot A
      if (getHeader(48))     // Look for mirrored data in slot A
        readRom_ST(32,48);   // Dump 512KB cart
      else                   
        readRom_ST(32,64);   // Dump 1MB cart
    }
    else {
      println_Msg(F("No cart detected in Slot A"));
      display_Update();
      wait();
    }
  }
  else {                      // Slot B was selected
    if (getHeader(64)) {      // Look for a cart in slot B
      if (getHeader(80))      // Look for mirrored data in slot B
        readRom_ST(64,80);    // Dump 512KB cart
      else
        readRom_ST(64,96);    // Dump 1MB cart
    }
    else {
      println_Msg(F("No cart detected in Slot B"));
      display_Update();
      wait();
    }
  }
}

// Read ST rom to SD card
void readRom_ST(unsigned int bankStart, unsigned int bankEnd) {
  // create a new folder to save rom file
  createFolderAndOpenFile("ST", "ROM", "SUFAMI_TURBO", "st");

  // Read specified banks
  readLoRomBanks(bankStart + 0x80, bankEnd + 0x80, &myFile);

  // Close file:
  myFile.close();

  // Compare dump CRC with db values
  compareCRC("st.txt", 0, 1, 0);
  
  println_Msg(FS(FSTRING_EMPTY));
  print_STR(press_button_STR, 1);
  display_Update();
  wait();
}
#endif

//******************************************
// End of File
//******************************************
