MTP Responder Contribution

Note: you probably already noticed I changed my StorageIDs to have the high word by non zero, like: 10000003
I had that too, but having storageID above 16 bit did not change anything.
I know it violates the document, but coding was simpler.

one events:
notifying every new file, for me is not an option, as files are created while host is disconnected.
 
I had that too, but having storageID above 16 bit did not change anything.
I know it violates the document, but coding was simpler.

All I changed was:
Code:
#define Store2Storage(x) (x+1)
#define Storage2Store(x) (x-1)

to:
Code:
#define Store2Storage(x) (((x)+1) | 0x10000000ul)
#define Storage2Store(x) (((x) & 0xefffffff) -1)

one events:
notifying every new file, for me is not an option, as files are created while host is disconnected.
Again I am only playing...
But in the Notify functions I added, example:
Code:
  bool MTPD::notifyFileRemoved(FS *pfs, const char *pathname) 
  {
    char filename[MAX_FILENAME_LEN];
    uint32_t size, parent;
    uint16_t store;
    uint32_t handle = storage_->MapFileNameToIndex(pfs, pathname, false, false, nullptr);

    printf("notifyFileRemoved: %x:%x maps to handle: %x\n", (uint32_t)pfs, pathname, handle);
    if (handle != 0xFFFFFFFFUL) {
      send_removeObjectEvent(handle);

      storage_->GetObjectInfo(handle, filename, &size, &parent, &store);
      storage_->MarkObjectDeleted(handle);
      uint32_t storage = Store2Storage(store);
      printf("  parent: %x storage: %x -> %x\n", parent, store, storage);
//      printf("notify StorageInfoChanged : %x\n", storage);
//      send_StorageInfoChangedEvent(storage);
    }
    return false;

  }
The code will look for that object in the current MTP storage tree, if it is not found it won't send anything.
In the create case, if the parent directory is not in your storage list, again it won't send anything.

So assuming that the list is not created when you are not using MTP hopefully it would bail pretty quick. And if you get a disconnect like status... I have not played with this, I would hope maybe your
code would clear out all of the cached stuff... But again I am only playing :D
 
Quick FYI - Yesterday I played some more with adding some additional notify functions, to see what happens when I send some of them. So far nothing major.

However your simple send the Reset, appears to work pretty well. I was afraid it would close the explorer window and the like, which it did not. Also was not sure what it would do if I was browsing a directory or two deep when that happened. It appeared to recover when I asked it to go back to parent or the like. Will play more.

Again it will be a nice system component!
 
Quick FYI - Yesterday I played some more with adding some additional notify functions, to see what happens when I send some of them. So far nothing major.

However your simple send the Reset, appears to work pretty well. I was afraid it would close the explorer window and the like, which it did not. Also was not sure what it would do if I was browsing a directory or two deep when that happened. It appeared to recover when I asked it to go back to parent or the like. Will play more.

Again it will be a nice system component!

You all sound like you are having way too much fun with MTP :)
 
Happy New Year all....

Quick note on my USBHost MTP device host code.... As I mentioned earlier, my Kindle Fire uses MTP, although it does not register as MTP type protocol... So I thought I would try it on my older Kindle (paper type display, with sort of keyboard below the display). Battery dead... Ordered a replacement which I installed yesterday. Turns out this one does not do MTP... Instead it connects to USB as a drive type...
So it won't be much help for this:
Code:
Device Descriptor:
  12 01 00 02 00 00 00 40 49 19 04 00 00 01 01 02 03 01 
    VendorID = 1949, ProductID = 0004, Version = 0100
    Class/Subclass/Protocol = 0 / 0 / 0
    Number of Configurations = 1
enumeration:
enumeration:
Manufacturer: Amazon
enumeration:
Product: Amazon Kindle
enumeration:
Serial Number: B006A0A00484981A
enumeration:
Config data length = 32
enumeration:
Configuration Descriptor:
  09 02 20 00 01 01 04 C0 32 
    NumInterfaces = 1
    ConfigurationValue = 1
  09 04 00 00 02 08 06 50 05 
    Interface = 0
    Number of endpoints = 2
    Class/Subclass/Protocol = 8(Mass Storage) / 6(SCSI) / 80(Bulk Only)
  07 05 81 02 00 02 00 
    Endpoint = 1 IN
    Type = Bulk
    Max Size = 512
    Polling Interval = 0
  07 05 01 02 00 02 01 
    Endpoint = 1 OUT
    Type = Bulk
    Max Size = 512
    Polling Interval = 1
enumeration:
 
@WMXZ - for the life of me I have not been able to get MTP_T4 to compile. I cloned MTP_T4 and USB2 libraries and put them in the 'Arduino/libraries folder'. Beings I do not have the latest cores library from Paul I followed the instruction for adding 'modifications_for_cores_teensy4' to 'usb_desc.h'. I could not find 'MTP_DISK' in that file but found this 'USB_MTPDISK' instead. So I added the contents of 'modifications_for_cores_teensy4' after 'USB_MTPDISK' . Was this what was intended?

