/*
 * Original Benchmark code from : https://www.instructables.com/Select-SD-Interface-for-ESP32/ by 陳亮
 * 
 * Updated by James Wallis 2022
 * Connect the SD card to the following pins: *
 * SD Card | ESP32
 *    CMD      15
 *    VSS      GND
 *    VDD      3.3V
 *    CLK      14
 *    VSS      GND
 *    D0       2  //some notes say to add 1K pull up after flashing, seems to work without it.
 *    D1       4  //only for 4bit
 *    D2       12 //only for 4bit
 *    D3       13 //only for 4bit
 */
// Note: 
#define SD_MODE_4pin
#define SD_MODE_1pin
//#define SD_MODE_SPI
 
#include "FS.h"
#include "SD.h"
#include "SD_MMC.h"
#include "core_version.h"

int TEST_FILE_SIZE = (1024 * 1024); // 1 MB
//int  TEST_FILE_SIZE =(64* 1024); // 64K for when it gets so very slow.

void TestSDFile(fs::FS &fs, const char *path, uint8_t *buf, int len)
{
  // First do write benchmark
  unsigned long start_time = millis();
  File file = fs.open(path, FILE_WRITE);
  if (!file) { Serial.println("Failed to open file for writing"); return;  }  
  int  loop = TEST_FILE_SIZE / len;
  Serial.printf("%5d passes @ %2dKB = %d\t",loop,len/1024,TEST_FILE_SIZE);
  while (loop--) { if (!file.write(buf, len)) {Serial.println("Write failed");return; }}
  file.flush();
  file.close();
  unsigned long time_used = millis() - start_time;
  Serial.printf("%5d\t",  int(TEST_FILE_SIZE / time_used));
  
  // Secondly do read benchmark
  start_time = millis();
  file = fs.open(path);
  if (!file) {Serial.println("Failed to open file for reading"); return; }
  loop = TEST_FILE_SIZE / len;    
  while (loop--)  { if (!file.read(buf, len)) { Serial.println("Read failed"); return; }}     
  file.close();
  time_used = millis() - start_time;
  Serial.printf("%5d\r\n",  int(TEST_FILE_SIZE / time_used));
}  


void testIO(fs::FS &fs)
{
  uint8_t *buf = (uint8_t*) malloc(64 * 1024);   /* malloc will not reset all bytes to zero, so it is a random data */
  TestSDFile(fs, "/test_1k.bin", buf, 1024); 
  TestSDFile(fs, "/test_2k.bin", buf, 2 * 1024);
  TestSDFile(fs, "/test_4k.bin", buf, 4 * 1024);
  TestSDFile(fs, "/test_8k.bin", buf, 8 * 1024);
  TestSDFile(fs, "/test_16k.bin", buf, 16 * 1024);
  TestSDFile(fs, "/test_32k.bin", buf, 32 * 1024);
  TestSDFile(fs, "/test_64k.bin", buf, 64 * 1024);  
  Serial.println("Done.");
}

void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.println("5 seconds to clear screen and insert SD");
  delay(5000);
  Serial.printf("SDK Version : %s    Arduino Version : %s\r\n",ESP.getSdkVersion(),ARDUINO_ESP32_RELEASE);
 
#ifdef SD_MODE_4pin
  Serial.println("4bit");
  if (!SD_MMC.begin("/sdcard", false)) Serial.println("Card Mount Failed");
  else testIO(SD_MMC);
#endif

#ifdef SD_MODE_1pin
  Serial.println("1bit");
  if (!SD_MMC.begin("/sdcard", true)) Serial.println("Card Mount Failed");
  else testIO(SD_MMC);
#endif

#ifdef SD_MODE_SPI
  Serial.println("SPI_HSPI"); 
  SPIClass spi = SPIClass(HSPI);  
  spi.begin(14 , 2  , 15  , 13   );// spi.begin(SCK,MISO,MOSI,CS);
 // SD.begin defaults to 4MHz, 
  if (!SD.begin(13,spi,40000000)) Serial.println("Card Mount Failed");
  else testIO(SD); 
#endif

}

void loop() {}
