Teensyduino File System Integration, including MTP and MSC

Here is a version of the mediaPresent that I think works for 3.6...
...
The important part is the #if defined for the MK...

I also pushed up the MTP test sketch I put calls into this for...

I have not done anything with the performance issues with T4 yet...
Right now on T3.6 the elapsedMicros when installed shows about 20
When not in, about 1780...

Edit: Also runs on T3.5

Just gave it a try with a T3.6 and works now to play with MTP
 
Tested change on Teensy MicroMod and Teensy 41:
Teensy 4.1 Results with the following configuration:
Code:
store:0 storage:10001 name:sdio fs:2000cad8
store:1 storage:20001 name:RAM0 fs:2000c8e4
store:2 storage:30001 name:RAM1 fs:2000c9b0
store:3 storage:40001 name:PROGM fs:2000c818
store:4 storage:50001 name:sflash5 fs:2000d478
store:5 storage:60001 name:sflash6 fs:2000d558
store:6 storage:70001 name:WINBOND1G fs:2000c3cc
store:7 storage:80001 name:WINBOND2G fs:2000c4c0
store:8 storage:90001 name:MSC0-exFAT-128 fs:2000a370
Check SDIO 0 0 3000883
Check SDIO 0 0 3000882
1. Takes a long time for drive to show in windows explorer
2. Only the Ram0 drive shows as well as a RED Sdio card. No other devices appear in explorer even though they still appear in drive list.
3. Card is detected but when I do a explorer refresh nothing appears again

Same thing happens with the Teensy Micromod. Testing is done with a modified MTP_TEST_INTEGRITY Sketch:
Code:
#include <MTP_Teensy.h>

//---------------------------------------------------
// Select drives you want to create
//---------------------------------------------------
#define USE_SD  1         // SDFAT based SDIO and SPI
#ifdef ARDUINO_TEENSY41
#define USE_LFS_RAM 1     // T4.1 PSRAM (or RAM)
#else
#define USE_LFS_RAM 0     // T4.1 PSRAM (or RAM)
#endif
#ifdef ARDUINO_TEENSY_MICROMOD
#define USE_LFS_QSPI 0    // T4.1 QSPI
#define USE_LFS_PROGM 1   // T4.4 Progam Flash
#define USE_LFS_SPI 0     // SPI Flash
#define USE_LFS_NAND 0
#define USE_LFS_QSPI_NAND 0
#define USE_LFS_FRAM 0
#else
#define USE_LFS_QSPI 0    // T4.1 QSPI
#define USE_LFS_PROGM 1   // T4.4 Progam Flash
#define USE_LFS_SPI 1     // SPI Flash
#define USE_LFS_NAND 1
#define USE_LFS_QSPI_NAND 0
#define USE_LFS_FRAM 0
#endif
#define USE_MSC 1    // set to > 0 experiment with MTP (USBHost.t36 + mscFS)
#define USE_SW_PU  1 //set to 1 if SPI devices do not have PUs,
                     // https://www.pjrc.com/better-spi-bus-design-in-3-steps/


#define DBGSerial Serial
FS *myfs;
File dataFile, myFile;  // Specifes that dataFile is of File type
int record_count = 0;
bool write_data = false;
uint8_t current_store = 0;
int index_sdio_storage = -1;
int index_sdspi_storage = -1;

#define BUFFER_SIZE_INDEX 128
uint8_t write_buffer[BUFFER_SIZE_INDEX];
#define buffer_mult 4
uint8_t buffer_temp[buffer_mult*BUFFER_SIZE_INDEX];

int bytesRead;
uint32_t drive_index = 0;

// These can likely be left unchanged
#define MYBLKSIZE 2048 // 2048
#define SLACK_SPACE  40960 // allow for overhead slack space :: WORKS on FLASH {some need more with small alloc units}
#define size_bigfile 1024*1024*24  //24 mb file

// Various Globals
const uint32_t lowOffset = 'a' - 'A';
const uint32_t lowShift = 13;
uint32_t errsLFS = 0, warnLFS = 0; // Track warnings or Errors
uint32_t lCnt = 0, LoopCnt = 0; // loop counters
uint64_t rdCnt = 0, wrCnt = 0; // Track Bytes Read and Written
int filecount = 0;
int loopLimit = 0; // -1 continuous, otherwise # to count down to 0
bool bWriteVerify = true;  // Verify on Write Toggle
File file3; // Single FILE used for all functions


//=============================================================================
// Global defines
//=============================================================================

MTPStorage storage;
MTPD    mtpd(&storage);

//=============================================================================
// MSC & SD classes
//=============================================================================
#if USE_SD==1
#define USE_BUILTIN_SDCARD
#if defined(USE_BUILTIN_SDCARD) && defined(BUILTIN_SDCARD)
#define CS_SD  BUILTIN_SDCARD
#else
#define CS_SD 10
#endif
#endif


// SDClasses 
#if USE_SD==1
#include <SD.h>
  // edit SPI to reflect your configuration (following is for T4.1)
  #define SD_MOSI 11
  #define SD_MISO 12
  #define SD_SCK  13

  #define SPI_SPEED SD_SCK_MHZ(25)  // adjust to sd card 
  elapsedMillis elapsed_millis_since_last_sd_check = 0;
  #define TIME_BETWEEN_SD_CHECKS_MS 1000
  bool sdio_previously_present;

  #if defined (BUILTIN_SDCARD)
    const char *sd_str[]={"sdio","sd1"}; // edit to reflect your configuration
    const int cs[] = {BUILTIN_SDCARD,10}; // edit to reflect your configuration
  #else
    const char *sd_str[]={"sd1"}; // edit to reflect your configuration
    const int cs[] = {10}; // edit to reflect your configuration
  #endif
  const int nsd = sizeof(sd_str)/sizeof(const char *);
  
SDClass sdx[nsd];
#endif

// =======================================================================
// Set up MSC Drive file systems on different storage media
// =======================================================================
#if USE_MSC == 1
#include <USBHost_t36.h>
#include <USBHost_ms.h>

// Add USBHost objectsUsbFs
USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
USBHub hub(myusb);

// MSC objects.
msController drive1(myusb);
msController drive2(myusb);
msController drive3(myusb);
msController drive4(myusb);

msFilesystem msFS1(myusb);
msFilesystem msFS2(myusb);
msFilesystem msFS3(myusb);
msFilesystem msFS4(myusb);
msFilesystem msFS5(myusb);

// Quick and dirty
msFilesystem *pmsFS[] = {&msFS1, &msFS2, &msFS3, &msFS4, &msFS5};
#define CNT_MSC  (sizeof(pmsFS)/sizeof(pmsFS[0]))
uint32_t pmsfs_store_ids[CNT_MSC] = {0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL};
char  pmsFS_display_name[CNT_MSC][20];

msController *pdrives[] {&drive1, &drive2, &drive3, &drive4};
#define CNT_DRIVES  (sizeof(pdrives)/sizeof(pdrives[0]))
bool drive_previous_connected[CNT_DRIVES] = {false, false, false, false};
#endif


// =======================================================================
// Set up LittleFS file systems on different storage media
// =======================================================================

#if USE_LFS_FRAM == 1 || USE_LFS_NAND == 1 || USE_LFS_PROGM == 1 || USE_LFS_QSPI == 1 || USE_LFS_QSPI_NAND == 1 || \
  USE_LFS_RAM == 1 || USE_LFS_SPI == 1
#include <LittleFS.h>
#endif

#if USE_LFS_RAM==1
const char *lfs_ram_str[] = {"RAM0","RAM1"};  // edit to reflect your configuration
const int lfs_ram_size[] = {200000, 4000000}; // edit to reflect your configuration
const int nfs_ram = sizeof(lfs_ram_str)/sizeof(const char *);
LittleFS_RAM ramfs[nfs_ram];
#endif

#if USE_LFS_QSPI==1
const char *lfs_qspi_str[]={"QSPI"};     // edit to reflect your configuration
const int nfs_qspi = sizeof(lfs_qspi_str)/sizeof(const char *);
LittleFS_QSPIFlash qspifs[nfs_qspi];
#endif

#if USE_LFS_PROGM==1
const char *lfs_progm_str[]={"PROGM"};     // edit to reflect your configuration
const int lfs_progm_size[] = {1000000}; // edit to reflect your configuration
const int nfs_progm = sizeof(lfs_progm_str)/sizeof(const char *);
LittleFS_Program progmfs[nfs_progm];
#endif

#if USE_LFS_SPI==1
const char *lfs_spi_str[]={"sflash5", "sflash6"}; // edit to reflect your configuration
//const char *lfs_spi_str[]={"Q64", "Q128", "Q512"}; // edit to reflect your configuration
const int lfs_cs[] = {5, 6 }; // edit to reflect your configuration
//const int lfs_cs[] = {3, 4, 5}; // edit to reflect your configuration
const int nfs_spi = sizeof(lfs_spi_str)/sizeof(const char *);
LittleFS_SPIFlash spifs[nfs_spi];
#endif

#if USE_LFS_NAND == 1
const char *nspi_str[]={"WINBOND1G", "WINBOND2G"};     // edit to reflect your configuration
const int nspi_cs[] = {3, 4}; // edit to reflect your configuration
const int nspi_nsd = sizeof(nspi_cs)/sizeof(int);
LittleFS_SPINAND nspifs[nspi_nsd]; // needs to be declared if LittleFS is used in storage.h
#endif

