Teensyduino File System Integration, including MTP and MSC

@KurtE @mjs513 - Decided to format my Kingston 120Gig SSD to ext4 and pile a couple of directories on it. I formatted the drive using sudo gparted with Ubuntu 20.04.

Result:
Screenshot at 2022-09-05 18-36-55.png

Seems to be something with RPI4 ext4 formatting. Really not sure:( Don't own a RPI4 just a RPI3. Hmmmm...I wonder?
 
@KurtE @mjs513 - Was able to duplicate the problem with MTP and the PI writable directory. It shows empty:
Screenshot at 2022-09-08 15-26-30.png

I'll see if I can figure out what it is...

Edit: Just put it in my Linux machine and checked the properties of the writable directory:

Screenshot at 2022-09-08 15-34-56.png

You will see that some directories are unreadable. That could be why nothing is showing up...

Edit #2: There appears to be Something different with some of the directories that is not supported by lwext4. Even Linux takes note of the difference:
Screenshot at 2022-09-08 16-15-59.png

Looks like you need special software to deal with it so in normal use this should not be a problem:)
 
Last edited:
@KurtE @mjs513 - Was able to duplicate the problem with MTP and the PI writable directory. It shows empty:
View attachment 29329

I'll see if I can figure out what it is...

Edit: Just put it in my Linux machine and checked the properties of the writable directory:

View attachment 29330

You will see that some directories are unreadable. That could be why nothing is showing up...

Thanks for checking but the interesting thing is that it is showing 225K items on disk at 5.9gb. In our case its shows almost nothing used and only 2 folders and the whole disk is free.??? even your MTP shows no folders and no files - its empty
 
Thanks for checking but the interesting thing is that it is showing 225K items on disk at 5.9gb. In our case its shows almost nothing used and only 2 folders and the whole disk is free.??? even your MTP shows no folders and no files - its empty

Sorry, I just did a second edit on the post with more info:)
 
Quick update:

Paul, merged in a couple of our USBHost_t36 PRs, including the USB Format cleanup code as well as the capability to have the MTP code monitor the state of USBHost Drives/volumes.
Those changes were put into the 1.58B2 build that came out for Windows and Ubuntu 64 bit. (I don't think he packaged up a Mac version yet

With that I then merged in my WIP code in MTP_Teensy into the main branch. So everything should be either that branch and the stuff put into B2.

Note: Some of the mechanisms that are put into this beta, to monitor the state of SD cards and USB Host drives will very likely be modified during the next few betas as
we extend out the capabilities of the FS.h and the like.

But hopefully we can keep the simple MTP type tasks simple...

Like the SimpleSD version, is now just:
Code:
#include <SD.h>
#include <MTP_Teensy.h>

#define CS_SD BUILTIN_SDCARD  // Works on T_3.6 and T_4.1
//#define CS_SD 10  // Works on SPI with this CS pin
void setup()
{
  // mandatory to begin the MTP session.
  MTP.begin();

  // Add SD Card
  SD.begin(CS_SD);
  MTP.addFilesystem(SD, "SD Card");
}

void loop() {
  MTP.loop();  //This is mandatory to be placed in the loop code.
}
And this monitors form disk insertion and removals.
 
@KurtE - Just setup TD1.58B2. I have a library called TeensyMiniOS that I have been playing with for testing. When I added TeensyEXT4V3 to it with TD1.57 I ran out of memory for local variables to the tune of 15k bytes. Recompiling it with TD1.58B2 it was +23K so it is more memory efficient:) But the mouse no longer works at all:( Will have to test and figure that out. I think I will also test the RA8876Teensy library. First though will play with MTP.

Edit - This is with a Logitech wireless mouse and keyboard. Moving the mouse sketch shows keypresses and left button shows keypress and release 1, right button 2.
 
@KurtE - Just setup TD1.58B2. I have a library called TeensyMiniOS that I have been playing with for testing. When I added TeensyEXT4V3 to it with TD1.57 I ran out of memory for local variables to the tune of 15k bytes. Recompiling it with TD1.58B2 it was +23K so it is more memory efficient:) But the mouse no longer works at all:( Will have to test and figure that out. I think I will also test the RA8876Teensy library. First though will play with MTP.

Edit - This is with a Logitech wireless mouse and keyboard. Moving the mouse sketch shows keypresses and left button shows keypress and release 1, right button 2.
Which mouse/keyboard? Normal or pro g?

We did some hid changes to support some advanced keyboards…

Try adding an extra hidparser object and see if it helps

EDIT: I think there is an issue with this combo unit with the changes made. Need to debug. I have my old wave type to try....

I think the keyboard object is claiming the mouse's report.

Will debug
 
Last edited:
It reproduced on my K350...

If you get a chance you might try:
Code:
hidclaim_t KeyboardController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
{
	// Lets try to claim a few specific Keyboard related collection/reports
	USBHDBGSerial.printf("KeyboardController::claim_collection(%p) Driver:%p(%u %u) Dev:%p Top:%x\n", this, driver, 
		driver->interfaceSubClass(), driver->interfaceProtocol(), dev, topusage);

	// only claim from one physical device
	// Lets only claim if this is the same device as claimed Keyboard... 
	//USBHDBGSerial.printf("\tdev=%p mydevice=%p\n", dev, mydevice);

	if (mydevice != NULL && dev != mydevice) return CLAIM_NO;

	// We will not claim boot mouse
[COLOR="#FF0000"]	if ((driver->interfaceSubClass() == 1) && (driver->interfaceProtocol() == 2)) return CLAIM_NO;
[/COLOR]
	// We will claim if BOOT Keyboard.

	if (((driver->interfaceSubClass() == 1) && (driver->interfaceProtocol() == 1)) 
		|| (topusage == TOPUSAGE_KEYBOARD))
Try adding that RED line. May do it cleaner but the idea is that make sure we don't claim any HID reports when driver InterfaceProtocol is Mouse
 
It reproduced on my K350...

If you get a chance you might try:
Code:
hidclaim_t KeyboardController::claim_collection(USBHIDParser *driver, Device_t *dev, uint32_t topusage)
{
	// Lets try to claim a few specific Keyboard related collection/reports
	USBHDBGSerial.printf("KeyboardController::claim_collection(%p) Driver:%p(%u %u) Dev:%p Top:%x\n", this, driver, 
		driver->interfaceSubClass(), driver->interfaceProtocol(), dev, topusage);

	// only claim from one physical device
	// Lets only claim if this is the same device as claimed Keyboard... 
	//USBHDBGSerial.printf("\tdev=%p mydevice=%p\n", dev, mydevice);

	if (mydevice != NULL && dev != mydevice) return CLAIM_NO;

	// We will not claim boot mouse
[COLOR="#FF0000"]	if ((driver->interfaceSubClass() == 1) && (driver->interfaceProtocol() == 2)) return CLAIM_NO;
[/COLOR]
	// We will claim if BOOT Keyboard.

	if (((driver->interfaceSubClass() == 1) && (driver->interfaceProtocol() == 1)) 
		|| (topusage == TOPUSAGE_KEYBOARD))
Try adding that RED line. May do it cleaner but the idea is that make sure we don't claim any HID reports when driver InterfaceProtocol is Mouse

That fixed the mouse issue. Thanks:)
Also, Tested the latest version of MTP from your repo and TD1.58B2.

With a few adjustments to TeensyEXT4V3:
Screenshot at 2022-09-11 15-44-17.png

And:
Screenshot at 2022-09-11 15-42-40.png

Seems to work without issue:)
 
@KurtE , first of all, thank you very much for developing this library, it's super useful! :D

I have been using the latest version from the repo and TD1.57. I would like to be able to only activate the MTP functionality when the user sends a specific "Switch MTP ON command", which would begin the MTP service and add a file system. However, it seems like if I don't place the MTP.begin() in the start of setup() code and add a filesystem right away, Teensy takes a long time to initialize the USB serial ports. Arduino serial monitor auto-connect times out. If I use other terminal application where the COM port connection is manual, I need to wait around 5 seconds after power on to be able to connect to the Teensy.

When I am using standard serial com, with USB Type set as Serial, the Serial begins immediately after power on. It takes much longer when I am using MTP (USB Type = Serial + MTPDisk). Here is a sample code which reproduces my issue. With this code, Arduino Serial monitor always gives the "Unable to open COM3" error message (if I just powered on the Teensy).
Code:
#include <MTP_Teensy.h>
#include <SD.h>
#define CS_SD BUILTIN_SDCARD  // Works on T_3.6 and T_4.1

void setup()
{
  uint32_t t1 = millis(); // Setup start time
  Serial.begin(9600);
  uint32_t t2 = millis(); // Serial ready time
  MTP.begin(); // mandatory to begin the MTP session.
  uint32_t t3 = millis(); // MTP ready time
  delay(5000); // just wait so we can see the print after we start the terminal
  Serial.printf("Start = %u ms ; Serial ready = %u ms ; MTP ready = %u ms \n", t1, t2, t3);
  // Add SD Card
  SD.begin(CS_SD);
}

void loop() {
  MTP.loop();  //This is mandatory to be placed in the loop code.
  if(Serial.available() && Serial.read() == 'S')
  {
    MTP.addFilesystem(SD, "SD Card");
    Serial.println("Adding Filesystem!");
    while(Serial.available()) Serial.read(); // empty input buffer
  }
}

Is this a known issue? Should I change something in my code to make it work? Thank you very much!
 
...
I have been using the latest version from the repo and TD1.57. I would like to be able to only activate the MTP functionality when the user sends a specific "Switch MTP ON command", which would begin the MTP service and add a file system. However, it seems like if I don't place the MTP.begin() in the start of setup() code and add a filesystem right away, Teensy takes a long time ...
Is this a known issue? Should I change something in my code to make it work? Thank you very much!

AFAIK, this is a consequence of the USB descriptor presented on plug in. The computer needs to resolve the requested services, the MTP.begin() is part of completing that during setup().

Perhaps there is a way to have the MTP code to selectively NAK the process and start without it? Then doing a restart of USB could have it when desired.

One other way put forth some time back was to have two chains of descriptors for use by usb_init code determined by a value stored in EEPROM. Checking that value in advance could alter the list presented to the computer. To change the list the indicating value in EEPROM would be changed and the Teensy restarted.

It was a concept that worked when tried years back ... wow 4 years ago - BING search of PJRC found it on first try::

https://forum.pjrc.com/threads/53608-Configure-USB-after-sketch-has-already-loaded

Concept presented and used to work - but full details not presented.
 
Wow, I didn't know that it was possible. Thanks for showing me that thread! For Teensy 4, would the procedure be similar?

And also, in that example, the EEPROM was checked right after the startup, so the desired behavior was to just delay the USB initialization to be able to choose which descriptor to use based on a value stored in the EEPROM. My needs are a little different. I would like to be able to start the Teensy as if our USB Type was just "Serial" (the default option). A later, if a user send a command telling "hey, turn MTP disk on", than I would run the USB initialization again, but changing it to USB Type = Serial + MTPDisk. Do you think something like this would be possible? I do not have any experience with the USB files from the Teensy 4 cores. Thank you!
 
Most anything is "Possible", but not sure, how difficult it might be to accomplish. And I doubt that is anything that is likely to be put into the main core stuff.

It would be reasonably easy for you to have MTP at startup, but have no storages installed and add the storage later,

Sorry, I don't know any easy way to do it. Maybe there is something in the MTP spec, that we missed.
 
@KurtE and @defragster thanks for all the info! I have tried many things and I think I managed to "solve" my issue regarding slow USB Serial initialization times. I just need to remove the Serial.begin() function. Than magically everything starts up fast again, both MTP and SERIAL.

The other challenge was to only show my files from SD card when the user sends a specific command. In order to accomplish that, now I only call MTP.begin() at setup, without adding a filesystem. So when the Teensy boots, a device with name "Teensy" immediately pops up on my File Explorer, however with no contents inside. Ideally I would like that this device wouldn't show up at all, but the current behavior is ok for my needs. Then, when the user sends an specific command, I use the MTP.addFilesystem command and the files from SD card appear. I also do have an command to "remove" the SD card folder, which is to call MTP.send_StoreRemovedEvent and stop calling MTP.loop in the loop. I don't know if that is the right thing to do, but so far it is working reasonably.

Explaining just in case someone comes across this question in the future. Once again, thanks for all amazing the support!
 
Teensy 4.1 using MTP needs program button to reprogram

Hi,

Ive just discovered that the MTP_teensy library now is really working nice (at least on a T4.1). I am planning to integrate this in the Teensy Batdetector project (see https://github.com/CorBer/teensy_batdetector). The code was extremely easy to use and worked right from the start, my hats of to those of you that have created this addition. This will make it possible to have devices where the SD card is hidden nicely inside away from external factors !

But ... when I want to reprogram the T41 I cannot do this without pressing the program-button, which isnt handy for a device that normally should be closed. My tests were made using PlatformIO on a Linux Mint 20.3 system with the stable 1.157 teensyduino environment. When I disable (remove or comment out) all the links to the MTP_Teensy library (incl library) this has no effect as the device still does not want to reboot into programming mode. Only when I also remove the USB_MTPDISK define from compiler defines I can (after pressing the program button) set the system back to a non-MTP setup. From then on I can program the T41 without any need to press the program button. So this seems to be related to some settings at startup that are allready activated before the MTP.begin() command.

The bootloader responds " error sending reboot command to /dev/hidraw5 "
- framework-arduinoteensy @ 1.157.220801 (1.57)
- tool-teensy @ 1.154.210805 (1.54)
- toolchain-gccarmnoneeabi @ 1.50401.190816 (5.4.1)

Does anybody have an idea how to solve this ?

regards
Cor
 
Hi, All you MTP experts:
I have created a project that saves about 600K of Sensor data into a RAMdisk file on the Teensy4.1.
Every day at Midnight it moves the file to the SD Card, renames the RAMdisk file with the new days date, and purges the previously written data, writes the header file (Is is .CSV file), and begins the data collection for the next day.

The files in the SD Card subdirectory are not showing up on my MacOS (Monterey 12.6.3). The Disk volume shows up just fine, the two volumes inside the Disk volumes show up fine, and the subdirectory on the SD Card show up just fine. These are created upon startup of the Teensy program in the Startup code.

Is there some magic incantation I need to perform using the MTP commands when ever there is a change in the files on any of these two sub volumes? (One is named TeensyRAMDisk and the other is named TeensySDCard)
Here is a picture of the Window opened when I open the Teensy Disk mounted on my Desktop:


Opened MTP Window on Mac.jpg



Regards,
Ed
 
@sbfreddie,
there are two methods to refresh MTP on host (Mac in your case)
1) unmount/mount disk (do not know how that is done on Mac)
2) let Teensy send an resetEvent or addObjectEvent.