I am using Ubuntu-18.04.1 with arduino-1.8.13 with TD1.54B5 with USB Type: MTP Disk (Experimental). When I try to compile it I get this error:
Code:
Archiving built core (caching) in: /tmp/arduino_cache_8792/core/core_teensy_avr_teensy41_usb_mtp,speed_600,opt_o2std,keys_en-us_8d6f8024b451cf939d8871bc92051169.a
Linking everything together...
/home/wwatson/arduino-1.8.13/hardware/teensy/../tools/arm/bin/arm-none-eabi-gcc -O2 -Wl,--gc-sections,--relax -T/home/wwatson/arduino-1.8.13/hardware/teensy/avr/cores/teensy4/imxrt1062_t41.ld -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -o /tmp/arduino_build_133876/mtp-test.ino.elf /tmp/arduino_build_133876/sketch/mtp-test.ino.cpp.o /tmp/arduino_build_133876/libraries/SD/SD.cpp.o /tmp/arduino_build_133876/libraries/SdFat/FreeStack.cpp.o /tmp/arduino_build_133876/libraries/SdFat/MinimumSerial.cpp.o /tmp/arduino_build_133876/libraries/SdFat/ExFatLib/ExFatDbg.cpp.o /tmp/arduino_build_133876/libraries/SdFat/ExFatLib/ExFatFile.cpp.o /tmp/arduino_build_133876/libraries/SdFat/ExFatLib/ExFatFilePrint.cpp.o /tmp/arduino_build_133876/libraries/SdFat/ExFatLib/ExFatFileWrite.cpp.o /tmp/arduino_build_133876/libraries/SdFat/ExFatLib/ExFatFormatter.cpp.o /tmp/arduino_build_133876/libraries/SdFat/ExFatLib/ExFatPartition.cpp.o /tmp/arduino_build_133876/libraries/SdFat/ExFatLib/ExFatVolume.cpp.o /tmp/arduino_build_133876/libraries/SdFat/ExFatLib/upcase.cpp.o /tmp/arduino_build_133876/libraries/SdFat/FatLib/FatDbg.cpp.o /tmp/arduino_build_133876/libraries/SdFat/FatLib/FatFile.cpp.o /tmp/arduino_build_133876/libraries/SdFat/FatLib/FatFileLFN.cpp.o /tmp/arduino_build_133876/libraries/SdFat/FatLib/FatFilePrint.cpp.o /tmp/arduino_build_133876/libraries/SdFat/FatLib/FatFileSFN.cpp.o /tmp/arduino_build_133876/libraries/SdFat/FatLib/FatFormatter.cpp.o /tmp/arduino_build_133876/libraries/SdFat/FatLib/FatPartition.cpp.o /tmp/arduino_build_133876/libraries/SdFat/FatLib/FatVolume.cpp.o /tmp/arduino_build_133876/libraries/SdFat/FsLib/FsFile.cpp.o /tmp/arduino_build_133876/libraries/SdFat/FsLib/FsNew.cpp.o /tmp/arduino_build_133876/libraries/SdFat/FsLib/FsVolume.cpp.o /tmp/arduino_build_133876/libraries/SdFat/SdCard/SdCardInfo.cpp.o /tmp/arduino_build_133876/libraries/SdFat/SdCard/SdSpiCard.cpp.o /tmp/arduino_build_133876/libraries/SdFat/SdCard/SdioTeensy.cpp.o /tmp/arduino_build_133876/libraries/SdFat/SpiDriver/SdSpiArtemis.cpp.o /tmp/arduino_build_133876/libraries/SdFat/SpiDriver/SdSpiChipSelect.cpp.o /tmp/arduino_build_133876/libraries/SdFat/SpiDriver/SdSpiDue.cpp.o /tmp/arduino_build_133876/libraries/SdFat/SpiDriver/SdSpiESP.cpp.o /tmp/arduino_build_133876/libraries/SdFat/SpiDriver/SdSpiParticle.cpp.o /tmp/arduino_build_133876/libraries/SdFat/SpiDriver/SdSpiSTM32.cpp.o /tmp/arduino_build_133876/libraries/SdFat/SpiDriver/SdSpiTeensy3.cpp.o /tmp/arduino_build_133876/libraries/SdFat/USBmsController/USBmscDevice.cpp.o /tmp/arduino_build_133876/libraries/SdFat/USBmsController/USBmscInfo.cpp.o /tmp/arduino_build_133876/libraries/SdFat/common/FmtNumber.cpp.o /tmp/arduino_build_133876/libraries/SdFat/common/FsDateTime.cpp.o /tmp/arduino_build_133876/libraries/SdFat/common/FsStructs.cpp.o /tmp/arduino_build_133876/libraries/SdFat/common/PrintBasic.cpp.o /tmp/arduino_build_133876/libraries/SdFat/common/SysCallBareUno.cpp.o /tmp/arduino_build_133876/libraries/SdFat/iostream/StdioStream.cpp.o /tmp/arduino_build_133876/libraries/SdFat/iostream/StreamBaseClass.cpp.o /tmp/arduino_build_133876/libraries/SdFat/iostream/istream.cpp.o /tmp/arduino_build_133876/libraries/SdFat/iostream/ostream.cpp.o /tmp/arduino_build_133876/libraries/SPI/SPI.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/MassStorageDriver.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/adk.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/antplus.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/bluetooth.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/digitizer.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/ehci.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/enumeration.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/hid.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/hub.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/joystick.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/keyboard.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/keyboardHIDExtras.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/memory.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/midi.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/mouse.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/print.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/rawhid.cpp.o /tmp/arduino_build_133876/libraries/USBHost_t36/serial.cpp.o /tmp/arduino_build_133876/libraries/MTP_t4/MTP.cpp.o /tmp/arduino_build_133876/libraries/MTP_t4/Storage.cpp.o /tmp/arduino_build_133876/libraries/LittleFS/LittleFS.cpp.o /tmp/arduino_build_133876/libraries/LittleFS/littlefs/lfs.c.o /tmp/arduino_build_133876/libraries/LittleFS/littlefs/lfs_util.c.o /tmp/arduino_build_133876/libraries/USB2/usb1_mtp.c.o /tmp/arduino_build_133876/libraries/USB2/usb2.c.o /tmp/arduino_build_133876/libraries/USB2/usb2_desc.c.o /tmp/arduino_build_133876/libraries/USB2/usb2_mtp.c.o /tmp/arduino_build_133876/libraries/USB2/usb2_seremu.c.o /tmp/arduino_build_133876/libraries/USB2/usb2_serial.c.o /tmp/arduino_build_133876/libraries/Time/DateStrings.cpp.o /tmp/arduino_build_133876/libraries/Time/Time.cpp.o /tmp/arduino_build_133876/core/core.a -L/tmp/arduino_build_133876 -larm_cortexM7lfsp_math -lm -lstdc++
/tmp/arduino_build_133876/libraries/USB2/usb1_mtp.c.o: In function `get_mtp_txEventcount':
/home/wwatson/Arduino/libraries/USB2/src/usb1_mtp.c:65: multiple definition of `get_mtp_txEventcount'
/tmp/arduino_build_133876/libraries/MTP_t4/MTP.cpp.o:/home/wwatson/Arduino/libraries/MTP_t4/src/MTP.cpp:1430: first defined here
/home/wwatson/arduino-1.8.13/hardware/tools/arm/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld: Disabling relaxation: it will not work with multiple definitions
/tmp/arduino_build_133876/libraries/USB2/usb1_mtp.c.o: In function `tx_event':
/home/wwatson/Arduino/libraries/USB2/src/usb1_mtp.c:68: multiple definition of `get_mtp_rxEventcount'
/tmp/arduino_build_133876/libraries/MTP_t4/MTP.cpp.o:/home/wwatson/Arduino/libraries/MTP_t4/src/Storage.h:185: first defined here
/tmp/arduino_build_133876/libraries/USB2/usb1_mtp.c.o: In function `tx_event':
/home/wwatson/Arduino/libraries/USB2/src/usb1_mtp.c:68: multiple definition of `usb_mtp_recvEvent'
/tmp/arduino_build_133876/libraries/MTP_t4/MTP.cpp.o:/home/wwatson/Arduino/libraries/MTP_t4/src/Storage.h:185: first defined here
collect2: error: ld returned 1 exit status
Multiple libraries were found for "SD.h"
 Used: /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SD
 Not used: /home/wwatson/arduino-1.8.13/libraries/SD