#if USE_LFS_QSPI_NAND == 1
const char *qnspi_str[]={"WIN-M02"};     // edit to reflect your configuration
const int qnspi_nsd = sizeof(qnspi_str)/sizeof(const char *);
LittleFS_QPINAND qnspifs[qnspi_nsd]; // needs to be declared if LittleFS is used in storage.h
#endif

#if USE_LFS_FRAM == 1
const char *qfspi_str[]={"Fram1", "Fram2", "Fram3"};     // edit to reflect your configuration
const int qfspi_cs[] = {3,4,5}; // edit to reflect your configuration
const int qfspi_nsd = sizeof(qfspi_cs)/sizeof(int);
LittleFS_SPIFram qfspifs[qfspi_nsd]; // needs to be declared if LittleFS is used in storage.h
#endif

void storage_configure()
{
  DateTimeFields date;
  breakTime(Teensy3Clock.get(), date);
  const char *monthname[12]={
    "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
  DBGSerial.printf("Date: %u %s %u %u:%u:%u\n",
    date.mday, monthname[date.mon], date.year+1900, date.hour, date.min, date.sec);

    
  #if USE_SD==1
    #if defined SD_SCK
      SPI.setMOSI(SD_MOSI);
      SPI.setMISO(SD_MISO);
      SPI.setSCK(SD_SCK);
    #endif

    for(int ii=0; ii<nsd; ii++)
    { 
      #if defined(BUILTIN_SDCARD)
        if(cs[ii] == BUILTIN_SDCARD)
        {
          DBGSerial.printf("!! Try installing BUILTIN SD Card");
          sdio_previously_present = sdx[ii].begin(BUILTIN_SDCARD);
          index_sdio_storage = storage.addFilesystem(sdx[ii], sd_str[ii]);
          if(!sdio_previously_present)
          { 
            Serial.printf("SDIO Storage %d %d %s failed or missing",ii,cs[ii],sd_str[ii]);  Serial.println();
          }
          else
          {
            uint64_t totalSize = sdx[ii].totalSize();
            uint64_t usedSize  = sdx[ii].usedSize();
            Serial.printf("SDIO Storage %d %d %s ",ii,cs[ii],sd_str[ii]); 
            Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
          }
        }
        else if(cs[ii]<BUILTIN_SDCARD)
      #endif
      {
        pinMode(cs[ii],OUTPUT); digitalWriteFast(cs[ii],HIGH);
        if(!sdx[ii].begin(cs[ii])) 
        { Serial.printf("SD Storage %d %d %s failed or missing",ii,cs[ii],sd_str[ii]);  Serial.println();
        }
        else
        {
          storage.addFilesystem(sdx[ii], sd_str[ii]);
          uint64_t totalSize = sdx[ii].totalSize();
          uint64_t usedSize  = sdx[ii].usedSize();
          Serial.printf("SD Storage %d %d %s ",ii,cs[ii],sd_str[ii]); 
          Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      }
    }
    elapsed_millis_since_last_sd_check = 0;
    #endif

#if USE_LFS_RAM==1
  for (int ii=0; ii<nfs_ram;ii++) {
    if (!ramfs[ii].begin(lfs_ram_size[ii])) {
      DBGSerial.printf("Ram Storage %d %s failed or missing",ii,lfs_ram_str[ii]);
      DBGSerial.println();
    } else {
      storage.addFilesystem(ramfs[ii], lfs_ram_str[ii]);
      uint64_t totalSize = ramfs[ii].totalSize();
      uint64_t usedSize  = ramfs[ii].usedSize();
      DBGSerial.printf("RAM Storage %d %s %llu %llu\n", ii, lfs_ram_str[ii],
        totalSize, usedSize);
    }
  }
#endif

#if USE_LFS_PROGM==1
  for (int ii=0; ii<nfs_progm;ii++) {
    if (!progmfs[ii].begin(lfs_progm_size[ii])) {
      DBGSerial.printf("Program Storage %d %s failed or missing",ii,lfs_progm_str[ii]);
      DBGSerial.println();
    } else {
      storage.addFilesystem(progmfs[ii], lfs_progm_str[ii]);
      uint64_t totalSize = progmfs[ii].totalSize();
      uint64_t usedSize  = progmfs[ii].usedSize();
      DBGSerial.printf("Program Storage %d %s %llu %llu\n", ii, lfs_progm_str[ii],
        totalSize, usedSize);
    }
  }
#endif

#if USE_LFS_QSPI==1
  for(int ii=0; ii<nfs_qspi;ii++) {
    if(!qspifs[ii].begin()) {
      DBGSerial.printf("QSPI Storage %d %s failed or missing",ii,lfs_qspi_str[ii]);
      DBGSerial.println();
    } else {
      storage.addFilesystem(qspifs[ii], lfs_qspi_str[ii]);
      uint64_t totalSize = qspifs[ii].totalSize();
      uint64_t usedSize  = qspifs[ii].usedSize();
      DBGSerial.printf("QSPI Storage %d %s %llu %llu\n", ii, lfs_qspi_str[ii], totalSize, usedSize);
    }
  }
#endif

#if USE_LFS_SPI==1
  for (int ii=0; ii<nfs_spi;ii++) {
    if (USE_SW_PU == 1) {
      pinMode(lfs_cs[ii],OUTPUT);
      digitalWriteFast(lfs_cs[ii],HIGH);
    }
    if (!spifs[ii].begin(lfs_cs[ii], SPI)) {
      DBGSerial.printf("SPIFlash Storage %d %d %s failed or missing",ii,lfs_cs[ii],lfs_spi_str[ii]);      DBGSerial.println();
    } else {
      storage.addFilesystem(spifs[ii], lfs_spi_str[ii]);
      uint64_t totalSize = spifs[ii].totalSize();
      uint64_t usedSize  = spifs[ii].usedSize();
      DBGSerial.printf("SPIFlash Storage %d %d %s %llu %llu\n", ii, lfs_cs[ii], lfs_spi_str[ii],
        totalSize, usedSize);
    }
  }
#endif
#if USE_LFS_NAND == 1
  for(int ii=0; ii<nspi_nsd;ii++) {
    if (USE_SW_PU == 1) {
      pinMode(nspi_cs[ii],OUTPUT);
      digitalWriteFast(nspi_cs[ii],HIGH);
    }
    if(!nspifs[ii].begin(nspi_cs[ii], SPI)) {
      DBGSerial.printf("SPIFlash NAND Storage %d %d %s failed or missing",ii,nspi_cs[ii],nspi_str[ii]);
      DBGSerial.println();
    } else {
      storage.addFilesystem(nspifs[ii], nspi_str[ii]);
      uint64_t totalSize = nspifs[ii].totalSize();
      uint64_t usedSize  = nspifs[ii].usedSize();
      DBGSerial.printf("Storage %d %d %s %llu %llu\n", ii, nspi_cs[ii], nspi_str[ii],
        totalSize, usedSize);
    }
  }
#endif

#if USE_LFS_QSPI_NAND == 1
  for(int ii=0; ii<qnspi_nsd;ii++) {
    if(!qnspifs[ii].begin()) {
       DBGSerial.printf("QSPI NAND Storage %d %s failed or missing",ii,qnspi_str[ii]); DBGSerial.println();
    } else {
      storage.addFilesystem(qnspifs[ii], qnspi_str[ii]);
      uint64_t totalSize = qnspifs[ii].totalSize();
      uint64_t usedSize  = qnspifs[ii].usedSize();
      DBGSerial.printf("Storage %d %s %llu %llu\n", ii, qnspi_str[ii], totalSize, usedSize);
    }
  }
#endif


/*
#if USE_LFS_FRAM == 1
const char *qfspi_str[]={"Fram1"};     // edit to reflect your configuration
const int qfspi_cs[] = {6}; // edit to reflect your configuration
const int qfspi_nsd = sizeof(qfspi_cs)/sizeof(int);
LittleFS_SPIFram qfspifs[qfspi_nsd]; // needs to be declared if LittleFS is used in storage.h
#endif
 */
#if USE_LFS_FRAM==1
  for (int ii=0; ii<qfspi_nsd;ii++) {
    if (USE_SW_PU == 1) {
      pinMode(qfspi_cs[ii],OUTPUT);
      digitalWriteFast(qfspi_cs[ii],HIGH);
    }
    if (!qfspifs[ii].begin(qfspi_cs[ii], SPI)) {
      DBGSerial.printf("SPIFlash Storage %d %d %s failed or missing",ii,qfspi_cs[ii],qfspi_str[ii]);
      DBGSerial.println();
    } else {
      storage.addFilesystem(qfspifs[ii], qfspi_str[ii]);
      uint64_t totalSize = qfspifs[ii].totalSize();
      uint64_t usedSize  = qfspifs[ii].usedSize();
      DBGSerial.printf("SPIFlash Storage %d %d %s %llu %llu\n", ii, qfspi_cs[ii], qfspi_str[ii],
        totalSize, usedSize);
    }
  }
#endif

}

void setup()
{

  // Open serial communications and wait for port to open:
#if defined(USB_MTPDISK_SERIAL)
  while (!Serial && millis() < 5000) {
    // wait for serial port to connect.
  }
#else
  //while(!DBGSerial.available()); // comment if you do not want to wait for
                                   // terminal (otherwise press any key to continue)
  while (!Serial && !DBGSerial.available() && millis() < 5000) 
  //myusb.Task(); // or third option to wait up to 5 seconds and then continue
#endif

  DBGSerial.print(CrashReport);
  DBGSerial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  delay(3000);
  

  //This is mandatory to begin the mtpd session.
  mtpd.begin();
  
  storage_configure();

  #if USE_MSC == 1
  myusb.begin();
  DBGSerial.print("Initializing MSC Drives ...");
  DBGSerial.println("\nInitializing USB MSC drives...");
  DBGSerial.println("MSC and MTP initialized.");
  checkMSCChanges();
  #endif
  DBGSerial.println("\nSetup done");
  menu();
}

int ReadAndEchoSerialChar() {
  int ch = DBGSerial.read();
  if (ch >= ' ') DBGSerial.write(ch);
  return ch;
}

uint8_t storage_index = '0';
void loop()
{
  if ( DBGSerial.available() ) {
    uint8_t command = DBGSerial.read();
    int ch = DBGSerial.read();
    if ('2'==command) storage_index = CommandLineReadNextNumber(ch, 0);
    while (ch == ' ') ch = DBGSerial.read();

    uint32_t fsCount;
    switch (command) {
    case '1':
      // first dump list of storages:
      fsCount = storage.getFSCount();
      DBGSerial.printf("\nDump Storage list(%u)\n", fsCount);
      for (uint32_t ii = 0; ii < fsCount; ii++) {
        if ( ii == storage_index )
          DBGSerial.print("STORE");
        else
          DBGSerial.print("store");
        DBGSerial.printf(":%u storage:%x name:%s fs:%x\n", ii, mtpd.Store2Storage(ii),
          storage.getStoreName(ii), (uint32_t)storage.getStoreFS(ii));
      }
      //DBGSerial.println("\nDump Index List");
      //storage.dumpIndexList();
      break;
    case '2':
      if (storage_index < storage.getFSCount()) {
        DBGSerial.printf("Storage Index %u Name: %s Selected\n", storage_index,
          storage.getStoreName(storage_index));
        myfs = storage.getStoreFS(storage_index);
        current_store = storage_index;
      } else {
        DBGSerial.printf("Storage Index %u out of range\n", storage_index);
      }
      break;

    case 'l': listFiles(); break;
    case 'e': eraseFiles(); break;
    case 's':
      DBGSerial.println("\nLogging Data!!!");
      write_data = true;   // sets flag to continue to write data until new command is received
      // opens a file or creates a file if not present,  FILE_WRITE will append data to
      // to the file created.
      dataFile = myfs->open("datalog.txt", FILE_WRITE);
      logData();
      break;
    case 'f': 
      format3();
      break;
    case 'x': stopLogging(); break;
    case'r':
      DBGSerial.println("Reset");
      mtpd.send_DeviceResetEvent();
      break;
    case 'd': dumpLog(); break;
    case 'b':
      bigFile( 0 ); // delete
      command = 0;
      break;
    case 'B':
      bigFile( 1 ); // CREATE
      command = 0;
      break;
    case 't':
      bigFile2MB( 0 ); // CREATE
      command = 0;
      break;
    case 'S':
      bigFile2MB( 1 ); // CREATE
      command = 0;
     break;
    case 'n': // No Verify on write
      bWriteVerify = !bWriteVerify;
      bWriteVerify ? DBGSerial.print(" Write Verify on: ") : DBGSerial.print(" Write Verify off: ");
     command = 0;
      break;
    case 'i':
      writeIndexFile();
      break;
    case 'R':
      DBGSerial.print(" RESTART Teensy ...");
      delay(100);
      SCB_AIRCR = 0x05FA0004;
      break;
    
    case '\r':
    case '\n':
    case 'h': menu(); break;
    }
    while (DBGSerial.read() != -1) ; // remove rest of characters.
  } else {
    #if USE_MSC == 1
    checkMSCChanges();
    #endif
    #if USE_SD == 1
    checkSDChanges();
    #endif
    mtpd.loop();
  }

  if (write_data) logData();
}

#if USE_SD == 1
void checkSDChanges()  {
    for(uint8_t ii=0; ii<nsd; ii++) {
      if(cs[ii] == BUILTIN_SDCARD) {
        if (elapsed_millis_since_last_sd_check >= TIME_BETWEEN_SD_CHECKS_MS) {
          elapsed_millis_since_last_sd_check = 0; 
          elapsedMicros em = 0;
          bool sdio_present = sdx[ii].mediaPresent();
          Serial.printf("Check SDIO %u %u %u\n", sdio_present, sdio_previously_present, (uint32_t)em);
          if (sdio_present != sdio_previously_present) {
            sdio_previously_present = sdio_present;
            if (sdio_present) DBGSerial.printf("###SD Media inserted(%d)\n", index_sdio_storage);
            else Serial.printf("###SD Media Removed(%d)\n", index_sdio_storage);
            mtpd.send_DeviceResetEvent();
          }
        }
      }
    }
}
#endif

#if USE_MSC == 1
void checkMSCChanges() {
  myusb.Task();

  USBMSCDevice mscDrive;
  PFsLib pfsLIB;
  for (uint8_t i=0; i < CNT_DRIVES; i++) {
    if (*pdrives[i]) {
      if (!drive_previous_connected[i]) {
        if (mscDrive.begin(pdrives[i])) {
          Serial.printf("\nUSB Drive: %u connected\n", i);
          pfsLIB.mbrDmp(&mscDrive, (uint32_t)-1, Serial);     
          Serial.printf("\nTry Partition list");
          pfsLIB.listPartitions(&mscDrive, Serial);
          drive_previous_connected[i] = true;
        }
      }
    } else {
      drive_previous_connected[i] = false;
    }
  }
  bool send_device_reset = false;
  for (uint8_t i = 0; i < CNT_MSC; i++) {
    if (*pmsFS[i] && (pmsfs_store_ids[i] == 0xFFFFFFFFUL)) {
      Serial.printf("Found new Volume:%u\n", i); Serial.flush();
      // Lets see if we can get the volume label:
      char volName[20];
      if (pmsFS[i]->mscfs.getVolumeLabel(volName, sizeof(volName)))
        snprintf(pmsFS_display_name[i], sizeof(pmsFS_display_name[i]), "MSC%d-%s", i, volName);
      else
        snprintf(pmsFS_display_name[i], sizeof(pmsFS_display_name[i]), "MSC%d", i);
      pmsfs_store_ids[i] = storage.addFilesystem(*pmsFS[i], pmsFS_display_name[i]);

      // Try to send store added. if > 0 it went through = 0 stores have not been enumerated
      if (mtpd.send_StoreAddedEvent(pmsfs_store_ids[i]) < 0) send_device_reset = true;
    }
    // Or did volume go away?
    else if ((pmsfs_store_ids[i] != 0xFFFFFFFFUL) && !*pmsFS[i] ) {
      if (mtpd.send_StoreRemovedEvent(pmsfs_store_ids[i]) < 0) send_device_reset = true;
      storage.removeFilesystem(pmsfs_store_ids[i]);
      // Try to send store added. if > 0 it went through = 0 stores have not been enumerated
      pmsfs_store_ids[i] = 0xFFFFFFFFUL;
    }
  }
  if (send_device_reset) mtpd.send_DeviceResetEvent();
}
#endif

void logData()
{
  // make a string for assembling the data to log:
  String dataString = "";

  // read three sensors and append to the string:
  for (int analogPin = 0; analogPin < 3; analogPin++) {
    int sensor = analogRead(analogPin);
    dataString += String(sensor);
    if (analogPin < 2) {
      dataString += ",";
    }
  }

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    // print to the serial port too:
    DBGSerial.println(dataString);
    record_count += 1;
  } else {
    // if the file isn't open, pop up an error:
    DBGSerial.println("error opening datalog.txt");
  }
  delay(100); // run at a reasonable not-too-fast speed for testing
}

void stopLogging()
{
  DBGSerial.println("\nStopped Logging Data!!!");
  write_data = false;
  // Closes the data file.
  dataFile.close();
  DBGSerial.printf("Records written = %d\n", record_count);
  mtpd.send_DeviceResetEvent();
}


void dumpLog()
{
  DBGSerial.println("\nDumping Log!!!");
  // open the file.
  dataFile = myfs->open("datalog.txt");

  // if the file is available, write to it:
  if (dataFile) {
    while (dataFile.available()) {
      DBGSerial.write(dataFile.read());
    }
    dataFile.close();
  }
  // if the file isn't open, pop up an error:
  else {
    DBGSerial.println("error opening datalog.txt");
  }
}

void menu()
{
  DBGSerial.println();
  DBGSerial.println("Menu Options:");
  DBGSerial.println("\t1 - List Drives (Step 1)");
  DBGSerial.println("\t2# - Select Drive # for Logging (Step 2)");
  DBGSerial.println("\tl - List files on disk");
  DBGSerial.println("\te - Erase files on disk with Format");
  DBGSerial.println("\ts - Start Logging data (Restarting logger will append records to existing log)");
  DBGSerial.println("\tx - Stop Logging data");
  DBGSerial.println("\td - Dump Log");
  DBGSerial.println("\tr - Reset MTP");
  DBGSerial.printf("\n\t%s","R - Restart Teensy");
  DBGSerial.printf("\n\t%s","i - Write Index File to disk");
  DBGSerial.printf("\n\t%s","'B, or b': Make Big file half of free space, or remove all Big files");
  DBGSerial.printf("\n\t%s","'S, or t': Make 2MB file , or remove all 2MB files");
  DBGSerial.printf("\n\t%s","'n' No verify on Write- TOGGLE");

  DBGSerial.println("\th - Menu");
  DBGSerial.println();
}

void listFiles()
{
  DBGSerial.print("\n Space Used = ");
  DBGSerial.println(myfs->usedSize());
  DBGSerial.print("Filesystem Size = ");
  DBGSerial.println(myfs->totalSize());

  printDirectory(myfs);
}

void eraseFiles()
{
  //DBGSerial.println("Formating not supported at this time");
  DBGSerial.println("\n*** Erase/Format started ***");
  myfs->format(1, '.', DBGSerial);
  Serial.println("Completed, sending device reset event");
  mtpd.send_DeviceResetEvent();
}

void format3()
{
  //DBGSerial.println("Formating not supported at this time");
  DBGSerial.println("\n*** Erase/Format Unused started ***");
  myfs->format(2,'.', DBGSerial );
  Serial.println("Completed, sending device reset event");
  mtpd.send_DeviceResetEvent();
}

void printDirectory(FS *pfs) {
  DBGSerial.println("Directory\n---------");
  printDirectory(pfs->open("/"), 0);
  DBGSerial.println();
}

void printDirectory(File dir, int numSpaces) {
  while (true) {
    File entry = dir.openNextFile();
    if (! entry) {
      //DBGSerial.println("** no more files **");
      break;
    }
    printSpaces(numSpaces);
    DBGSerial.print(entry.name());
    if (entry.isDirectory()) {
      DBGSerial.println("/");
      printDirectory(entry, numSpaces + 2);
    } else {
      // files have sizes, directories do not
      printSpaces(36 - numSpaces - strlen(entry.name()));
      DBGSerial.print("  ");
      DBGSerial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

void printSpaces(int num) {
  for (int i = 0; i < num; i++) {
    DBGSerial.print(" ");
  }
}


uint32_t CommandLineReadNextNumber(int &ch, uint32_t default_num) {
  while (ch == ' ') ch = DBGSerial.read();
  if ((ch < '0') || (ch > '9')) return default_num;

  uint32_t return_value = 0;
  while ((ch >= '0') && (ch <= '9')) {
    return_value = return_value * 10 + ch - '0';
    ch = DBGSerial.read();
  }
  return return_value;
}



void readVerify( char szPath[], char chNow ) {
  uint32_t timeMe = micros();
  file3 = myfs->open(szPath);
  if ( 0 == file3 ) {
    Serial.printf( "\tV\t Fail File open %s\n", szPath );
    errsLFS++;
  }
  char mm;
  char chNow2 = chNow + lowOffset;
  uint32_t ii = 0;
  while ( file3.available() ) {
    file3.read( &mm , 1 );
    rdCnt++;
    //Serial.print( mm ); // show chars as read
    ii++;
    if ( 0 == (ii / lowShift) % 2 ) {
      if ( chNow2 != mm ) {
        Serial.printf( "<Bad Byte!  %c! = %c [0x%X] @%u\n", chNow2, mm, mm, ii );
        errsLFS++;
        break;
      }
    }
    else {
      if ( chNow != mm ) {
        Serial.printf( "<Bad Byte!  %c! = %c [0x%X] @%u\n", chNow, mm, mm, ii );
        errsLFS++;
        break;
      }
    }
  }
  Serial.printf( "  Verify %u Bytes ", ii );
  if (ii != file3.size()) {
    Serial.printf( "\n\tRead Count fail! :: read %u != f.size %llu", ii, file3.size() );
    errsLFS++;
  }
  file3.close();
  timeMe = micros() - timeMe;
  Serial.printf( " @KB/sec %5.2f", ii / (timeMe / 1000.0) );
}

bool bigVerify( char szPath[], char chNow ) {
  uint32_t timeMe = micros();
  file3 = myfs->open(szPath);
  uint64_t fSize;
  if ( 0 == file3 ) {
    return false;
  }
  char mm;
  uint32_t ii = 0;
  uint32_t kk = file3.size() / 50;
  fSize = file3.size();
  Serial.printf( "\tVerify %s bytes %llu : ", szPath, fSize );
  while ( file3.available() ) {
    file3.read( &mm , 1 );
    rdCnt++;
    ii++;
    if ( !(ii % kk) ) Serial.print('.');
    if ( chNow != mm ) {
      Serial.printf( "<Bad Byte!  %c! = %c [0x%X] @%u\n", chNow, mm, mm, ii );
      errsLFS++;
      break;
    }
    if ( ii > fSize ) { // catch over length return makes bad loop !!!
      Serial.printf( "\n\tFile LEN Corrupt!  FS returning over %u bytes\n", fSize );
      errsLFS++;
      break;
    }
  }
  if (ii != file3.size()) {
    Serial.printf( "\n\tRead Count fail! :: read %u != f.size %llu\n", ii, file3.size() );
    errsLFS++;
  }
  else
    Serial.printf( "\tGOOD! >>  bytes %lu", ii );
  file3.close();
  timeMe = micros() - timeMe;
  Serial.printf( "\n\tBig read&compare KBytes per second %5.2f \n", ii / (timeMe / 1000.0) );
  if ( 0 == ii ) return false;
  return true;
}



void bigFile( int doThis ) {
  char myFile[] = "/0_bigfile.txt";
  char fileID = '0' - 1;
  DateTimeFields dtf = {0, 10, 7, 0, 22, 7, 121};

  if ( 0 == doThis ) {  // delete File
    Serial.printf( "\nDelete with read verify all #bigfile's\n");
    do {
      fileID++;
      myFile[1] = fileID;
      if ( myfs->exists(myFile) && bigVerify( myFile, fileID) ) {
        filecount--;
        myfs->remove(myFile);
      }
      else break; // no more of these
    } while ( 1 );
  }
  else {  // FILL DISK
    uint32_t resW = 1;
    
    char someData[MYBLKSIZE];
    uint64_t xx, toWrite;
    toWrite = (myfs->totalSize()) - myfs->usedSize();
    if ( toWrite < 65535 ) {
      Serial.print( "Disk too full! DO :: reformat");
      return;
    }
    if ( size_bigfile < toWrite *2 )
      toWrite = size_bigfile;
    else 
      toWrite/=2;
    toWrite -= SLACK_SPACE;
    xx = toWrite;
    Serial.printf( "\nStart Big write of %llu Bytes", xx);
    uint32_t timeMe = millis();
    file3 = nullptr;
    do {
      if ( file3 ) file3.close();
      fileID++;
      myFile[1] = fileID;
      file3 = myfs->open(myFile, FILE_WRITE);
    } while ( fileID < '9' && file3.size() > 0);
    if ( fileID == '9' ) {
      Serial.print( "Disk has 9 halves 0-8! DO :: b or q or F");
      return;
    }
    memset( someData, fileID, MYBLKSIZE );
    uint64_t hh = 0;
    uint64_t kk = toWrite/MYBLKSIZE/60;
    while ( toWrite > MYBLKSIZE && resW > 0 ) {
      resW = file3.write( someData , MYBLKSIZE );
      hh++;
      if ( !(hh % kk) ) Serial.print('.');
      toWrite -= MYBLKSIZE;
    }
    file3.setCreateTime(dtf);
    file3.setModifyTime(dtf);
    file3.close();
    timeMe = millis() - timeMe;
    file3 = myfs->open(myFile, FILE_WRITE);
    if ( file3.size() > 0 ) {
      filecount++;
      Serial.printf( "\nBig write %s took %5.2f Sec for %llu Bytes : file3.size()=%llu", myFile , timeMe / 1000.0, xx, file3.size() );
    }
    if ( file3 != 0 ) file3.close();
    Serial.printf( "\n\tBig write KBytes per second %5.2f \n", xx / (timeMe / 1.0) );
    Serial.printf("\nBytes Used: %llu, Bytes Total:%llu\n", myfs->usedSize(), myfs->totalSize());
    if ( myfs->usedSize() == myfs->totalSize() ) {
      Serial.printf("\n\n\tWARNING: DISK FULL >>>>>  Bytes Used: %llu, Bytes Total:%llu\n\n", myfs->usedSize(), myfs->totalSize());
      warnLFS++;
    }
    if ( resW < 0 ) {
      Serial.printf( "\nBig write ERR# %i 0x%X \n", resW, resW );
      errsLFS++;
      myfs->remove(myFile);
    }
  }
}

void bigFile2MB( int doThis ) {
  char myFile[] = "/0_2MBfile.txt";
  char fileID = '0' - 1;
  DateTimeFields dtf = {0, 10, 7, 0, 22, 7, 121};

  if ( 0 == doThis ) {  // delete File
    Serial.printf( "\nDelete with read verify all #bigfile's\n");
    do {
      fileID++;
      myFile[1] = fileID;
      if ( myfs->exists(myFile) && bigVerify( myFile, fileID) ) {
        filecount--;
        myfs->remove(myFile);
      }
      else break; // no more of these
    } while ( 1 );
  }
  else {  // FILL DISK
    uint32_t resW = 1;
    
    char someData[2048];
    uint32_t xx, toWrite;
    toWrite = 2048 * 1000;
    if ( toWrite > (65535 + (myfs->totalSize() - myfs->usedSize()) ) ) {
      Serial.print( "Disk too full! DO :: q or F");
      return;
    }
    xx = toWrite;
    Serial.printf( "\nStart Big write of %u Bytes", xx);
    uint32_t timeMe = micros();
    file3 = nullptr;
    do {
      if ( file3 ) file3.close();
      fileID++;
      myFile[1] = fileID;
      file3 = myfs->open(myFile, FILE_WRITE);
    } while ( fileID < '9' && file3.size() > 0);
    if ( fileID == '9' ) {
      Serial.print( "Disk has 9 files 0-8! DO :: b or q or F");
      return;
    }
    memset( someData, fileID, 2048 );
    int hh = 0;
    while ( toWrite >= 2048 && resW > 0 ) {
      resW = file3.write( someData , 2048 );
      hh++;
      if ( !(hh % 40) ) Serial.print('.');
      toWrite -= 2048;
    }
    xx -= toWrite;
    file3.setCreateTime(dtf);
    file3.setModifyTime(dtf);
    file3.close();
    timeMe = micros() - timeMe;
    file3 = myfs->open(myFile, FILE_WRITE);
    if ( file3.size() > 0 ) {
      filecount++;
      Serial.printf( "\nBig write %s took %5.2f Sec for %lu Bytes : file3.size()=%llu", myFile , timeMe / 1000000.0, xx, file3.size() );
    }
    if ( file3 != 0 ) file3.close();
    Serial.printf( "\n\tBig write KBytes per second %5.2f \n", xx / (timeMe / 1000.0) );
    Serial.printf("\nBytes Used: %llu, Bytes Total:%llu\n", myfs->usedSize(), myfs->totalSize());
    if ( myfs->usedSize() == myfs->totalSize() ) {
      Serial.printf("\n\n\tWARNING: DISK FULL >>>>>  Bytes Used: %llu, Bytes Total:%llu\n\n", myfs->usedSize(), myfs->totalSize());
      warnLFS++;
    }
    if ( resW < 0 ) {
      Serial.printf( "\nBig write ERR# %i 0x%X \n", resW, resW );
      errsLFS++;
      myfs->remove(myFile);
    }
  }
}

void writeIndexFile() 
{
  DateTimeFields dtf = {0, 10, 7, 0, 22, 7, 121};
  // open the file.
  Serial.println("Write Large Index File");
  uint32_t timeMe = micros();
  file3 = myfs->open("LargeIndexedTestfile.txt", FILE_WRITE_BEGIN);
  if (file3) {
    file3.truncate(); // Make sure we wipe out whatever was written earlier
    for (uint32_t i = 0; i < 43000*4; i++) {
      memset(write_buffer, 'A'+ (i & 0xf), sizeof(write_buffer));
      file3.printf("%06u ", i >> 2);  // 4 per physical buffer
      file3.write(write_buffer, i? 120 : 120-12); // first buffer has other data...
      file3.printf("\n");
      if ( !(i % 1024) ) Serial.print('.');

    }
    file3.setCreateTime(dtf);
    file3.setModifyTime(dtf);
    file3.close();
    
    timeMe = micros() - timeMe;
    file3 = myfs->open("LargeIndexedTestfile.txt", FILE_WRITE);
    if ( file3.size() > 0 ) {
       Serial.printf( " Total time to write %d byte: %5.2f seconds\n", file3.size(), (timeMe / 1000.0));
       Serial.printf( "\n\tBig write KBytes per second %5.2f \n", file3.size() / (timeMe / 1000.0) );
    }
    if ( file3 != 0 ) file3.close();
    Serial.println("\ndone.");
    
  }
}
 
On a T3.6 with a similar configuration
Code:
Dump Storage list(6)
store:0 storage:10001 name:sdio fs:1fff3120
store:1 storage:20001 name:sflash5 fs:1fff7690
store:2 storage:30001 name:sflash6 fs:1fff7770
store:3 storage:40001 name:WINBOND1G fs:1fff2670
store:4 storage:50001 name:WINBOND2G fs:1fff2764
store:5 storage:60001 name:MSC0-exFAT-128 fs:1fff3c10
Check SDIO 0 0 1779
Check SDIO 0 0 1779
I can insert the sd card and all devices appear and are accessible including USB:
Capture.PNG
 
Quick update: I did push up a Pull request for SD library for mediaPresent... https://github.com/PaulStoffregen/SD/pull/36

Two parts:

T3.x - The fix I mentioned earlier today

T4.x - When it detects that SD was not inserted on an SDIO SD... The call before was taking like 3 seconds to fail the restart.. So used the set DAT3 pin to INPUT_PULLDOWN and check the state of the IO pin and then check to see if it finds the device
Which appears to be working on T4.1... Need to now check on T4 and MicroMod to make sure I have the right PIN #...

maybe soon try SPI version. To see just how slow... Also wonder if we should add a way to specify Chip Detect pin for those who have external readers with the ability to check...

EDIT: Tested on MMOD and T4... Had to change pin number for MMOD as DAT3/2 sort of swapped
 
Last edited:
Quick update: I did push up a Pull request for SD library for mediaPresent... https://github.com/PaulStoffregen/SD/pull/36

Two parts:

T3.x - The fix I mentioned earlier today

T4.x - When it detects that SD was not inserted on an SDIO SD... The call before was taking like 3 seconds to fail the restart.. So used the set DAT3 pin to INPUT_PULLDOWN and check the state of the IO pin and then check to see if it finds the device
Which appears to be working on T4.1... Need to now check on T4 and MicroMod to make sure I have the right PIN #...

maybe soon try SPI version. To see just how slow... Also wonder if we should add a way to specify Chip Detect pin for those who have external readers with the ability to check...

EDIT: Tested on MMOD and T4... Had to change pin number for MMOD as DAT3/2 sort of swapped

Yep - just tried it on both the T4.1 and micromod and both work perfectly - I just needed to resync :)
 
Quick update: I did push up a Pull request for SD library for mediaPresent... https://github.com/PaulStoffregen/SD/pull/36

Merged.

But what happens if the SD library isn't started by begin()? As shown in the SdFat_Usage example, the user can call SD.sdfs.begin(SdioConfig(DMA_SDIO)) or SD.sdfs.begin(SdioConfig(FIFO_SDIO)). Maybe we should have a way to reach into SdFat to detect if it's using SPI vs SDIO rather than storing a private csPin variable?
 
Merged.

But what happens if the SD library isn't started by begin()? As shown in the SdFat_Usage example, the user can call SD.sdfs.begin(SdioConfig(DMA_SDIO)) or SD.sdfs.begin(SdioConfig(FIFO_SDIO)). Maybe we should have a way to reach into SdFat to detect if it's using SPI vs SDIO rather than storing a private csPin variable?
I was going to test that case, right now I was hoping at minimum if I don't know if it is SDIO, I can not use the speedup part of the T4x code path and it takes 3 seconds to detect if the media was inserted.

Right now playing with SPI code to see how it responds.

But was going to also suggest would be great if SDFat might give us a clue.

Plus also wanted to see why T4.x is a lot slower to bail when trying to do an SD.begin() (or restart) when there is no card inserted...
 
@KurtE - @PaulStoffregen

Just tried it on a T4.1 using a modified version of Kurts test sketch.
Code:
#include <SD.h>

bool media_present = false;

void setup() {
  while (!Serial) ;
  Serial.println("Test Media Present");
  media_present = SD.sdfs.begin(SdioConfig(FIFO_SDIO));
  Serial.printf("\n$$$Media Present: %u\n", media_present);
}


void loop() {
  if (Serial.available()) {
    while (Serial.read() != -1) ;
    Serial.println("Paused");
    while (Serial.read() == -1) ;
    while (Serial.read() != -1) ;
  }
  //Serial.println(digitalReadFast(_SD_DAT3), DEC);
  elapsedMicros em;
  bool cur_media_present = SD.mediaPresent();
  Serial.printf("New: %u Prev: %u em:%u\n", cur_media_present, media_present, (uint32_t)em);
  if (cur_media_present != media_present) {
    media_present = cur_media_present;
  }
  delay(1000);
}
and it works for SDIO:
Code:
Test Media Present

$$$Media Present: 0
New: 0 Prev: 0 em:3000883
New: 0 Prev: 0 em:3000882
New: 0 Prev: 0 em:3000859
New: 0 Prev: 0 em:3000882
New: 1 Prev: 0 em:157837
New: 1 Prev: 1 em:0
New: 1 Prev: 1 em:0
New: 1 Prev: 1 em:0
New: 1 Prev: 1 em:0
New: 1 Prev: 1 em:0
New: 1 Prev: 1 em:0

KurtE said:
But was going to also suggest would be great if SDFat might give us a clue.
so probably a good idea.
 
Decided to add Paul's benchmark sketch into MTP_TEST_Integrity sketch I am using. So on a T4.1 with the following:
Code:
Dump Storage list(11)
store:0 storage:10001 name:Program fs:2000c40c
store:1 storage:20001 name:RAM fs:2000c4d8
store:2 storage:30001 name:sdio fs:2000ccb8
store:3 storage:40001 name:RAM0 fs:2000cac4
store:4 storage:50001 name:RAM1 fs:2000cb90
store:5 storage:60001 name:PROGM fs:2000c9f8
store:6 storage:70001 name:sflash5 fs:2000d658
store:7 storage:80001 name:sflash6 fs:2000d738
store:8 storage:90001 name:WINBOND1G fs:2000c5ac
store:9 storage:a0001 name:WINBOND2G fs:2000c6a0
store:10 storage:b0001 name:MSC0-exFAT-128 fs:2000a370

here are the results
Code:
[B]Storage Index 9 Name: WINBOND2G Selected
[/B]Writing 524288 byte file...  707 ms, bandwidth = 741567 bytes/sec
Writing 524288 byte file...  307 ms, bandwidth = 1707778 bytes/sec
Writing 524288 byte file...  312 ms, bandwidth = 1680410 bytes/sec
Writing 524288 byte file...  307 ms, bandwidth = 1707778 bytes/sec
Writing 524288 byte file...  307 ms, bandwidth = 1707778 bytes/sec
Writing 524288 byte file...  307 ms, bandwidth = 1707778 bytes/sec
Writing 524288 byte file...  308 ms, bandwidth = 1702233 bytes/sec
Writing 524288 byte file...  308 ms, bandwidth = 1702233 bytes/sec
Writing 524288 byte file...  308 ms, bandwidth = 1702233 bytes/sec
Writing 524288 byte file...  308 ms, bandwidth = 1702233 bytes/sec

[B]Storage Index 8 Name: WINBOND1G Selected
[/B]Writing 524288 byte file...  525 ms, bandwidth = 998643 bytes/sec
Writing 524288 byte file...  324 ms, bandwidth = 1618172 bytes/sec
Writing 524288 byte file...  323 ms, bandwidth = 1623182 bytes/sec
Writing 524288 byte file...  324 ms, bandwidth = 1618172 bytes/sec
Writing 524288 byte file...  323 ms, bandwidth = 1623182 bytes/sec
Writing 524288 byte file...  323 ms, bandwidth = 1623182 bytes/sec
Writing 524288 byte file...  323 ms, bandwidth = 1623182 bytes/sec
Writing 524288 byte file...  322 ms, bandwidth = 1628223 bytes/sec
Writing 524288 byte file...  323 ms, bandwidth = 1623182 bytes/sec
Writing 524288 byte file...  323 ms, bandwidth = 1623182 bytes/sec

[B]store:10 storage:b0001 name:MSC0-exFAT-128 fs:2000a370
[/B]Writing 524288 byte file...  308 ms, bandwidth = 1702233 bytes/sec
Writing 524288 byte file...  304 ms, bandwidth = 1724631 bytes/sec
Writing 524288 byte file...  300 ms, bandwidth = 1747626 bytes/sec
Writing 524288 byte file...  300 ms, bandwidth = 1747626 bytes/sec
Writing 524288 byte file...  300 ms, bandwidth = 1747626 bytes/sec
Writing 524288 byte file...  305 ms, bandwidth = 1718977 bytes/sec
Writing 524288 byte file...  305 ms, bandwidth = 1718977 bytes/sec
Writing 524288 byte file...  306 ms, bandwidth = 1713359 bytes/sec
Writing 524288 byte file...  305 ms, bandwidth = 1718977 bytes/sec
Writing 524288 byte file...  305 ms, bandwidth = 1718977 bytes/sec

[B]Storage Index 4 Name: RAM1 Selected
[/B]Writing 524288 byte file...  75 ms, bandwidth = 6990506 bytes/sec
Writing 524288 byte file...  75 ms, bandwidth = 6990506 bytes/sec
Writing 524288 byte file...  76 ms, bandwidth = 6898526 bytes/sec
Writing 524288 byte file...  77 ms, bandwidth = 6808935 bytes/sec
Writing 524288 byte file...  75 ms, bandwidth = 6990506 bytes/sec
Writing 524288 byte file...  75 ms, bandwidth = 6990506 bytes/sec
Writing 524288 byte file...  77 ms, bandwidth = 6808935 bytes/sec
Writing 524288 byte file...  75 ms, bandwidth = 6990506 bytes/sec
Writing 524288 byte file...  75 ms, bandwidth = 6990506 bytes/sec
Writing 524288 byte file...  76 ms, bandwidth = 6898526 bytes/sec

[B]Storage Index 5 Name: PROGM Selected
[/B]Writing 524288 byte file...  855 ms, bandwidth = 613202 bytes/sec
Writing 524288 byte file...  854 ms, bandwidth = 613920 bytes/sec
Writing 524288 byte file...  856 ms, bandwidth = 612485 bytes/sec
Writing 524288 byte file...  854 ms, bandwidth = 613920 bytes/sec
Writing 524288 byte file...  857 ms, bandwidth = 611771 bytes/sec
Writing 524288 byte file...  854 ms, bandwidth = 613920 bytes/sec
Writing 524288 byte file...  856 ms, bandwidth = 612485 bytes/sec
Writing 524288 byte file...  854 ms, bandwidth = 613920 bytes/sec
Writing 524288 byte file...  854 ms, bandwidth = 613920 bytes/sec
Writing 524288 byte file...  857 ms, bandwidth = 611771 bytes/sec

[B]Storage Index 6 Name: sflash5 Selected
[/B]Writing 524288 byte file...  3802 ms, bandwidth = 137897 bytes/sec
Writing 524288 byte file...  3740 ms, bandwidth = 140183 bytes/sec
Writing 524288 byte file...  3722 ms, bandwidth = 140861 bytes/sec
Writing 524288 byte file...  3661 ms, bandwidth = 143208 bytes/sec
Writing 524288 byte file...  3592 ms, bandwidth = 145959 bytes/sec
Writing 524288 byte file...  3615 ms, bandwidth = 145031 bytes/sec
Writing 524288 byte file...  3681 ms, bandwidth = 142430 bytes/sec
Writing 524288 byte file...  3663 ms, bandwidth = 143130 bytes/sec
Writing 524288 byte file...  3680 ms, bandwidth = 142469 bytes/sec
Writing 524288 byte file...  3634 ms, bandwidth = 144272 bytes/sec

[B]Storage Index 2 Name: sdio Selected
[/B]Writing 524288 byte file...  33 ms, bandwidth = 15887515 bytes/sec
Writing 524288 byte file...  34 ms, bandwidth = 15420235 bytes/sec
Writing 524288 byte file...  34 ms, bandwidth = 15420235 bytes/sec
Writing 524288 byte file...  34 ms, bandwidth = 15420235 bytes/sec
Writing 524288 byte file...  34 ms, bandwidth = 15420235 bytes/sec
Writing 524288 byte file...  39 ms, bandwidth = 13443282 bytes/sec
Writing 524288 byte file...  34 ms, bandwidth = 15420235 bytes/sec
Writing 524288 byte file...  34 ms, bandwidth = 15420235 bytes/sec
Writing 524288 byte file...  33 ms, bandwidth = 15887515 bytes/sec
Writing 524288 byte file...  35 ms, bandwidth = 14979657 bytes/sec

and if anyone is interested in the latest incarnation of the sketch that also has @KurtE SD Card media test incorporated
 

Attachments

  • mtp-test-integrity-211215b.zip
    9.8 KB · Views: 35
Merged.

But what happens if the SD library isn't started by begin()? As shown in the SdFat_Usage example, the user can call SD.sdfs.begin(SdioConfig(DMA_SDIO)) or SD.sdfs.begin(SdioConfig(FIFO_SDIO)). Maybe we should have a way to reach into SdFat to detect if it's using SPI vs SDIO rather than storing a private csPin variable?

Another possible answer: which I want to explore anyway as I had the functionality in the MTP code before FS only...

I was thinking about adding a new method to SD, like setChipDetectPin(uint8_t pin=BUILTIN_SDCARD);

Maybe does not default to this, but, if BUILTIN_SDCARD is passed in, it will figure out to use or not use DAT3.

However also if it is an SPI version and you are using something like an Adafruit or Sparkfun breakout with CD pin it can use this for speed ups... May also add another parameter with default on if it should invert. I doubt in most case you will need to invert, but have seen some with two pads, so maybe you pulled it high instead of low...
 
If anyone has wanted to jump into MTP testing but gotten bogged down with the many library changes needed, a 1.56-beta4 installer is now available to roll up the many changes.

https://forum.pjrc.com/threads/68972-Teensyduino-1-56-Beta-4

Just add the MTP_Teensy library in {Documents}/Arduino/libraries and remember to set Tools > USB Type to MTP (experimental).

https://github.com/KurtE/MTP_Teensy

With the packet loss issue fixed and LittleFS now fast enough, MTP is becoming much more fun. :)
 
Another possible answer: which I want to explore anyway as I had the functionality in the MTP code before FS only...

I was thinking about adding a new method to SD, like setChipDetectPin(uint8_t pin=BUILTIN_SDCARD);

Maybe does not default to this, but, if BUILTIN_SDCARD is passed in, it will figure out to use or not use DAT3.

However also if it is an SPI version and you are using something like an Adafruit or Sparkfun breakout with CD pin it can use this for speed ups... May also add another parameter with default on if it should invert. I doubt in most case you will need to invert, but have seen some with two pads, so maybe you pulled it high instead of low...

From what I remember the use of the CD pin worked very nicely in our previous testing and would be a great add so yes I like the idea.
 
If anyone has wanted to jump into MTP testing but gotten bogged down with the many library changes needed, a 1.56-beta4 installer is now available to roll up the many changes.

https://forum.pjrc.com/threads/68972-Teensyduino-1-56-Beta-4

Just add the MTP_Teensy library in {Documents}/Arduino/libraries and remember to set Tools > USB Type to MTP (experimental).

https://github.com/KurtE/MTP_Teensy

With the packet loss issue fixed and LittleFS now fast enough, MTP is becoming much more fun. :)

Believe you will also need @KurtE changes to USBHost_t36 in order to use USB drives: https://github.com/KurtE/USBHost_t36/tree/FS_Integration_MSC
 
Quick update/WIP - working on better detecting when SD cards are inserted and removed...

Adding possible support to select a CHIP DETECT pin, that some external readers have...

I think it is starting to work. Testing with T4.1 with Audio board and external Sparkfun without level shifter (https://www.sparkfun.com/products/544)

I pushed up wip branch: https://github.com/KurtE/SD/tree/card_detect_pin

In MTP_Teensy pushed up an updated: SD_MTP-logger sketch that uses this

It appears to be detecting the three different cases.

Again note: I am using a (not yet approved) new method
Code:
	bool setMediaDetectPin(uint8_t pin);

Also at times not showing up on MTP in red when not inserted, I am thinking maybe SD is still holding on to cached date like free space and total space even when not valid anymore... investigating

EDIT: Interesting question - how does one tell a random FS or in this case simple random SDClass object, that your data is invalid...

That is suppose in the case the card is pulled out, and I call off to myfs->totalSize(). Most likely the SD (and underlying SDFat) object is normally just going to return a value that it cached away. Likewise with the freeClusterCount, which we have turned on option to cache this value...

So again how do we tell it that you may need to invalidate your cache...
 
Last edited:
Also at times not showing up on MTP in red when not inserted, I am thinking maybe SD is still holding on to cached date like free space and total space even when not valid anymore... investigating

EDIT: Interesting question - how does one tell a random FS or in this case simple random SDClass object, that your data is invalid...

That is suppose in the case the card is pulled out, and I call off to myfs->totalSize(). Most likely the SD (and underlying SDFat) object is normally just going to return a value that it cached away. Likewise with the freeClusterCount, which we have turned on option to cache this value...

So again how do we tell it that you may need to invalidate your cache...

Something I have been wanting to setup and play with is an unmount function. One that would make sure all files are flushed and closed and any cached data is cleared. Then invalidate that drive. This would allow for safe removal of the drive without data loss. Another consideration is if there are multiple partitions on the same physical drive. They would also have to be unmounted. This would allow for safe removal of the device without data loss or corruption. I guess having an activity LED would be handy as well to show any background activity going on before unplugging the device. Just some thoughts...
 
Something I have been wanting to setup and play with is an unmount function. One that would make sure all files are flushed and closed and any cached data is cleared. Then invalidate that drive. This would allow for safe removal of the drive without data loss. Another consideration is if there are multiple partitions on the same physical drive. They would also have to be unmounted. This would allow for safe removal of the device without data loss or corruption. I guess having an activity LED would be handy as well to show any background activity going on before unplugging the device. Just some thoughts...

I think I may have a sort of fix that appears to work reasonably (SD stuff)... With MTP we remove the storage from list when drive goes away...

Code:
          if (media_present) DBGSerial.printf("\n### %s(%d) inserted dt:%u\n",  myfs[i].name, i, (uint32_t)em);
          else {
            DBGSerial.printf("\n### %s(%d) removed dt:%u\n",  myfs[i].name, i, (uint32_t)em);
            myfs[i].sd.sdfs.end();
          }
In the case of disconnect, call the sdfs.end() method, which will tell the fs object to remove it fat/exfat ptr... so the functions like freeclustercount will return 0...
 
Also at times not showing up on MTP in red when not inserted, I am thinking maybe SD is still holding on to cached date like free space and total space even when not valid anymore... investigating

EDIT: Interesting question - how does one tell a random FS or in this case simple random SDClass object, that your data is invalid...

That is suppose in the case the card is pulled out, and I call off to myfs->totalSize(). Most likely the SD (and underlying SDFat) object is normally just going to return a value that it cached away. Likewise with the freeClusterCount, which we have turned on option to cache this value...

So again how do we tell it that you may need to invalidate your cache...

Evening all ran the SD_Logger sketch and it worked like a charm so I decided to again incorporate it into that overly complex mtp_test_integrity sketch :) and again it works perfectly so I would highly recommend issuing the PR for to SD. I am using a adafruit external card reader for testing by the way.

In the case of disconnect, call the sdfs.end() method, which will tell the fs object to remove it fat/exfat ptr... so the functions like freeclustercount will return 0...
very cool. That pretty much happens with USB drives now.

Although what stopped me from answering before is what happens if a FS gets corrupted after its mounted guess the same would apply or am I going down one of our infamous rabbit holes. Also thinking about if just using SD or other media without MTP addfilesystem?
 
I think I may have a sort of fix that appears to work reasonably (SD stuff)... With MTP we remove the storage from list when drive goes away...

Code:
          if (media_present) DBGSerial.printf("\n### %s(%d) inserted dt:%u\n",  myfs[i].name, i, (uint32_t)em);
          else {
            DBGSerial.printf("\n### %s(%d) removed dt:%u\n",  myfs[i].name, i, (uint32_t)em);
            myfs[i].sd.sdfs.end();
          }
In the case of disconnect, call the sdfs.end() method, which will tell the fs object to remove it fat/exfat ptr... so the functions like freeclustercount will return 0...

I just update to Arduino-1.8.18 and TD1.56B4. Also updated to your latest SD and MTP_Teensy. Going to try to get some play time in tonight:)

