MTP Responder Contribution

Good day/night @all ...
SD card delete on Windows does not delete the file on Windows - something observed here post #666

Yup, on windows, this works when Kurt merges my pullrequest.

Edit:
I've now commented out #define MTP_VERBOSE_PRINT_CONTAINER 1
and guess what.. ... deleting works now, with linux.
I can even create a new directory, and a new empty file (without contents)
 
Last edited:
Yup, on windows, this works when Kurt merges my pullrequest.

Just gave it a test on a T4.1 with the Built-in card. Deleted several files and restarted the T4.1. The files I created were still present on the card after restart. Yes I incorporated your PR:
Code:
void MTPStorage_SD::removeFile(uint32_t store, char *file)
{ 
  char tname[MAX_FILENAME_LEN];
  
  File f1=sd_open(store,file,0);
  File f2;
  while(f2=f1.openNextFile())
  { sprintf(tname,"%s/%s",file,f2.name());
    [B]if(!f2.isDirectory()) removeFile(store,tname); else sd_remove(store,tname);[/B]
  }
  sd_rmdir(store,file);
}

Again this is on a Windows10x64 PC
 
Just gave it a test on a T4.1 with the Built-in card. Deleted several files and restarted the T4.1. The files I created were still present on the card after restart. Yes I incorporated your PR:
Code:
void MTPStorage_SD::removeFile(uint32_t store, char *file)
{ 
  char tname[MAX_FILENAME_LEN];
  
  File f1=sd_open(store,file,0);
  File f2;
  while(f2=f1.openNextFile())
  { sprintf(tname,"%s/%s",file,f2.name());
    [B]if(!f2.isDirectory()) removeFile(store,tname); else sd_remove(store,tname);[/B]
  }
  sd_rmdir(store,file);
}

Again this is on a Windows10x64 PC

Same here. Deleted just the 'AUDIO...PDF' - did a TyComm Rest and the file still present.
 
hm. interesting. you are right.
It must have worked, because my files from a few hours ago are still deleted.... grmbl....!"§$%
 
That seems a PC MTP-initiator problem (not to act on reset event)

@WMXZ - In my case I literally turned power off and the back on and the files were still there. If I did a reset (from Kurt's sketch) I didn't see the files until I did a restart of the T4.1 I do remember that we tested the deletes on they worked early on but been playing with flash so haven't played with SD card in a very long time.

@Frank B - maybe you changed something else as well?
 
That seems a PC MTP-initiator problem (not to act on reset event)

Not sure what that means? The Reset was a board Reset with TyComm GUI button that restarts the Teensy.

I just did rename of Audio_workshop.pdf to xA...PDF and copied two images and another copy of A...PDF

On Reset all files still present.

Also after 'delete' doing a COPY of the file again does NOT complain about 'overwrite existing file'

ALSO: Delete on 'WINBOND' does remove the file

<edit>: ALSO to confirm right source edit ... I put this ERROR 'x' on the line and it reported error:
T:\tCode\libraries\MTP_t4-MEM_send_object_large\src\Storage.cpp:306:1: error: 'x' was not declared in this scope
x if(!f2.isDirectory()) removeFile(store,tname); else sd_remove(store,tname);
 
Not sure what that means? The Reset was a board Reset with TyComm GUI button that restarts the Teensy.

What does the MTP debug log say?
is the PC restarting MTP initialization?
Teensy may reboot too fast for MTP initiator to react, I don't know.
Anyhow MTP works fine for me, so I have no urgent need for changes.
 
pulled in two PRs....

Did not see them as since I am not owner of main library, it does not send me notifications unless @kurte ...
 
Note: The remove file code still does not smell correct to me: I will instrument more, but.

We call: bool MTPStorage_SD::DeleteObject(uint32_t object)

Which properly removes this object form the list...

And in my case I was deleting Drake.jpg
So it creates the path: "\Drake.jpg"
And calls removeFile with it... removeFile(r.store,filename);


Code:
void MTPStorage_SD::removeFile(uint32_t store, char *file)
{ 
  char tname[MAX_FILENAME_LEN];
  
  File f1=sd_open(store,file,0);
  File f2;
  while(f2=f1.openNextFile())
  { sprintf(tname,"%s/%s",file,f2.name());
    if(!f2.isDirectory()) removeFile(store,tname); else sd_remove(store,tname);
  }
  sd_rmdir(store,file);
}
I could be wrong but I feel this function has several issues:

It calls sd_open on our file. It then tries to open up the next file... But this is not a directory so I would assume this would return f2 logical would return false and the while loop would exit,
at which time f1 is still open, not sure that matters, but then we call sd_rmdir with our file which is NOT a directory?

My guess is the fix is to
a) undo the delete PR and inside removeFile it should again be:
Code:
    if(f2.isDirectory()) removeFile(store,tname); else sd_remove(store,tname);