Using library SD at version 2.0.0 in folder: /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SD 
Using library SdFat at version 2.0.0-beta.8 in folder: /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat 
Using library SPI at version 1.0 in folder: /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SPI 
Using library USBHost_t36 at version 0.1 in folder: /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/USBHost_t36 
Using library MTP_t4 at version 1.0.0-beta.1 in folder: /home/wwatson/Arduino/libraries/MTP_t4 
Using library LittleFS at version 1.0.0 in folder: /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/LittleFS 
Using library USB2 at version 0.9.0-beta.1 in folder: /home/wwatson/Arduino/libraries/USB2 
Using library Time at version 1.6 in folder: /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/Time 
Error compiling for board Teensy 4.1.

I am not sure of what I might be doing wrong. Any ideas:)
 
Ok - I finally got it to compile using the latest version of 'cores' without using 'USB2'. Now it gives this error when uploading:
Code:
error sending reboot command to /dev/hidraw0
Teensy did not respond to a USB-based request to enter program mode.
Please press the PROGRAM MODE BUTTON on your Teensy to upload your sketch.
the selected serial port Please press the PROGRAM MODE BUTTON on your Teensy to upload your sketch.
 does not exist or your board is not connected

I press the program button and it uploads but tycommander returns this error when enabling serial manually as it does not enable automatically:
Code:
permission denied for device '/dev/hidraw0'

Which I suppose is why the program button needs to be pressed to get it to upload.

Again, am i missing something?

If I 'sudo' tycommander after pressing the program button it will enable serial. I press 'enter' and get this:
Code:
MTP_test
SDIO Storage 0 254 sdio 31262687232 32833536
SD Storage 1 10 sd1 31262687232 32817152
RAM Storage 0 RAM1 1999872 512
RAM Storage 1 RAM2 4000000 512
Program Storage 0 PROGM 983040 8192
QSPI Storage 0 QSPI failed or missing
SPIFlash Storage 0 3 nand1 failed or missing
SPIFlash Storage 1 4 nand2 failed or missing
SPIFlash Storage 2 5 nand3 failed or missing
SPIFlash Storage 3 6 nand4 failed or missing

**** dir of sd[0] ****
32MEGfile.dat
test1.txt
TEENSYSD2_SDIO/
mtpindex.dat

Setup done
1002 16 1 0:  1
2001 16 3 0:  1


1002 16 1 0:  1
2001 16 3 0:  1
1002 16 1 0:  1
2001 16 3 0:  1
1001 12 1 1: 
2001 12 3 1:

The drive never appears in the disk manager. but will show up in the Linux shotwell program as 'Teensy MTP Disk'. It remains un-accessable.
 
Last edited:
Try getting new version of tycommander. Issue about changes to usb descriptor, if I remember correctly
 
I could not find 'MTP_DISK' in that file but found this 'USB_MTPDISK' instead. So I added the contents of 'modifications_for_cores_teensy4' after 'USB_MTPDISK' . Was this what was intended?
I corrected the Readme file (thanks for pointing out)

re TyCommander, I'm not using this, so I cannot comment
If you update boards.txt (modifications for teensy_avr) then there should be two entries MTP DISK (Experimental) and MTP Disk SERIAL (Experimental)
MTP DISK uses SEREMU
MTP DISK SERIAL uses SERIAL

Anyhow, on my VSCode dev system and using MTP DISK SERIAL, I have ALWAYS to remove monitor (Arduino or Putty) before trying to upload, or I have to press button.
This is most likely do residual incompatibility between Teensy.exe and MTP DISK SERIAL