Reason is, that for MTP, only the Host interrogates the slave (Teensy). The only chance for Teensy to say something without being asked, is to send an event, but host must be listening for this event and is not required to react.

AFAIK, MTP is a Microsoft 'invention' so Macs implementation may have different features.
I use always a reset event, which works always on my Windows PC
 
WMXZ:
So are you saying that after I write a new file on the SD Card, or change the file name on the RAMDisk, I should use a MTP.addobjectEvent(); command to the MTP library?
If that is correct I will try it and see what happens.

Thanks,
Ed
 
WMXZ:
I forgot to mention that the app I am using on the Mac is called: MacDroid.

I also was using another app called MTP for Mac but, it is in beta test and stops working after 10 days without informing you, so if you plug a MTP device into the Mac it crashes the Mac, Very bad.

Regards,
Ed
 
Note: I am not much of a MAC person, but have older MAC laptop that I use to debug stuff on from time to time.

On it I was using some version of MTP like you mentioned, that had a 10 day trial period...

But then switched to the: Android File Transfer app.
I believe it was PaulStoffregen who mentioned that utility earlier.

And as @WMXZ mentioned, yes currently you need to tell MTP that you added/removed... stuff and/or do a resetEvent, which tells the causes the host to re-query the data when it wants to display a directory. Note: at least in some cases, the host may or may not actually refresh it's contents on the screen if it is displaying an MTP directory and it receives a reset. You may have to do a refresh of that folder to see the updated contents.
 