So if it is a directory it recurses on itself and calls remove file else it simply removes the file.

b) in ::deleteObject method it should have the same code:
i.e. change:
Code:
    removeFile(r.store,filename);
to:
Code:
    if(f2.isDirectory()) removeFile(store,tname); else sd_remove(store,tname);

Will test it out!

Maybe removeFile should be renamed to something like: recursiveDeleteDirectory
 
I think I fixed it. Did not change the calling function like I mentioned but instead at the start of removeFile only do what it was doing if the passed in file is a directory, else it calls remove...

Code:
void MTPStorage_SD::removeFile(uint32_t store, char *file)
{ 
  char tname[MAX_FILENAME_LEN];
  
  File f1=sd_open(store,file,0);
  if(f1.isDirectory())
  {  File f2;
    while(f2=f1.openNextFile())
    { sprintf(tname,"%s/%s",file,f2.name());
      if(f2.isDirectory()) removeFile(store,tname); else sd_remove(store,tname);
    }
    sd_rmdir(store,file);
  }
  else
  {
    sd_remove(store,file);
  }
}
 
I think I fixed it. Did not change the calling function like I mentioned but instead at the start of removeFile only do what it was doing if the passed in file is a directory, else it calls remove...

Code:
void MTPStorage_SD::removeFile(uint32_t store, char *file)
{ 
  char tname[MAX_FILENAME_LEN];
  
  File f1=sd_open(store,file,0);
  if(f1.isDirectory())
  {  File f2;
    while(f2=f1.openNextFile())
    { sprintf(tname,"%s/%s",file,f2.name());
      if(f2.isDirectory()) removeFile(store,tname); else sd_remove(store,tname);
    }
    sd_rmdir(store,file);
  }
  else
  {
    sd_remove(store,file);
  }
}

That looks good. I'll try with linux.
It has still the problem, that reading or writing files does not work.
Creating emtpy files or directories works since i have disabled all the printfs.. and no "timeout" anymore.
 
Thanks,
Will boot up linux as well soon.

Right now playing with Teensy 4.1 board designs to play with Hexapods over on the Robotshop forum...
 
That looks good. I'll try with linux.
It has still the problem, that reading or writing files does not work.
Creating emtpy files or directories works since i have disabled all the printfs.. and no "timeout" anymore.

That altered MTPStorage_SD::removeFile() works here on Windows. (T_4.0 on LogLow breakout)

I deleted 3 of the previous files and hit GUI/RESET in TyComm

Teensy comes back now without those files!

One more test file was present - deleted that and Reset - File was gone on return!

And COOL win10 finally asked what to do when 'Teensy' appears and I said 'open file folder' so on Reset it closes Explorer and Auto opens on Teensy when it returns after restarting.

Removed the SD card to Win10 machine and no fatal errors - but it did clean up some "instance tags". Note I had not done this before so these entries may have come from other use/abuse.
Code:
Chkdsk was executed in read/write mode.  

Checking file system on I:

Stage 1: Examining basic file system structure ...
Cleaning up instance tags for file 0x76c92.
Cleaning up instance tags for file 0x76e27.
Cleaning up instance tags for file 0x77092.
Cleaning up instance tags for file 0x770b6.
Cleaning up instance tags for file 0x77343.
Cleaning up instance tags for file 0x77375.
Cleaning up instance tags for file 0x7737b.
  1188864 file records processed.                                                         File verification completed.
 Phase duration (File record verification): 54.30 seconds.
  7989 large file records processed.                                     Phase duration (Orphan file record recovery): 0.00 milliseconds.
  0 bad file records processed.                                       Phase duration (Bad file record checking): 1.55 milliseconds.

Stage 2: Examining file name linkage ...
  2807 reparse records processed.                                         1366196 index entries processed.                                                        Index verification completed.
 Phase duration (Index verification): 4.88 minutes.

 Phase duration (Orphan reconnection): 1.57 seconds.

 Phase duration (Orphan recovery to lost and found): 3.43 seconds.
  2807 reparse records processed.                                        Phase duration (Reparse point and Object ID verification): 21.26 milliseconds.

Stage 3: Examining security descriptors ...
Cleaning up 229 unused index entries from index $SII of file 0x9.
Cleaning up 229 unused index entries from index $SDH of file 0x9.
Cleaning up 229 unused security descriptors.
Security descriptor verification completed.
 Phase duration (Security descriptor verification): 91.73 milliseconds.
  88667 data files processed.                                             Phase duration (Data attribute verification): 1.41 milliseconds.
CHKDSK is verifying Usn Journal...
Usn Journal verification completed.

Windows has made corrections to the file system.
No further action is required.
 
That looks good. I'll try with linux.
It has still the problem, that reading or writing files does not work.
Creating emtpy files or directories works since i have disabled all the printfs.. and no "timeout" anymore.

Ok made the change and seems to be working. When you delete the file it stays deleted even after a T4.1 power off/power on restart.

Not sure what happened but now for some strange reason I can not seem to transfer the workshop.pdf (8.5MB) file to the 64MB Flash or any of the NAND even with large buffer set to true?
Code:
,+,,,,,,,,,,,,,,,:+,,,,,,,,,,+.+WR 2048 2048 1445 8890368 341 1441
,,,,,,,,,,,,,,,:::::::::::........
*** SendObject TImeout ***
*** tranfer did not complete fully ***
CL 8892416
RESP:2005(RSP:OPERATION_NOT_SUPPORTED)l: 12 T:23

It seems to die right at the end on the 1G or 2G chip. May be my sketch or I messed something up some place.
 
Then made a folder 'test' and copied 4 files into that folder.

Then deleted that folder.

Reset of Teensy showed the folder gone.