I'm not familiar with modern Linux, (e.g. need to mount the MTP device, etc)
I know MTP is working on Linux. While I develop on Windows10, Hardware and Software is used also on Ubuntu.

Your log file indicates that initiator opened session, asks for device info, but never asks for storage info, therefore you only get device but not the disks.
 
Good morning...

Right now when I am playing with mtp-test,

I have a modified version of the setup code, that waits up to 5 seconds for Serial monitor to connect.
Code:
void setup()
{ 
  #if defined(USB_MTPDISK_SERIAL) 
    while(!Serial && millis() < 5000); // comment if you do not want to wait for terminal
  #else
    while(!Serial.available() && millis() < 5000); // comment if you do not want to wait for terminal (otherwise press any key to continue)
  #endif
  Serial.begin(115200);
  delay(250);

  Serial.println("MTP_test");
  Serial.flush();

This helps for example when I plug it in and I am not running terminal...
Also with the newer Seremu code, Paul added something in that waits for a USB device message to signal that there is a Serial monitor. So far there is not a new Terminal monitor that is part of the build that does it. So code that currently does: while (!Serial) ;
Will wait forever.
Which is why @WMXZ added in the #if around the two parts.

Recently I added Seremu support to USBHost code (side topic) where I have put code in to try to signal it... Not fully sure yet if it works. But do have my MTP Host test program where anything that comes in from the thing plugged into the host plug, that All Serial or Serial Emulation stuff is forwarded to(or from) the PC over SerialUSB1.

The main point is, you might check to see if your code is waiting forever, in which case none of the storages will be added...
 
@WMXZ
If you update boards.txt (modifications for teensy_avr) then there should be two entries MTP DISK (Experimental) and MTP Disk SERIAL (Experimental)
MTP DISK uses SEREMU
MTP DISK SERIAL uses SERIAL

Missed this step last night. I updated boards.txt. Now 'MTP Disk SERIAL (Experimental)' shows up in the tools menu.

Also for this:
Code:
permission denied for device '/dev/hidraw0'
I searched for this on the internet and found this link:
https://unix.stackexchange.com/questions/85379/dev-hidraw-read-permissions/85459
Then I added the following to '49-teensy.rules':
Code:
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", MODE="0664", GROUP="plugdev"

Right or wrong it took care of permissions error in both uploading to the T4.1 and in tycommander.

When selecting 'MTP Disk SERIAL (Experimental)' in the tools menu and compiling I get this spew:
Code:
/home/wwatson/arduino-1.8.13/hardware/teensy/../tools/arm/bin/arm-none-eabi-g++ -c -O2 -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -std=gnu++14 -fno-exceptions -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1062__ -DTEENSYDUINO=154 -DARDUINO=10813 -DARDUINO_TEENSY41 -DF_CPU=600000000 -DUSB_MTPDISK_SERIAL -DLAYOUT_US_ENGLISH -I/tmp/arduino_build_567358/pch -I/home/wwatson/arduino-1.8.13/hardware/teensy/avr/cores/teensy4 -I/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SD/src -I/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src -I/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SPI -I/home/wwatson/Arduino/libraries/MTP_t4/src -I/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/LittleFS/src -I/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/Time /tmp/arduino_build_567358/sketch/mtp-test.ino.cpp -o /tmp/arduino_build_567358/sketch/mtp-test.ino.cpp.o
In file included from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/ExFatLib/ExFatLib.h:27:0,
                 from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h:33,
                 from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SD/src/SD.h:27,
                 from /home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:3:
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/ExFatLib/ExFatVolume.h: In member function 'bool ExFatVolume::ls()':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/ExFatLib/ExFatVolume.h:209:16: error: 'Serial' was not declared in this scope
     return ls(&Serial);
                ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/ExFatLib/ExFatVolume.h: In member function 'bool ExFatVolume::ls(uint8_t)':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/ExFatLib/ExFatVolume.h:224:16: error: 'Serial' was not declared in this scope
     return ls(&Serial, flags);
                ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/ExFatLib/ExFatVolume.h: In member function 'bool ExFatVolume::ls(const ExChar_t*, uint8_t)':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/ExFatLib/ExFatVolume.h:241:16: error: 'Serial' was not declared in this scope
     return ls(&Serial, path, flags);
                ^
In file included from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FatLib/FatVolume.h:28:0,
                 from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FatLib/FatLib.h:27,
                 from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h:34,
                 from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SD/src/SD.h:27,
                 from /home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:3:
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FatLib/FatFile.h: In member function 'bool FatFile::ls(uint8_t)':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FatLib/FatFile.h:913:16: error: 'Serial' was not declared in this scope
     return ls(&Serial, flags);
                ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FatLib/FatFile.h: In member function 'size_t FatFile::printName()':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FatLib/FatFile.h:920:32: error: 'Serial' was not declared in this scope
     return FatFile::printName(&Serial);
                                ^
In file included from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FatLib/FatLib.h:27:0,
                 from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h:34,
                 from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SD/src/SD.h:27,
                 from /home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:3:
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FatLib/FatVolume.h: In member function 'bool FatVolume::ls(uint8_t)':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FatLib/FatVolume.h:223:16: error: 'Serial' was not declared in this scope
     return ls(&Serial, flags);
                ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FatLib/FatVolume.h: In member function 'bool FatVolume::ls(const char*, uint8_t)':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FatLib/FatVolume.h:240:16: error: 'Serial' was not declared in this scope
     return ls(&Serial, path, flags);
                ^
In file included from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FsLib/FsLib.h:31:0,
                 from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h:35,
                 from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SD/src/SD.h:27,
                 from /home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:3:
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FsLib/FsVolume.h: In member function 'bool FsVolume::ls()':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FsLib/FsVolume.h:235:16: error: 'Serial' was not declared in this scope
     return ls(&Serial);
                ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FsLib/FsVolume.h: In member function 'bool FsVolume::ls(uint8_t)':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FsLib/FsVolume.h:250:16: error: 'Serial' was not declared in this scope
     return ls(&Serial, flags);
                ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FsLib/FsVolume.h: In member function 'bool FsVolume::ls(const char*, uint8_t)':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FsLib/FsVolume.h:269:16: error: 'Serial' was not declared in this scope
     return ls(&Serial, path, flags);
                ^
In file included from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FsLib/FsLib.h:32:0,
                 from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h:35,
                 from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SD/src/SD.h:27,
                 from /home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:3:
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FsLib/FsFile.h: In member function 'bool FsBaseFile::ls(uint8_t)':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FsLib/FsFile.h:275:16: error: 'Serial' was not declared in this scope
     return ls(&Serial, flags);
                ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FsLib/FsFile.h: In member function 'bool FsBaseFile::ls()':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/FsLib/FsFile.h:279:16: error: 'Serial' was not declared in this scope
     return ls(&Serial);
                ^
In file included from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SD/src/SD.h:27:0,
                 from /home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:3:
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h: In member function 'void SdBase<Vol>::initErrorPrint()':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h:294:21: error: 'Serial' was not declared in this scope
     initErrorPrint(&Serial);
                     ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h: In member function 'void SdBase<Vol>::errorHalt(const __FlashStringHelper*)':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h:302:16: error: 'Serial' was not declared in this scope
     errorHalt(&Serial, msg);
                ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h: In member function 'void SdBase<Vol>::errorHalt()':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h:306:32: error: 'Serial' was not declared in this scope
   void errorHalt() {errorHalt(&Serial);}
                                ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h: In member function 'void SdBase<Vol>::errorHalt(const char*)':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h:312:47: error: 'Serial' was not declared in this scope
   void errorHalt(const char* msg) {errorHalt(&Serial, msg);}
                                               ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h: In member function 'void SdBase<Vol>::initErrorHalt()':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h:315:40: error: 'Serial' was not declared in this scope
   void initErrorHalt() {initErrorHalt(&Serial);}
                                        ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h: In member function 'void SdBase<Vol>::errorPrint(const char*)':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h:321:49: error: 'Serial' was not declared in this scope
   void errorPrint(const char* msg) {errorPrint(&Serial, msg);}
                                                 ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h: In member function 'void SdBase<Vol>::errorPrint(const __FlashStringHelper*)':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h:326:64: error: 'Serial' was not declared in this scope
   void errorPrint(const __FlashStringHelper* msg) {errorPrint(&Serial, msg);}
                                                                ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h: In member function 'void SdBase<Vol>::initErrorHalt(const char*)':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h:332:55: error: 'Serial' was not declared in this scope
   void initErrorHalt(const char* msg) {initErrorHalt(&Serial, msg);}
                                                       ^
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h: In member function 'void SdBase<Vol>::initErrorHalt(const __FlashStringHelper*)':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat/src/SdFat.h:339:20: error: 'Serial' was not declared in this scope
     initErrorHalt(&Serial, msg);
                    ^
In file included from /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SD/src/SD.h:35:0,
                 from /home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:3:
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/cores/teensy4/FS.h: In member function 'virtual void File::whoami()':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/cores/teensy4/FS.h:83:3: error: 'Serial' was not declared in this scope
   Serial.printf("  File    this=%x, f=%x\n", (int)this, (int)f);
   ^
In file included from /home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:3:0:
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SD/src/SD.h: In member function 'virtual void SDFile::whoami()':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SD/src/SD.h:70:3: error: 'Serial' was not declared in this scope
   Serial.printf("   SDFile this=%x, refcount=%u\n",
   ^
In file included from /home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:4:0:
/home/wwatson/Arduino/libraries/MTP_t4/src/MTP.h: At global scope:
/home/wwatson/Arduino/libraries/MTP_t4/src/MTP.h:78:23: error: 'MTP_RX_SIZE_480' was not declared in this scope
   #define MTP_RX_SIZE MTP_RX_SIZE_480 
                       ^
/home/wwatson/Arduino/libraries/MTP_t4/src/MTP.h:81:26: note: in expansion of macro 'MTP_RX_SIZE'
   uint8_t rx_data_buffer[MTP_RX_SIZE] __attribute__ ((aligned(32)));
                          ^
/home/wwatson/Arduino/libraries/MTP_t4/src/MTP.h:79:23: error: 'MTP_TX_SIZE_480' was not declared in this scope
   #define MTP_TX_SIZE MTP_TX_SIZE_480 
                       ^
/home/wwatson/Arduino/libraries/MTP_t4/src/MTP.h:82:26: note: in expansion of macro 'MTP_TX_SIZE'
   uint8_t tx_data_buffer[MTP_TX_SIZE] __attribute__ ((aligned(32)));
                          ^
In file included from /home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:19:0:
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/LittleFS/src/LittleFS.h: In member function 'virtual void LittleFSFile::whoami()':
/home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/LittleFS/src/LittleFS.h:59:3: error: 'Serial' was not declared in this scope
   Serial.printf("  LittleFSFile this=%x, refcount=%u\n",
   ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino: In function 'void storage_configure()':
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:108:13: error: 'Serial' was not declared in this scope
           { Serial.printf("SDIO Storage %d %d %s failed or missing",ii,cs[ii],sd_str[ii]);  Serial.println();
             ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:115:13: error: 'Serial' was not declared in this scope
             Serial.printf("SDIO Storage %d %d %s ",ii,cs[ii],sd_str[ii]); 
             ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:124:11: error: 'Serial' was not declared in this scope
         { Serial.printf("SD Storage %d %d %s failed or missing",ii,cs[ii],sd_str[ii]);  Serial.println();
           ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:131:11: error: 'Serial' was not declared in this scope
           Serial.printf("SD Storage %d %d %s ",ii,cs[ii],sd_str[ii]); 
           ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:142:9: error: 'Serial' was not declared in this scope
       { Serial.printf("Ram Storage %d %s failed or missing",ii,lfs_ram_str[ii]); Serial.println();
         ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:149:9: error: 'Serial' was not declared in this scope
         Serial.printf("RAM Storage %d %s ",ii,lfs_ram_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
         ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:158:9: error: 'Serial' was not declared in this scope
       { Serial.printf("Program Storage %d %s failed or missing",ii,lfs_progm_str[ii]); Serial.println();
         ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:165:9: error: 'Serial' was not declared in this scope
         Serial.printf("Program Storage %d %s ",ii,lfs_progm_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
         ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:174:9: error: 'Serial' was not declared in this scope
       { Serial.printf("QSPI Storage %d %s failed or missing",ii,lfs_qspi_str[ii]); Serial.println();
         ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:181:9: error: 'Serial' was not declared in this scope
         Serial.printf("QSPI Storage %d %s ",ii,lfs_qspi_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
         ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:190:9: error: 'Serial' was not declared in this scope
       { Serial.printf("SPIFlash Storage %d %d %s failed or missing",ii,lfs_cs[ii],lfs_spi_str[ii]); Serial.println();
         ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:197:9: error: 'Serial' was not declared in this scope
         Serial.printf("SPIFlash Storage %d %d %s ",ii,lfs_cs[ii],lfs_spi_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
         ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino: In function 'void setup()':
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:215:12: error: 'Serial' was not declared in this scope
     while(!Serial); // comment if you do not want to wait for terminal
            ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:219:3: error: 'Serial' was not declared in this scope
   Serial.println("MTP_test");
   ^
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino: In function 'void loop()':
/home/wwatson/Arduino/libraries/MTP_t4/examples/mtp-test/mtp-test.ino:286:6: error: 'Serial' was not declared in this scope
   if(Serial.available())
      ^
Multiple libraries were found for "SD.h"
 Used: /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SD
 Not used: /home/wwatson/arduino-1.8.13/libraries/SD
Using library SD at version 2.0.0 in folder: /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SD 
Using library SdFat at version 2.0.4 in folder: /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SdFat 
Using library SPI at version 1.0 in folder: /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/SPI 
Using library MTP_t4 at version 1.0.0-beta.1 in folder: /home/wwatson/Arduino/libraries/MTP_t4 
Using library LittleFS at version 1.0.0 in folder: /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/LittleFS 
Using library Time at version 1.6 in folder: /home/wwatson/arduino-1.8.13/hardware/teensy/avr/libraries/Time 
Error compiling for board Teensy 4.1.
.

Not sure what this is all about but it's probably something have missed again.

In any case I cannot get Teensy-MTP to show up in the Disk Mounter. In earlier versions of MTP Responder it did.

I have a legit version of Windows 7 that I am going to install in VirtualBox and see what happens there.
 
I believe those errors are caused by not updating the T3.x or T4.x code as shown in readme:
## Installation:
Code:
 - If you wanted to use USB_MTP_SERIAL  
   - T4.x edit teensy/avr/cores/teensy4/usb_desc.h with content of 'modifications_for_cores_teensy4' (insert after MTP_DISK)
   - T3.x edit teensy/avr/cores/teensy3/usb_desc.h with content of 'modifications_for_cores_teensy3' (insert after MTP_DISK)
 
I believe those errors are caused by not updating the T3.x or T4.x code as shown in readme:
## Installation:
Code:
 - If you wanted to use USB_MTP_SERIAL  
   - T4.x edit teensy/avr/cores/teensy4/usb_desc.h with content of 'modifications_for_cores_teensy4' (insert after MTP_DISK)
   - T3.x edit teensy/avr/cores/teensy3/usb_desc.h with content of 'modifications_for_cores_teensy3' (insert after MTP_DISK)

You were right:) I know I copied and pasted to both usb_desc.h files but obviously did not save the changes. That's what I get for staying up late and trying to do stuff. It now compiles and uploads but still will not show up as an MTP drive in Linux.

Setting up Widows in VirtualBox now. Will try that and see what happens:)

Thanks for the help @KurtE and @WMXZ.
 
There was some discussion of strlcpy(). IMO, don't just use it, use it and check the return value. Ie:

Code:
if (strlcpy(dest, src, sizeof(dest)) > sizeof(dest))  
   handle_error();
 
@WMXZ and others wanting to play - I started playing some more yesterday and I am in the process of starting again from your current (master) code and adding in some of the changes I have done.

I put in a PR to core: https://github.com/PaulStoffregen/cores/pull/532 which updates the USB descriptor for both T3.x and T4 for the larger end point max transfer size of 16 to 32. Likewise told the system that we will be doing writes to this endpoint not reads.

I also did a PR back to you with just my T3.x changes to Event TX, that allocates a TX transfer when it needs it, it currently limits it to 4 currently outstanding transfers. The code is setup to work like several other USB writes, that it expects that once the underlying USB system has completed the write operation, it will free that transfer object back to the free pool, so you only use it once.

Tested very slightly modified version of your current mtp-test, that if you do an 'a' command and you don't have RAM drives enabled, but you do have an SDIO drive it will do the operations to that instead. Did that as not really enough room on T3.6 for some of these drives. I did try it on T3.6 and was able to run this, then use your 'r' command the new files show up. I did it a couple of times and each time they showed up.

I did a PR back to you with these changes: https://github.com/WMXZ-EU/MTP_t4
If anyone else is interested these are in my mtp_events_merge branch.

---

Next up - Maybe a few gratuitous extensions to storage interface? And maybe a question or two:
Currently the MTPStorage_SD class has 3 public members:
Code:
// Storage implementation for SD. SD needs to be already initialized.
class MTPStorage_SD : public MTPStorageInterface, mSD_Base
{ 
public:
  void addFilesystem(FS &fs, const char *name) { sd_addFilesystem(fs, name);}
  void dumpIndexList(void);
  uint32_t getStoreID(const char *name) {return sd_getStoreID(name);}
Wondering about and or thinking of changing:
a) addFileSystem currently return void. Why not return the the storage Index (or ID?)
b) dumpIndexList - my current version in other branch prints additional things like the file name, which I found useful to me.
c) getStoreID - unclear are you returning the actual Storage ID or are you returning the index into storage array? The code looks like it is the array index. So slightly confusing between store id and storage id? But as long as it is understood...

Was thinking of adding a couple of new simple methods, like:
Code:
    uint32_t getFSCount(void);
    const char *getStoreName(uint32_t store);  // again looks like store is just an index...
    FS* getStoreFS(uint32_t store);

Then maybe also add some of my notify on file level to your code and test case, maybe like:
Code:
      if(ch=='a') 
      {
        Serial.println("Add Files");
        static int count=100;
        for(int ii=0; ii<10;ii++)
        { char filename[80];
          sprintf(filename,"/test_%d.txt",count++);
          Serial.println(filename);
          File file=sdx[0].open(filename,FILE_WRITE_BEGIN);
            file.println("This is a test line");
          file.close();
          [COLOR="#FF0000"]mtpd.send_AddObjectEvent(store, filename);[/COLOR]
        }
        // attempt to notify PC on added files (does not work yet)
        uint32_t store = storage.getStoreID("sdio");
        Serial.print("Store "); Serial.println(store);
        mtpd.send_StorageInfoChangedEvent(store);
      }
And the internal code to this would need to ask the underlying store to map the file name to the object ID and if necessary create that ID, and then send the event.
However note: This code bails before sending any event or actually creating the node in your list, if while walking the pathname, it finds that the parents are not in your active list. That is if for example the host has not asked you to enumerate a storage, and object is on that storage, like wise if file is in sub directory and that sub directory has not been enumerated, again no need to add object to list nor send event...

Then after this, maybe will have some fun and create a different test sketch, which maybe tries out other things people might want to do:

Example: maybe start of with a display, like either ILI9341 or ILI9488. Then have it start off doing a slide show off of a storage. So may want stuff like:
a) Know if the user has added a new bitmap or the like to some folder on the storage and maybe add or remove those from the play list. Maybe when it sees a new file, it may need/want to run code to normalize if necessary...

b) Maybe have a configuration file, that maybe has information in it like, how long to show each image... So how to find out if/when this file changes? Especially since right now we don't have anything like modification date implemented? So maybe add some form of FS change notification? If we get an MTP message about a change to a file, maybe there should be way for sketch to say let me know when files change...

And go from there... :D
 
Morning @KurtE
See you have been busy again :)

Anyway so if I am reading your post right I should go ahead update the core with your changes: https://github.com/PaulStoffregen/cores/pull/532 and then use your updated MTP_T4 branch: https://github.com/KurtE/MTP_t4/tree/mtp_events_merge which is basically the PR to MTP.

Then I can start playing and maybe test with the larger NAND chips to see if I get any errors.

EDIT: I did update your test sketch though:
Code:
#include "Arduino.h"

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

#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 1
#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"
  #define USE_RAM 0
  #define USE_SPI 1
  #define USE_QSPI 0
  #define USE_HS_QSPI 0
  #define USE_NAND 1
  #define USE_QSPI_NAND 0
  #define USE_FRAM 0
#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_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_SPI == 1
    const char *spi_str[]={"WINBOND"};     // edit to reflect your configuration
    const int spi_cs[] = {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_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_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_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_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
 
#endif


MTPStorage_SD storage;
MTPD    mtpd(&storage);

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_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_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]);
          
        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_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]);
          
        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_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]);
          
        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_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]);
     
          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_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]);
     
          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
}
/****  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)
  #endif
  Serial.println("MTP_test");

  #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_LFS_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

  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 USE_LFS_RAM==1
      if(ch=='a') 
      {
        Serial.println("Add Files");
        static int count=100;
        for(int ii=0; ii<10;ii++)
        { char filename[80];
          sprintf(filename,"/test_%d.txt",count++);
          Serial.println(filename);
          File file=ramfs[0].open(filename,FILE_WRITE_BEGIN);
            file.println("This is a test line");
          file.close();
        }
        // attempt to notify PC on added files (does not work yet)
        uint32_t store = storage.getStoreID("RAM1");
        Serial.print("Store "); Serial.println(store);
        mtpd.send_StorageInfoChangedEvent(store);
      }
    #elif USE_SD==1
      if(ch=='a') 
      {
        Serial.println("Add Files");
        static int count=100;
        for(int ii=0; ii<10;ii++)
        { char filename[80];
          sprintf(filename,"/test_%d.txt",count++);
          Serial.println(filename);
          File file=sdx[0].open(filename,FILE_WRITE_BEGIN);
            file.println("This is a test line");
          file.close();
        }
        // attempt to notify PC on added files (does not work yet)
        uint32_t store = storage.getStoreID("sdio");
        Serial.print("Store "); Serial.println(store);
        mtpd.send_StorageInfoChangedEvent(store);
      }
    #endif
  }
#endif
}
 
Last edited:
Morning!

Yes that is the current stuff I am working off of. My LittleFS is still off of LFSinterity/PlusNAND
 
@KurtE
Ok I did what I described in post #591. It recognized the N01 and N02 chips on the memory breakout board was able to create a directory and copy files up to 1.1Mb and the was able open/delete them. However if I tried to copy a 5Mb pdf however to either chip MTP would restart and the files didn't show as copied.

EDIT: Happens when using QSPI or SPI but same thing happens if I try to use the 512Mb flash as well.

EDIT2: also happens on a 16Mb winbond flash.
 
Last edited:
Morning!

Yes that is the current stuff I am working off of. My LittleFS is still off of LFSinterity/PlusNAND

Yep that's the latest. I did the push yesterday for the BBLUT stuff so not sure if you have those changes in your version.
 
Yes - So far I have not had any luck with larger files on slower devices. It feels like if a transfer takes over a certain amount of time that the MTP connection will get killed...
I have the stuff in my other branch that tries to keep reading data from the USB host in the transfer at a rate while it is busy writing data out... I think it helps some, but still there were some timeouts.

I wonder(ed) if maybe the host has some way to tell us stuff and/or if there is a way for us to tell host that we are still working on it.

I Don't think the host can tell us on the main TX (Our RX endpoint) as that end point is being used in the transfer of the file. I don't think the host can tell us anything over an event endpoint as we don't have an event endpoint that can receive data... Not sure if we can have one or not. I tried setting one up earlier, but did not receive anything. But then again maybe it then asked me for information like which events I might process and did not respond appropriately to.

Will get back to looking at that soon, after get a few of these other pieces on place.

Note: in current builds I am getting a warning in LittleFS_NAND.cpp (671) about cmd being set but not used...
 
@KurtE
Thanks Kurt for the info Kurt. Think the stuff for keep reading the data actually helped. If I remember right when I was using it I was able to transfer the 5Mb file. Maybe its worth putting back in at some point.

Next time I am on the computer will give the updates a try - in the living room right now do some reorganization.

As for the cmd error probably should comment that piece for now. I turned off the issuing of the BBM command until I test it and those cmd's are part of the addBBLUT function.
 
@wmxz and @mjs513 and ...

I pushed up the next set of changes to the branch with the Pull Request.

I am properly generating the object added events for the new files created in your 'a' command.

So if you hit F5 on PC, the new files show up.

Also found what appears to be the issue with the code that was sending the storage Info changed message not appearing to do anything.

This appears to be the case that in your code, when the system asks for which events we do, the one for the MTP_EVENT_STORAGE_INFO_CHANGED
was not uncommented.

After I removed the // and reduced the size of the Ram disk, after I create the new files, and went back to the top level Teensy window the free space changed.
 
Good Morning @KurtE
I finally got to download your latest updates and they seem to be working.

If I hit F5 on the PC they do show up.

The other commands seem to working as well I tried the 'd' command and that printed correctly. I did notice a problem with the 'a' command though. You use it twice - once for ram and once for SD card. Maybe you should update it so you use 'a' and 'A' :)

Using LFSIntegrity I created a large File (62.5Mb) and it did transfer from the NAND 1G to the PC with no problem but here is the interesting part. Transferring to the NAND might file type dependent. I was able to transfer a 9MB mp4 file (yes it played from the NAND), a 6MB Zip file, 3MB STL file, a different 5MB PDF and a 2.5MB CSV file without a problem. So maybe its just an issue with the specific file you are transferring.
 
Good Morning,

Not sure about why different files work differently. I suspect it is more on what the writing to the chips are doing. If with yours and Defragsters changes it finds enough already formatted blocks to use, such that it writes fast enough than it succeeds. If it runs into places where it needs to erase blocks and the erase is slow...

Since this is @WMXZ's project, I am trying to figure out how much more that I should do in this pass? My plans is probably to add another command, like 'x' the files that I added, and have versions of command that notifies the host about the files removed and see if that works.

I think that would be a good stopping point for this set of changes.
'a' versus 'A' I thought I had one or the other add compiled in. If RAM is configured it tries to do RAM, if not if SDIO is configured it tries to do SDIO... I mainly added the second part as wanted to test on T3.6 and not sure we could create a RAM drive that would work ok in that small of memory... Again if I were extending it much more I would probably bring in more from my version in the other branch. Or maybe as a minimum, maybe check for a second character after the 'a' to see if you typed a0 it would go to your zero indexed storage, a1...

After I play a little more with the events and no other major distraction gets my interest, I may go back to try to integrate in a version of the transfer code from the other branch that tries to keep reading from the host while the other stuff is still busy... But there are a few different approaches to help make this work, not sure which way to go, like:

a) Have a larger "Big" buffer allocated as part of the main class that is used to read ahead and try to dribble just enough to keep the host happy.
b) Maybe try to dynamically allocate buffers (malloc? extmem_malloc?) that if necessary we keep allocating as much memory as we can to keep reading from the host until we have all of the data and then we continue to flush the data from this memory to flash however long it takes. Again not sure what this would entail? Does the code sit and wait until the last bits of the file are transferred before returning the status to the host? Will that cause it to still timeout? If we try to tell it is done and continue to finish writing the file, what happens if the host tries to start up a write of another file? Or if the host shows the file there, will a user think it is done and unplug their teensy which may still be busy writing out the data?

Again as I mentioned yesterday that when I try working on some of this, maybe good to try a complete different example sketch which uses a display...

But first Coffee
 
Back
Top