Thanks...
 
Hi all been awhile.
Just updated to the newest Arduino-1.8.18 and TD1.56#B4.

I'm running into a weird MTP issue seems to be smaller size file related less than 512 bytes :confused: ( 371 bytes )
Can someone try to copy the attached file using the newest MTP.
I'm just not sure if it's my setup or MTP has issue with small files ?

WINDOWS 10 Teensy 4.1
I'm using one of the File>examples>MTP_Teensy>simple.
Code:
#include <SD.h>
#include <LittleFS.h>
#include <MTP_Teensy.h>

#define DBGSerial Serial

FS *myfs;
File dataFile;
int record_count = 0;
bool write_data = false;
uint8_t current_store = 0;

MTPStorage storage;     // TODO: storage inside MTP instance, not separate class
MTPD    MTP(&storage);  // TODO: MTP instance created by default

LittleFS_RAM      ramdisk;
LittleFS_Program  progdisk;
LittleFS_SPIFlash flashchip;

const int SD_ChipSelect = BUILTIN_SDCARD;
const int Flash_ChipSelect = 6;


void setup()
{
  // let msusb stuff startup as soon as possible
  //usbmsc.begin();

  DBGSerial.begin(9600);
  while (!DBGSerial && millis() < 5000) {
    // wait for serial port to connect.
  }

  DBGSerial.print(CrashReport);
  DBGSerial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  delay(1000);
  
  // mandatory to begin the MTP session.
  MTP.begin();

  // Add a RAM Disk
  if (ramdisk.begin(65536)) {
    storage.addFilesystem(ramdisk, "RAM");
    // storage.setIndexStore(istore);
    DBGSerial.println("Ram disk initialized");
  }

  // Add the SD Card
  if (SD.begin(SD_ChipSelect)) {
    storage.addFilesystem(SD, "SD_Card");
    DBGSerial.println("SD Card initialized");
  }

  // Add a disk with unused Program memory
  if (progdisk.begin(400000)) {
    storage.addFilesystem(progdisk, "Program");
    DBGSerial.println("Program Storage initialized");
  }

  // Add a SPI Flash chip
  if (flashchip.begin(Flash_ChipSelect)) {
    storage.addFilesystem(flashchip, "SPI Flash");
    DBGSerial.println("SPI Flash initialized");
  }

  DBGSerial.println("\nSetup done");
}