Moved SD to Win10 and it said no need to Scan { which it also said above p#740 }.

Then Scanning showed the same set of 'instance tags' being addressed, but no other issues.

And BTW: On Windows reading files works just fine TXT or PDF.
 
Works with Lubuntu-Linux, too.
Good work.

But I would re-think sprintf.. don't you want to use snprintf?
 
@KurtE
Did a little more playing after diner.

Seems the NAND's (1G/2G) don't like using LARGE_BUFFER (addFileSystem(......., true) - they fail to transfer the 8.5 MB workshop pdf. However, if I set it to false the transfer completes successfully and I can open, delete and read the file from the NAND's.

For the 64MB (25Q512) chips, large buffer = true gets about half way through then fails:
Code:
.+WR 2048 2048 5781413 2058240 4000 6043
.+.+.+.+.+.+.+@WR 2048 2048 5777829 2060288 4000 48772
.+WR 2048 2048 5777317 2062336 4000 6079
.+.+.+...............   [transfer starts fails at this point....]
If I set it to false for the 64MB chips - it fails almost as soon as it starts.
 
@mjs513 - Yep everything is very timing critical...
Is it running with a secondary buffer?

In my version of the sketch I have in setup:
Code:
#ifdef ARDUINO_TEENSY41
  if (external_psram_size) {
    send_object_buffer_size = SEND_BUFFER_SIZE_EXTMEM;
    send_object_buffer = (char*)extmem_malloc(send_object_buffer_size);
  }
#endif
  if (!send_object_buffer) {
    send_object_buffer_size = SEND_BUFFER_SIZE_DMAMEM;
    send_object_buffer = (char*)malloc(send_object_buffer_size);
  }
  if (send_object_buffer) mtpd.addSendObjectBuffer(send_object_buffer, send_object_buffer_size);
Where I defined very large buffers...

Note in your debug output:
Code:
.+WR 2048 2048 5781413 2058240 4000 6043
.+.+.+.+.+.+.+@WR 2048 2048 5777829 2060288 4000 48772
.+WR 2048 2048 5777317 2062336 4000 6079
.+.+.+...............   [transfer starts fails at this point....]
The @ says I have filled the buffer and so I stop the reading of data until that next write goes through

Or course there could be bugs in the code 8)

@Frank - I agree with you. Maybe I should include this with my Pull Request back to @WMXZ
 
@KurtE
Yes it should be running with the secondary buffer. I copied that over into my version of the sketch.

Know this may sound strange but instead of using a straight buffer have you thought about using a circular buffer instead. Not sure how to implement in the send object code. I do remember we used on spitranfer from tonton81 very successfully. He even has a circular buffer lib that makes it easy.

On my phone right now. I’ll post the link in the morning. Time for some zzzz’s
 
Did a NAND test in mtp-test : found it takes setting two NAND #define flags to build.

That was on T_4.1 with QSPI.
 
Did a NAND test in mtp-test : found it takes setting two NAND #define flags to build.

That was on T_4.1 with QSPI.

Not sure what you mean by takes two NAND #defines? Should only need:
Code:
#define USE_LFS_QSPI_NAND  1
to use.

Remember that on the memory board CS 3 and 4 correspond to NAND 1G and 2G chips. CS 5 and 6 correspond to the NOR 25Q512 (64MB) chip which requires:
Code:
#define USE_LFS_SPI 1
to use.

Did just a find a copy&paste error though when using QSPI NAND when using my version of the sketch. Lines 346 to 354 need to read:
Code:
    #if USE_LFS_QSPI_NAND==1
    for(int ii=0; ii<qnspi_nsd;ii++)
    {
      if (store_fs == &qnspifs[ii] ) 
      { lfs = &qnspifs[ii];
        break;
      }
    }
    #endif
Here is the updated sketch that I am using where I either enabled or disabled large memory buffers as Kurt mentioned in an earlier thread:
Code:
#include "Arduino.h"

#include "SD.h"
#include "MTP.h"

extern "C" {
  extern uint8_t external_psram_size;
}

#define USE_EVENTS 1

#if USE_EVENTS==1
  extern "C" int usb_init_events(void);
#else
  int usb_init_events(void) {}
#endif


#if defined(__IMXRT1062__)
  // following only as long usb_mtp is not included in cores
  #if !__has_include("usb_mtp.h")
    #include "usb1_mtp.h"
  #endif
#else
  #ifndef BUILTIN_SCCARD 
    #define BUILTIN_SDCARD 254
  #endif
  void usb_mtp_configure(void) {}
#endif

#define USE_SD 0
#define HAVE_LITTLEFS 1 // set to zero if no LtttleFS is existing or to be used
#if HAVE_LITTLEFS==1
  #include "LittleFS.h"
  #include "LittleFS_NAND.h"
#ifdef ARDUINO_TEENSY41
#define USE_LFS_RAM 0     // T4.1 PSRAM (or RAM)
#else
#define USE_LFS_RAM 0     // T4.1 PSRAM (or RAM)
#endif
  #define USE_LFS_PROGM 0   // T4.4 Progam Flash
  #define USE_LFS_SPI 0
  #define USE_LFS_QSPI 0
  #define USE_LFS_NAND 0
  #define USE_LFS_QSPI_NAND 1
  #define USE_LFS_FRAM 0

  #define ENABLE_LARGE_BUFFER true
  #define DISABLED_LARGE_BUFFER false
#endif



/****  Start device specific change area  ****/

  // edit SPI to reflect your configuration (following is fot T4.1)
  #define SD_MOSI 11
  #define SD_MISO 12
  #define SD_SCK  13

  #define SPI_SPEED SD_SCK_MHZ(16)  // adjust to sd card 

// SDClasses
  const char *sd_str[]={"sdio"}; // edit to reflect your configuration
  const int cs[] = {BUILTIN_SDCARD}; // edit to reflect your configuration
  const int nsd = sizeof(cs)/sizeof(int);

SDClass sdx[nsd];

//LittleFS classes
#if HAVE_LITTLEFS==1
  #include "LittleFS.h"
  #if USE_LFS_RAM == 1
    const char *ram_str[]={"RAM0", "RAM1"};     // edit to reflect your configuration
    const int ram_size[] = {2'000'000, 4'000'000};
    const int ram_nsd = sizeof(ram_size)/sizeof(int);
    LittleFS_RAM ramfs[ram_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
  
  #if USE_LFS_SPI == 1
    const char *spi_str[]={"Winbond5","Winbond6"};     // edit to reflect your configuration
    const int spi_cs[] = {5,6}; // edit to reflect your configuration
    const int spi_nsd = sizeof(spi_cs)/sizeof(int);
    LittleFS_SPIFlash spifs[spi_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
  
  #if USE_LFS_FRAM == 1
    const char *fram_str[]={"CYPRESS"};     // edit to reflect your configuration
    const int fram_cs[] = {10}; // edit to reflect your configuration
    const int fram_nsd = sizeof(fram_cs)/sizeof(int);
    LittleFS_SPIFlash fram[fram_nsd]; // needs to be declared if LittleFS is used in storage.h
  #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[]={"WINBOND1G"};     // edit to reflect your configuration
    const int qnspi_nsd = 1;
    LittleFS_QPINAND qnspifs[qnspi_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif
  
  #if USE_LFS_QSPI == 1
    const char *qspi_str[]={"QSPI0"};     // edit to reflect your configuration
    const int qspi_nsd = 1;
    LittleFS_QSPIFlash qspifs[qspi_nsd]; // needs to be declared if LittleFS is used in storage.h
  #endif

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

  LittleFS_Program progmfs[nfs_progm]; 
#endif

#endif


MTPStorage_SD storage;
MTPD    mtpd(&storage);

char *send_object_buffer = nullptr;
uint32_t send_object_buffer_size = 0;
#define SEND_BUFFER_SIZE_EXTMEM 1048576  // 1mb to start?
#define SEND_BUFFER_SIZE_DMAMEM 131072  // 128KB?  // Need to experiment...


void storage_configure()
{
  #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)
        {
          if(!sdx[ii].sdfs.begin(SdioConfig(FIFO_SDIO))) 
          { Serial.printf("SDIO 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("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].sdfs.begin(SdSpiConfig(cs[ii], SHARED_SPI, SPI_SPEED))) 
        { 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);
        }
      }
    }
    #endif

    #if HAVE_LITTLEFS==1
      #if USE_LFS_RAM == 1
        for(int ii=0; ii<ram_nsd;ii++)
        {
          { if(!ramfs[ii].begin(ram_size[ii])) { Serial.println("No storage"); while(1);}
            storage.addFilesystem(ramfs[ii], ram_str[ii]);
          }
          uint64_t totalSize = ramfs[ii].totalSize();
          uint64_t usedSize  = ramfs[ii].usedSize();
          Serial.printf("Storage %d %s ",ii,ram_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

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

      #if USE_LFS_SPI == 1
        for(int ii=0; ii<spi_nsd;ii++) {
          pinMode(spi_cs[ii],OUTPUT); digitalWriteFast(spi_cs[ii],HIGH);
          if(!spifs[ii].begin(spi_cs[ii], SPI)) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(spifs[ii], spi_str[ii], ENABLED_LARGE_BUFFER);
          
        uint64_t totalSize = spifs[ii].totalSize();
        uint64_t usedSize  = spifs[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,spi_cs[ii],spi_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_LFS_FRAM == 1
        for(int ii=0; ii<fram_nsd;ii++) {
          pinMode(fram_cs[ii],OUTPUT); digitalWriteFast(fram_cs[ii],HIGH);
          if(!fram[ii].begin(fram_cs[ii], SPI)) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(fram[ii], fram_str[ii], DISABLED_LARGE_BUFFER);
          
        uint64_t totalSize = fram[ii].totalSize();
        uint64_t usedSize  = fram[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,fram_cs[ii],fram_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_LFS_NAND == 1
        for(int ii=0; ii<nspi_nsd;ii++) {
          pinMode(nspi_cs[ii],OUTPUT); digitalWriteFast(nspi_cs[ii],HIGH);
          if(!nspifs[ii].begin(nspi_cs[ii], SPI)) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(nspifs[ii], nspi_str[ii], DISABLED_LARGE_BUFFER);
          
        uint64_t totalSize = nspifs[ii].totalSize();
        uint64_t usedSize  = nspifs[ii].usedSize();
        Serial.printf("Storage %d %d %s ",ii,nspi_cs[ii],nspi_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_LFS_QSPI_NAND == 1
       for(int ii=0; ii<qnspi_nsd;ii++) {
          if(!qnspifs[ii].begin()) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(qnspifs[ii], qnspi_str[ii], DISABLED_LARGE_BUFFER);
     
          uint64_t totalSize = qnspifs[ii].totalSize();
          uint64_t usedSize  = qnspifs[ii].usedSize();
          Serial.printf("Storage %d %s ",ii,qnspi_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif

      #if USE_LFS_QSPI == 1
       for(int ii=0; ii<qspi_nsd;ii++) {
          if(!qspifs[ii].begin()) {Serial.println("No storage"); while(1);}
          storage.addFilesystem(qspifs[ii], qspi_str[ii], ENABLE_LARGE_BUFFER);
     
          uint64_t totalSize = qspifs[ii].totalSize();
          uint64_t usedSize  = qspifs[ii].usedSize();
          Serial.printf("Storage %d %s ",ii,qspi_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      #endif
      
    #endif
}

 // try to get the right FS for this store and then call it's format if we have one...
  bool mtpd_format_cb(uint32_t store, uint32_t p2)
  {
    // lets try to map the store to the actual FS object.
    Serial.printf("Format Callback: store: %u p2:%u\n", store, p2);
    FS *store_fs = storage.getStoreFS(store); 
    LittleFS *lfs = nullptr;
    SDClass *sfs = nullptr;
  #if USE_SD==1
    for(int ii=0; ii<nsd; ii++)
    { 
      if (store_fs == &sdx[ii] ) 
      { sfs = &sdx[ii];
        break;
      }
    }
    #endif

    #if USE_LFS_RAM==1
    for(int ii=0; ii<ram_nsd;ii++)
    {
      if (store_fs == &ramfs[ii] ) 
      { lfs = &ramfs[ii];
        break;
      }
    }
    #endif

    #if USE_LFS_PROGM==1
    for(int ii=0; ii<nfs_progm;ii++)
    {
      if (store_fs == &progmfs[ii] ) 
      { lfs = &progmfs[ii];
        break;
      }
    }
    #endif

    #if USE_LFS_QSPI==1
    for(int ii=0; ii<qspi_nsd;ii++)
    {
      if (store_fs == &qspifs[ii] ) 
      { lfs = &qspifs[ii];
        break;
      }
    }
    #endif

    #if USE_LFS_SPI==1
    for(int ii=0; ii<spi_nsd;ii++)
    {
      if (store_fs == &spifs[ii] ) 
      { lfs = &spifs[ii];
        break;
      }
    }
    #endif
  
  
    #if USE_LFS_FRAM==1
    for(int ii=0; ii<fram_nsd;ii++)
    {
      if (store_fs == &fram[ii] ) 
      { lfs = &fram[ii];
        break;
      }
    }
    #endif

    #if USE_LFS_NAND==1
    for(int ii=0; ii<nspi_nsd;ii++)
    {
      if (store_fs == &nspifs[ii] ) 
      { lfs = &nspifs[ii];
        break;
      }
    }
    #endif  
  
    #if USE_LFS_QSPI_NAND==1
    for(int ii=0; ii<qnspi_nsd;ii++)
    {
      if (store_fs == &qnspifs[ii] ) 
      { lfs = &qnspifs[ii];
        break;
      }
    }
    #endif  
  
  
    // see if we have an lfs
    if (lfs) 
    { Serial.printf("Quick Format: %s\n", storage.getStoreName(store));
      return lfs->quickFormat();
    }
    else if (sfs)
    { Serial.printf("Format of SD types not implemented yet\n");

    }
    else Serial.println("Did not find Store in list???");
    return false;

  }


/****  End of device specific change area  ****/

  #if USE_SD==1
    // Call back for file timestamps.  Only called for file create and sync(). needed by SDFat-beta
    #include "TimeLib.h"
    void dateTime(uint16_t* date, uint16_t* time, uint8_t* ms10) 
    { *date = FS_DATE(year(), month(), day());
      *time = FS_TIME(hour(), minute(), second());
      *ms10 = second() & 1 ? 100 : 0;
    }
  #endif

void setup()
{ 
  #if defined(USB_MTPDISK_SERIAL) 
    while(!Serial); // comment if you do not want to wait for terminal
  #else
    while(!Serial.available()); // comment if you do not want to wait for terminal (otherwise press any key to continue)
    //while(!Serial.available() && millis() < 5000); // or third option to wait up to 5 seconds and then continue
  #endif
  Serial.println("MTP_test");

#ifdef ARDUINO_TEENSY41
  if (external_psram_size) {
    send_object_buffer_size = SEND_BUFFER_SIZE_EXTMEM;
    send_object_buffer = (char*)extmem_malloc(send_object_buffer_size);
  }
#endif
  if (!send_object_buffer) {
    send_object_buffer_size = SEND_BUFFER_SIZE_DMAMEM;
    send_object_buffer = (char*)malloc(send_object_buffer_size);
  }
  if (send_object_buffer) mtpd.addSendObjectBuffer(send_object_buffer, send_object_buffer_size);

  

  #if USE_EVENTS==1
    usb_init_events();
  #endif

  #if !__has_include("usb_mtp.h")
    usb_mtp_configure();
  #endif
  storage_configure();

  #if USE_SD==1
  // Set Time callback // needed for SDFat
  FsDateTime::callback = dateTime;

  {
    const char *str = "test1.txt";
    if(sdx[0].exists(str)) sdx[0].remove(str);
    File file=sdx[0].open(str,FILE_WRITE_BEGIN);
        file.println("This is a test line");
    file.close();

    Serial.println("\n**** dir of sd[0] ****");
    sdx[0].sdfs.ls();
  }

  #endif
  #if USE_RAM==1
    for(int ii=0; ii<10;ii++)
    { char filename[80];
      sprintf(filename,"/test_%d.txt",ii);
      File file=ramfs[0].open(filename,FILE_WRITE_BEGIN);
        file.println("This is a test line");
      file.close();
    }
    ramfs[0].mkdir("Dir0");
    for(int ii=0; ii<10;ii++)
    { char filename[80];
      sprintf(filename,"/Dir0/test_%d.txt",ii);
      File file=ramfs[0].open(filename,FILE_WRITE_BEGIN);
        file.println("This is a test line");
      file.close();
    }
    ramfs[0].mkdir("Dir0/dir1");
    for(int ii=0; ii<10;ii++)
    { char filename[80];
      sprintf(filename,"/Dir0/dir1/test_%d.txt",ii);
      File file=ramfs[0].open(filename,FILE_WRITE_BEGIN);
        file.println("This is a test line");
      file.close();
    }
    uint32_t buffer[256];
    File file = ramfs[1].open("LargeFile.bin",FILE_WRITE_BEGIN);
    for(int ii=0;ii<3000;ii++)
    { memset(buffer,ii%256,1024);
      file.write(buffer,1024);
    }
    file.close();

  #endif

  // WIP - try format callback code.
  mtpd.setFormatCB(&mtpd_format_cb);

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

void loop()
{ 
  mtpd.loop();

#if USE_EVENTS==1
  if(Serial.available())
  {
    char ch=Serial.read();
    Serial.println(ch);
    if(ch=='r') 
    {
      Serial.println("Reset");
      mtpd.send_DeviceResetEvent();
    }
    if (ch=='d')
    {
      // first dump list of storages:
      uint32_t fsCount = storage.getFSCount();
      Serial.printf("\nDump Storage list(%u)\n", fsCount);
      for (uint32_t ii = 0; ii < fsCount; ii++) {
        Serial.printf("store:%u name:%s fs:%x ROYW:%x\n", ii, storage.getStoreName(ii), (uint32_t)storage.getStoreFS(ii), storage.getReadOnYieldWrites(ii));
      }
      Serial.println("\nDump Index List");
      storage.dumpIndexList();
    }
    #if USE_LFS_RAM==1
      if(ch=='a') 
      {
        Serial.println("Add Files");
      static int next_file_index_to_add=100;
        uint32_t store = storage.getStoreID("RAM1");
        for(int ii=0; ii<10;ii++)
        { char filename[80];
          sprintf(filename,"/test_%d.txt",next_file_index_to_add++);
          Serial.println(filename);
          File file=ramfs[0].open(filename,FILE_WRITE_BEGIN);
            file.println("This is a test line");
            file.println("This is a test line");
            file.println("This is a test line");
            file.println("This is a test line");
            file.println("This is a test line");
            file.println("This is a test line");
            file.println("This is a test line");
            file.println("This is a test line");
            file.println("This is a test line");
            file.println("This is a test line");
          file.close();
          mtpd.send_addObjectEvent(store, filename);
        }
        // attempt to notify PC on added files (does not work yet)
        Serial.print("Store "); Serial.println(store);
        mtpd.send_StorageInfoChangedEvent(store);
      }
      if(ch=='x') 
      {
        Serial.println("Delete Files");
        static int next_file_index_to_delete=100;
        uint32_t store = storage.getStoreID("RAM1");
        for(int ii=0; ii<10;ii++)
        { char filename[80];
          sprintf(filename,"/test_%d.txt",next_file_index_to_delete++);
          Serial.println(filename);
          if (ramfs[0].remove(filename))
          {
            mtpd.send_removeObjectEvent(store, filename);
          }
        }
        // attempt to notify PC on added files (does not work yet)
        Serial.print("Store "); Serial.println(store);
        mtpd.send_StorageInfoChangedEvent(store);
      }
    #elif USE_SD==1
      if(ch=='a') 
      {
        Serial.println("Add Files");
        static int next_file_index_to_add=100;
        uint32_t store = storage.getStoreID("sdio");
        for(int ii=0; ii<10;ii++)
        { char filename[80];
          sprintf(filename,"/test_%d.txt",next_file_index_to_add++);
          Serial.println(filename);
          File file=sdx[0].open(filename,FILE_WRITE_BEGIN);
            file.println("This is a test line");
          file.close();
          mtpd.send_addObjectEvent(store, filename);
        }
        // attempt to notify PC on added files (does not work yet)
        Serial.print("Store "); Serial.println(store);
        mtpd.send_StorageInfoChangedEvent(store);
      }
      if(ch=='x') 
      {
        Serial.println("Delete Files");
        static int next_file_index_to_delete=100;
        uint32_t store = storage.getStoreID("sdio");
        for(int ii=0; ii<10;ii++)
        { char filename[80];
          sprintf(filename,"/test_%d.txt",next_file_index_to_delete++);
          Serial.println(filename);
          if (sdx[0].remove(filename))
          {
            mtpd.send_removeObjectEvent(store, filename);
          }
        }
        // attempt to notify PC on added files (does not work yet)
        Serial.print("Store "); Serial.println(store);
        mtpd.send_StorageInfoChangedEvent(store);
      }
    #endif
  }
#endif
}
 
@mjs513 -
Changed this one and got compile error : #define USE_LFS_QSPI_NAND 1 //optional

Then saw I needed to set :: #define USE_LFS_NAND 1

Typical of cascading #ifdef he11 - only mentioned as it broke build after it seemed I set the needed flag.
 
Back
Top