Kurt:
Here is the way my Teensy4.1 software works:
It logs environmental data from a BME680 at 10 second intervals for 24 hrs to a RAMDisk with the the current date in it's name.
At midnight it closes the RAMDisk file, copies the entire file to the SD Card directory called EnvironmentData, renames the RAMDisk file with the new date, clears the old data in the file, opens and begins logging data again.

I have used the command MTP.reset() after the entire process that occurs at midnight but the new RAMDisk filename, and the added file, in the EnvironmentData folder on the SD Card do not show up even if I unmount and remount the Teensy4.1 MTP disk called "Teensy" on the Macs desktop.

However if I reboot the Teensy4.1, which occurs frequently because I am constantly changing the code for other things (The program is presently at 4826 lines) in the codebase they show up just fine on the Mac's Desktop.

Do you have or can you point me to some examples of the MTP commands to add, remove, or rename files or folders under the MTP umbrella.

Thanks,
Ed

P.S. The Android file transfer app is junk, its is very buggy, crashes often, and has not been updated in a long while.
 
Last edited:
Again I don't use the MAC, except at times for MAC specific issues. I mostly use Windows (main machine has W11), secondary machine Ubuntu 22.04 (or W10)...
Note: At times I think of Ubuntu in the same way that Paul thinks of Windows ;)