int ReadAndEchoSerialChar() {
  int ch = DBGSerial.read();
  if (ch >= ' ') DBGSerial.write(ch);
  return ch;
}

void loop()
{
  if ( DBGSerial.available() ) {
    uint8_t command = DBGSerial.read();
    int ch = DBGSerial.read();
    uint8_t storage_index = CommandLineReadNextNumber(ch, 0);
    while (ch == ' ') ch = DBGSerial.read();

    uint32_t fsCount;
    switch (command) {
    case '1':
      // first dump list of storages:
      fsCount = storage.getFSCount();
      DBGSerial.printf("\nDump Storage list(%u)\n", fsCount);
      for (uint32_t ii = 0; ii < fsCount; ii++) {
        DBGSerial.printf("store:%u storage:%x name:%s fs:%x\n", ii, MTP.Store2Storage(ii),
          storage.getStoreName(ii), (uint32_t)storage.getStoreFS(ii));
      }
      DBGSerial.println("\nDump Index List");
      storage.dumpIndexList();
      break;
    case '2':
      if (storage_index < storage.getFSCount()) {
        DBGSerial.printf("Storage Index %u Name: %s Selected\n", storage_index,
          storage.getStoreName(storage_index));
        myfs = storage.getStoreFS(storage_index);
        current_store = storage_index;
      } else {
        DBGSerial.printf("Storage Index %u out of range\n", storage_index);
      }
      break;

    case 'l': listFiles(); break;
    case 's':
      DBGSerial.println("\nLogging Data!!!");
      write_data = true;   // sets flag to continue to write data until new command is received
      // opens a file or creates a file if not present,  FILE_WRITE will append data to
      // to the file created.
      dataFile = myfs->open("datalog.txt", FILE_WRITE);
      logData();
      break;
    case 'x': stopLogging(); break;
    case'r':
      DBGSerial.println("Reset");
      MTP.send_DeviceResetEvent();
      break;
    case 'd': dumpLog(); break;
    case '\r':
    case '\n':
    case 'h': menu(); break;
    }
    while (DBGSerial.read() != -1) ; // remove rest of characters.
  } else {
    MTP.loop();
    //#if USE_MSC > 0
    //usbmsc.checkUSBStatus(false);
    //#endif
  }

  if (write_data) logData();
}

