LocalFileHandle problem

25 Nov 2013

Greetings,

I have managed to get my LPC11U24 to play midi files.

One of the big problems I had along the way was that reading the LocalFileSystem, where I have put some .MID files, was very slow using fread(). My player kept stalling as the files could not be read quickly enough.

I was pointed to an example of how to use the LocalFileHandle class to speed it up. What had seemed to be an impossible task became possible.

What I am trying to do is repeatedly play all .MID files that have been copied to the LocalFileSystem. The documentation for LocalFileHandle is a bit sparse, to say the least. There does not appear to be a way to find files in the directory using LocalFileHandle itself (or is there?), so I kept the LocalFileSystem declaration and readdir() that I had been using, and then used the LocalFileHandle once I have a file name.

This seems to work just fine, But, (there is always a but) I have a problem. I found that after processing the second file (or if there was only one .MID file in the directory, after processing that file for the second time), my program comes to a grinding halt. I found that the close() call was not returning to me. I noticed at the point that the close() was done a second time, the LocalFileSystem files appeared again on the USB-attached PC, after being inaccessible while my program was running up to that point.

In desperation mode I tried commenting out the close(), and I actually got a bit further. I could then process many more files before I eventually got an open failure. I am not 100% sure my way of testing that the open was successful is correct, but I think it is telling the truth, and that this failure may be due to running out of memory, but that is just a wild guess on my part.

Below is a very much cut down version of what I am doing but which behaves the same way. It gets the same problem if it selects other file types that are on the the LocalFileSystem such as .BIN.

Anybody got any ideas?

#include "mbed.h"

DigitalOut l1(LED1);   

LocalFileSystem local("local");               // Create the local filesystem under the name "local"
 
int main()
{

uint8_t FileBuffer[64]; 
int filecount=0;

while ( 1 )
  {   
     printf("Main loop. opening dirctory\r\n");   
  
     DIR *d = opendir("/local");               

     struct dirent *p;
     while((p = readdir(d)) != NULL)
       {         
         if ( strstr(p->d_name,".MID") ) 
           {
              printf("Opening %s\r\n",p->d_name);        

              FILEHANDLE fh = local_file_open(p->d_name, O_RDONLY);
              LocalFileHandle lfh(fh);
    
              if ( fh  == NULL ) 
                 {
                   fprintf(stderr,"local_file_open failed\n");
                   exit(1);
                }

              printf("local file open  - %d\r\n",++filecount);

              lfh.read(FileBuffer,64);

              printf("Closing LocalFileHandle\r\n");   
              l1=1;
              lfh.close();
              l1=0;
              printf("Closed\r\n");   
    
           }   // twas a .MID file
 
       }   // all in directory
 
     printf("Closing directory\r\n");   
     closedir(d);
     printf("Directory closed\r\n");   
     
  }  // forever

} // main      
25 Nov 2013

I think this happens because the LocalFileHandle expects to be dynamically allocated through the normal fopen() code path. It therefore does a delete this; in its close method which could easily lead to a crash or otherwise unexpected results. You could try modifying the code to look more like this:

#include "mbed.h"
 
DigitalOut l1(LED1);   
 
LocalFileSystem local("local");               // Create the local filesystem under the name "local"
 
int main()
{
 
uint8_t FileBuffer[64]; 
int filecount=0;
 
while ( 1 )
  {   
     printf("Main loop. opening dirctory\r\n");   
  
     DIR *d = opendir("/local");               
 
     struct dirent *p;
     while((p = readdir(d)) != NULL)
       {         
         if ( strstr(p->d_name,".MID") ) 
           {
              printf("Opening %s\r\n",p->d_name);        
 
              FILEHANDLE fh = local_file_open(p->d_name, O_RDONLY);
              LocalFileHandle* lfh = new LocalFileHandle(fh);
              // TODO: Make sure that lfh was allocated successfully.
    
              if ( fh  == NULL ) 
                 {
                   fprintf(stderr,"local_file_open failed\n");
                   exit(1);
                }
 
              printf("local file open  - %d\r\n",++filecount);
 
              lfh->read(FileBuffer,64);
 
              printf("Closing LocalFileHandle\r\n");   
              l1=1;
              // Don't need to delete lfh as lfh->close() takes care of that.
              lfh->close();
              l1=0;
              printf("Closed\r\n");   
    
           }   // twas a .MID file
 
       }   // all in directory
 
     printf("Closing directory\r\n");   
     closedir(d);
     printf("Directory closed\r\n");   
     
  }  // forever
 
} // main
25 Nov 2013

Thanks Adam (again - you seem to have solutions for all my problems).

I tried that and it works. Why the close() should do what it does is a bit too subtle for me at this stage.

I let the test program run around the loop over a thousand times and it was still going strong. I can tell you the LocalFileSystem was getting presented to the host PC and then whipped away so rapidly that I thought Windows was going to have a heart attack. I was still getting silly windows popping up asking me what to do with the files it found long after I reset the test program.

I have the real program running now, but I'm pretty sure it is going to make it around the loop as many times as I want.