Also note: I do very little logging type stuff..

So if you have suggestions on what Free utility or the like to use on the MAC, that would be great.

Showing updated files. If you look at several of the MTP sketches that have some basic Loging built in. like USB_MTP-logger.ino
(I mention this one as I updated it to use newer stuff today).

But for example when the command is executed to stop logging, it runs the code:
Code:
void stopLogging() {
  Serial.println("\nStopped Logging Data!!!");
  write_data = false;
  // Closes the data file.
  dataFile.close();
  Serial.printf("Records written = %d\n", record_count);
  MTP.send_DeviceResetEvent();
}
Which has the call to reset the device. In the sample run, that I just did it, we see:
Screenshot.jpg

Notice that the log file has not shown up. But then after I hit F5 it then shows up:
Screenshot1.png
 
Kurt:
What does an F5 do on Windows? I have not used Windows for a long time.

So, you are saying that I should use the "MTP.send_DeviceResetEvent()" after I close the file and then when I open it again and change the name send another "MTP.send_DeviceResetEvent()".

I would have to use the DeviceResetEvent 3 times, once when I close the logging file, once when I open it and rename it, and then again when I copy it to the SD Card?

What about these other MTP commands:
MTP.send_addObjectEvent(),
MTP.removeObjectEvent().

What are they used for?

If sure would like if somebody wrote a MTP for beginners WIKI or something like that to explain how to use these powerful commands for beginners.
MTP is probably one of the most powerful and useful libraries for the Teensy created for anyone who needs to move data and files back and forth to PC's.

Thanks,
Ed
 
Back
Top