void logData()
{
  // make a string for assembling the data to log:
  String dataString = "";

  // read three sensors and append to the string:
  for (int analogPin = 0; analogPin < 3; analogPin++) {
    int sensor = analogRead(analogPin);
    dataString += String(sensor);
    if (analogPin < 2) {
      dataString += ",";
    }
  }

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    // print to the serial port too:
    DBGSerial.println(dataString);
    record_count += 1;
  } else {
    // if the file isn't open, pop up an error:
    DBGSerial.println("error opening datalog.txt");
  }
  delay(100); // run at a reasonable not-too-fast speed for testing
}

void stopLogging()
{
  DBGSerial.println("\nStopped Logging Data!!!");
  write_data = false;
  // Closes the data file.
  dataFile.close();
  DBGSerial.printf("Records written = %d\n", record_count);
  MTP.send_DeviceResetEvent();
}


void dumpLog()
{
  DBGSerial.println("\nDumping Log!!!");
  // open the file.
  dataFile = myfs->open("datalog.txt");

  // if the file is available, write to it:
  if (dataFile) {
    while (dataFile.available()) {
      DBGSerial.write(dataFile.read());
    }
    dataFile.close();
  }
  // if the file isn't open, pop up an error:
  else {
    DBGSerial.println("error opening datalog.txt");
  }
}

void menu()
{
  DBGSerial.println();
  DBGSerial.println("Menu Options:");
  DBGSerial.println("\t1 - List Drives (Step 1)");
  DBGSerial.println("\t2 - Select Drive for Logging (Step 2)");
  DBGSerial.println("\tl - List files on disk");
  DBGSerial.println("\te - Erase files on disk");
  DBGSerial.println("\ts - Start Logging data (Restarting logger will append records to existing log)");
  DBGSerial.println("\tx - Stop Logging data");
  DBGSerial.println("\td - Dump Log");
  DBGSerial.println("\tr - Reset MTP");
  DBGSerial.println("\th - Menu");
  DBGSerial.println();
}

void listFiles()
{
  DBGSerial.print("\n Space Used = ");
  DBGSerial.println(myfs->usedSize());
  DBGSerial.print("Filesystem Size = ");
  DBGSerial.println(myfs->totalSize());

  printDirectory(myfs);
}
#if USE_MSC > 0
extern PFsLib pfsLIB;
#endif

void printDirectory(FS *pfs) {
  DBGSerial.println("Directory\n---------");
  printDirectory(pfs->open("/"), 0);
  DBGSerial.println();
}

void printDirectory(File dir, int numSpaces) {
  while (true) {
    File entry = dir.openNextFile();
    if (! entry) {
      //DBGSerial.println("** no more files **");
      break;
    }
    printSpaces(numSpaces);
    DBGSerial.print(entry.name());
    if (entry.isDirectory()) {
      DBGSerial.println("/");
      printDirectory(entry, numSpaces + 2);
    } else {
      // files have sizes, directories do not
      printSpaces(36 - numSpaces - strlen(entry.name()));
      DBGSerial.print("  ");
      DBGSerial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

void printSpaces(int num) {
  for (int i = 0; i < num; i++) {
    DBGSerial.print(" ");
  }
}


uint32_t CommandLineReadNextNumber(int &ch, uint32_t default_num) {
  while (ch == ' ') ch = DBGSerial.read();
  if ((ch < '0') || (ch > '9')) return default_num;

  uint32_t return_value = 0;
  while ((ch >= '0') && (ch <= '9')) {
    return_value = return_value * 10 + ch - '0';
    ch = DBGSerial.read();
  }
  return return_value;
}

Windows 10 definitely complaining with some sound and this is what I see on serial monitor.
Code:
LP:28122 CMD: 100c(SEND_OBJECT_INFO)l: 20 T:26 : 20001 ffffffff
28122 DATA:100c(SEND_OBJECT_INFO)l: 154 T:26 : 0 3000 173 3000 0
SendObjectInfo: 131073 4294967295 20004100: ST:0 F:3000 0 SZ:371 3000 0 0 0 0 0 0 0 0 0 0 : README
Read DateTime string: 20211215T202943.0
>> date/Time: 61ba5037 12/15/2021 20:29:43
Created: 61ba5037
Read DateTime string: 20010206T041332.0
>> date/Time: 3a7f79ec 2/6/2001 4:13:32
Modified: 3a7f79ec
28126 RESP:2001(RSP:OK)l: 24 T:26 : 20001 ffffffff 16
LP:28126 CMD: 100d(SEND_OBJECT)l: 12 T:27
MTPD::SendObject: len:371
len -129 diskpos: 500
 # USB Packets: 1 total: 0 avg ms: 0 max: 0
 # Write: 1 total:0 avg ms: 0 max: 0(0)
  >> >=100ms: 0 50:0 40:0 30:0 20:0 10:0
  >> Last write times
  0
>>>Total Time: 8031
28135 RESP:2007(RSP:INCOMPLETE_TRANSFER)l: 12 T:27
LP:28160 CMD: 1005(GET_STORAGE_INFO)l: 16 T:28 : 20001
131073 1 name:SD_Card
131073 1 name:SD_Card
28160 RESP:2001(RSP:OK)l: 16 T:28 : 20001

EDIT: Forgot to mention the file is just a simple text file.
Code:
Dieser Ordner enth„lt Archive mit Software, die in Verbindung mit HDDRIVER
n?tzlich sein kann. Sollten Fragen zu dieser Software bestehen, wenden Sie
sich bitte direkt an die Autoren.

This folder contains archives with software that can be useful in combination
with HDDRIVER. If you have any questions concerning this software please
directly contact the authors.
 

Attachments

  • README.zip
    391 bytes · Views: 40
Last edited:
Hi all been awhile.
Just updated to the newest Arduino-1.8.18 and TD1.56#B4.

I'm running into a weird MTP issue seems to be smaller size file related less than 512 bytes ( 371 bytes )
Can someone try to copy the attached file using the newest MTP.
I'm just not sure if it's my setup or MTP has issue with small files ?
Hi Chris - been a while

Well that is strange - I just tried to transfer the file myself with a different sketch (don't ask its a monster) and getting the INCOMPLETE MESSAGE. But the interesting thing is that
Code:
LP:24292 CMD: 100d(SEND_OBJECT)l: 12 T:89
MTPD::SendObject: len:391
len -109 diskpos: 500
 # USB Packets: 1 total: 0 avg ms: 0 max: 0
 # Write: 1 total:0 avg ms: 0 max: 0(0)
  >> >=100ms: 0 50:0 40:0 30:0 20:0 10:0
  >> Last write times
  0
>>>Total Time: 32121
24325 RESP:2007(RSP:INCOMPLETE_TRANSFER)l: 12 T:89
LP:24327 CMD: 1005(GET_STORAGE_INFO)l: 16 T:8a : 30001
when the sendObject is executed its showing a len of -109 bytes????

Just tried it with a couple of other very small files. Think I know what the issue is though. I tried with a 51byte file and a 83byte file but when I do a properties on windows it shows 0bytes on disk. My guess is that MTP is running into problems with this - It is very late here and my brain is fried will have to took closer tomorrow unless @KurtE jumps in.
 
Probably missing simple test at start that file size is greater than what will fit in first packet
 
I will fix in morning, but probably about line 2505
Code:
  // first copy in the rest of the first packet into the diskbuffer.
  int cb_recv = MTP_RX_SIZE - sizeof(MTPHeader);
  check_memcpy(disk_buffer_, rx_data_buffer + sizeof(MTPHeader), cb_recv, disk_buffer_, DISK_BUFFER_SIZE);
  c_read_em = 1;
  len -= cb_recv;
  disk_pos = cb_recv;
Should have test:
Code:
  int cb_recv = MTP_RX_SIZE - sizeof(MTPHeader);
  if (cb_recv > len) cb_recv = len;   
  check_memcpy(disk_buffer_, rx_data_buffer + sizeof(MTPHeader), cb_recv, disk_buffer_, DISK_BUFFER_SIZE);
  c_read_em = 1;
  len -= cb_recv;
  disk_pos = cb_recv;
 
I will fix in morning, but probably about line 2505
Code:
  // first copy in the rest of the first packet into the diskbuffer.
  int cb_recv = MTP_RX_SIZE - sizeof(MTPHeader);
  check_memcpy(disk_buffer_, rx_data_buffer + sizeof(MTPHeader), cb_recv, disk_buffer_, DISK_BUFFER_SIZE);
  c_read_em = 1;
  len -= cb_recv;
  disk_pos = cb_recv;
Should have test:
Code:
  int cb_recv = MTP_RX_SIZE - sizeof(MTPHeader);
  if (cb_recv > len) cb_recv = len;   
  check_memcpy(disk_buffer_, rx_data_buffer + sizeof(MTPHeader), cb_recv, disk_buffer_, DISK_BUFFER_SIZE);
  c_read_em = 1;
  len -= cb_recv;
  disk_pos = cb_recv;
Yep just found that as well, without that test
Code:
  // first copy in the rest of the first packet into the diskbuffer.
  int cb_recv = MTP_RX_SIZE - sizeof(MTPHeader);
  check_memcpy(disk_buffer_, rx_data_buffer + sizeof(MTPHeader), cb_recv, disk_buffer_, DISK_BUFFER_SIZE);
  c_read_em = 1;
  len -= cb_recv;
  disk_pos = cb_recv;

printf("Before while len>0: %d, %d\n", cb_recv, len);
--------------
MTPD::SendObject: len:51
Before while len>0: 500, -449
 
Well thank you guys for the confirmation and thanks for the hell of a job you guys are doing here ;).
I am using this for easy file transfer between PC and my own build ATARI hard drive emulation based on Teensy 4.1 for Atari ST/e ACSI port this peripheral bus is very similiar to the industry standard SCSI (Small Computer Systems Interface) bus.
 
Back
Top