Recursive SPIN routine - USB thumbdrive file find
                    I wanted to develop a routine for my VMUSIC2 project which would locate a particular MP3 file on a USB thumbdrive inserted into the VMUSIC2.
Of course, there can be many nested folders and it seemed that a recursive routine was the best approach.
Since the Parallax memory stick datalogger module is similar to the VMUSIC2 (both use the Vinculum VNC1L USB host controller), this code should work
with the datalogger.
I have many vbscripts that do this using the FileSystemObject in the Windows scripting runtime DLL but doing this in SPIN for a Propeller
would be a different scenario due to memory constraints, etc.
What I did was define a global byte array in the DAT section which would hold up to 500 thirteen byte top-level directory names i.e. directories immediately under the root.
Then I created recursive method which defines a local variable to store up to 10 sub-folder names. It calls itself to handle nested sub-folders.
It passes an index pointer, directory counter, and subfolder array address to the supporting methods.
As it works it way through the directory structure, it looks at each file name and compares it to the search filename.
I use a variable named dirlvl to keep track of the nesting level. It is also used to build a array of the directory names maintaining a path to the current folder.
Of course, as the routine calls itself, more memory is being allocated and then freed up when a directory has been processed
and processing resumes with the parent directory.
I am trying to figure out the best way to monitor available memory during the recursion.
One way would be to check the dirlvl variable, but there may be a better way.
I also want to see if I can speed it up...
Here is the terminal output using a some small folders - you can see the line "
> Found it!" when the file has been located.
 
                
                            Of course, there can be many nested folders and it seemed that a recursive routine was the best approach.
Since the Parallax memory stick datalogger module is similar to the VMUSIC2 (both use the Vinculum VNC1L USB host controller), this code should work
with the datalogger.
I have many vbscripts that do this using the FileSystemObject in the Windows scripting runtime DLL but doing this in SPIN for a Propeller
would be a different scenario due to memory constraints, etc.
What I did was define a global byte array in the DAT section which would hold up to 500 thirteen byte top-level directory names i.e. directories immediately under the root.
Then I created recursive method which defines a local variable to store up to 10 sub-folder names. It calls itself to handle nested sub-folders.
It passes an index pointer, directory counter, and subfolder array address to the supporting methods.
As it works it way through the directory structure, it looks at each file name and compares it to the search filename.
I use a variable named dirlvl to keep track of the nesting level. It is also used to build a array of the directory names maintaining a path to the current folder.
Of course, as the routine calls itself, more memory is being allocated and then freed up when a directory has been processed
and processing resumes with the parent directory.
I am trying to figure out the best way to monitor available memory during the recursion.
One way would be to check the dirlvl variable, but there may be a better way.
I also want to see if I can speed it up...
[SIZE=2]CON
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000[/SIZE]
[SIZE=2]' -------  Pin assigments ------
  vm_rts   = 0             ' Request To Send --> VMusic2 pin 6  (CTS#)  - green 
  vm_rx    = 1             ' Receive Data    <-- VMusic2 pin 5  (TXD)   - yellow
  vm_tx    = 2             ' Transmit Data   --> VMusic2 pin 4  (RXD)   - orange
  vm_cts   = 3             ' Clear To Send   <-- VMusic2 pin 2  (RTS#)  - brown[/SIZE]
[SIZE=2]vm_port       = 0
  BAUD          = 9_600         ' LCD baud rate
  maxdirs       = 500           ' number of directory names to table
  maxpath       = 10            ' max number of folder names in path for recursive routine
  maxsubdirs    = 12            ' number of sub folders allowed under top level folder
  maxbuff       = 60            ' size of buffer for parsing VM2 serial output
  
VAR
  long useser           ' USB serial connection detected T/F
  long debugsw          ' control output to Parallax Terminal
  long diskchk          ' "No Disk" check
  byte fname[13]           ' file name playing
  byte rxbuff[maxbuff]     ' work buffer 
  byte mp3title[maxbuff]   ' hold song title
  byte artist[maxbuff]     ' hold artist
  byte buffptr[/SIZE]
[SIZE=2]word dircntr          'directory counter
  long dirptr           'directory pointer
  byte dirlvl           'directory nesting level
  byte findsw           '1=recursive search for filename
  long pathptr          'path pointer[/SIZE]
[SIZE=2]
OBJ
  uarts         : "pcFullDuplexSerial4FC" '1 COG for 4 serial ports
  Debug         : "FullDuplexSerial"  '"SerialMirror"  '"Extended_FDSerial"
  I2C           : "Basic_I2C_Driver_1"
' strng         : "ASCII0_STREngine_1"   
  
PUB Main | idx     
  dira[vm_rts]~~                 
  outa[vm_rts]~                        ' Take Vinculum Out Of Reset - set low
  
  useser := false
  if ina[31] == 1                      ' RX (pin 31) is high if USB is connected
    Debug.start(31, 30, 0, 57600)      ' ignore tx echo on rx
    useser := true                     ' Debug serial connection is active
    debugsw := true
  else
    outa[30] := 0                      ' Force Propeller Tx line LOW if USB not connected
    
''-----------------------
''override debugsw to disable terminal displays
' debugsw := false     
''-----------------------[/SIZE]
[SIZE=2]if debugsw == true
    Debug.str(string(16,"Please wait",13))  ' CLS, disp msg[/SIZE]
[SIZE=2]I2C.Initialize(I2C#BootPin)               ' initialize I2C object
  
  diskchk := 1[/SIZE]
[SIZE=2]uarts.Init                           'start four port serial cog
'  uarts.AddPort(vm_port,vm_rx,vm_tx,vm_cts,vm_rts,UARTS#DEFAULTTHRESHOLD,UARTS#NOMODE,UARTS#BAUD9600)
  uarts.AddPort(vm_port,vm_rx,vm_tx,vm_cts,vm_rts,UARTS#DEFAULTTHRESHOLD,UARTS#INVERTCTS,UARTS#BAUD9600)
  uarts.Start    
  Read_VMResp[/SIZE]
[SIZE=2]waitcnt(clkfreq * 2 + cnt)
  uarts.str(vm_port, string("IPA",$0D)) 'monitor mode ascii
  Read_VMResp
  waitcnt(clkfreq / 2 + cnt)   [/SIZE]
[SIZE=2]uarts.str(vm_port, string("ECS",$0D)) 'extended command set
  Read_VMResp
  waitcnt(clkfreq / 2 + cnt)   [/SIZE]
[SIZE=2]uarts.str(vm_port, string("CD / "))     'CD root                  
  Read_VMResp[/SIZE]
[SIZE=2]
{  store directory names in dirs table
}[/SIZE]
[SIZE=2]ReadDirectory            'read and store directory names[/SIZE]
[SIZE=2]
  bytemove(@fname, string("STARBU~1.MP3"),13)
  FindFile[/SIZE]
[SIZE=2]
  repeat
    waitcnt(clkfreq * 5 + cnt)   [/SIZE]
[SIZE=2]{  store directory names in dirs table
} 
PUB ReadDirectory | idx
  dircntr := 0
  dirptr := @dirs    
'  debug.dec(@rxbuff)   'address of rxbuff
'  debug.tx(13)
  debug.str(string("dirs addr: "))
  debug.dec(dirptr)     'address of dirs
  debug.tx(13)
  buffptr := 0  
  uarts.str(vm_port, string("DIR",$0D))   'directory list
  Read_Dirs[/SIZE]
[SIZE=2]if debugsw == true
    repeat idx from 0 to dircntr-1
      dirptr := @dirs + (idx * 13)
      debug.dec(dirptr)
      debug.tx(32)
      debug.str(dirptr)
      debug.tx(13)[/SIZE]
[SIZE=2]buffptr := 0  
  waitcnt(clkfreq * 2 + cnt) [/SIZE]
[SIZE=2]{ Read directory names (under root) and store into dirs byte array
  Each directory name takes 13 bytes
}
PUB Read_Dirs| iobyte
  iobyte:=0
  repeat
    iobyte:=uarts.rxtime(vm_port,500)
    if iobyte < 0 
      quit
    else
'      debug.tx(iobyte)
      if Process_Directory(iobyte)
        if debugsw == true 
          debug.dec(dircntr)
          debug.str(string(" Directories",13))
      
PUB Process_Directory(datain)
  if datain == 13                     'carriage return?
    rxbuff[buffptr++] := 0
    if StoreDir
      return true
    buffptr :=0
'    bytefill(@rxbuff, 0, maxbuff)    'Clear Buff to 0
    return
  else  
    if buffptr < maxbuff - 1 
      rxbuff[buffptr++] := datain     'add byte to buffer[/SIZE]
[SIZE=2]
PUB StoreDir | dirlen
  if findString(@rxbuff,string("D:\>")) > 0
    return true
  dirlen := findString(@rxbuff,string(" DIR")) - @rxbuff    'calc length of directory name
  if dirlen > 0              'length of directory name
'    debug.dec(dirlen)
'    debug.tx(13)
    bytemove(dirptr, @rxbuff, dirlen)
    dircntr++
    dirptr := @dirs + (dircntr * 13)    'calc addr to store next dir name  
'    debug.dec(dirptr)
'    debug.tx(13)[/SIZE]
[SIZE=2]
PUB FindFile | idx
  findsw := 1           'enable filename match 
  debug.str(string("Searching for: "))
  debug.str(@fname)
  debug.tx(13)
'loop thru top level directories
  repeat idx from 0 to dircntr-1      
    dirptr := @dirs + (idx * 13)
    dirlvl :=0
'   debug.str(dirptr)
'   debug.tx(13)
    Recurse(dirptr)             'call recursive routine to search for file
  debug.str(string("Done Searching"))
  findsw := 0           'disable filename match 
  
PUB Recurse(parent)| fldrptr, fldrcntr, fldrs[(maxsubdirs * 13) / 4], idx, psize
  dirlvl++
' if dirlvl == 1
'   bytefill(@dirpath,0,maxpath*13)
  pathptr := @dirpath + ((dirlvl-1) * 13)
  psize := strsize(parent)
  bytemove(pathptr, parent, psize)
  debug.str(string(13,"Path: "))
   repeat idx from 0 to dirlvl-1
     debug.tx("\")
     debug.str(@dirpath + (idx * 13))
  debug.tx(13)
{
  debug.tx(13)
  debug.str(string("- - - - - - - - - - - "))
  debug.str(string("dir level: "))
  debug.dec(dirlvl)
  debug.tx(13)
}
  fldrptr := @fldrs
  fldrcntr := 0
  longfill(@fldrs, 0, 39)
  
{
  debug.str(string("fldrs addr: "))
  debug.dec(fldrptr)
  debug.tx(13)
}
  if findString(parent,string("/")) <> @parent
{
    debug.str(string("CD "))
    debug.str(fldr)
    debug.tx(13)
}
    uarts.str(vm_port, string("CD "))
    uarts.str(vm_port, parent)           'change directory
    uarts.tx(vm_port, $0D)               'carriage return
    Read_VMResp[/SIZE]
[SIZE=2]{
  buffptr := 0
  if findsw == 1
    uarts.str(vm_port, string("DIR "))
    uarts.str(vm_port, @fname)            'dir 'filename'
    uarts.tx(vm_port,$0D)  
    Read_VMResp
}
  
  uarts.str(vm_port, string("DIR",$0D))   'directory list
  Read_SubDirs(@fldrptr, @fldrcntr, @fldrs)[/SIZE]
[SIZE=2]'for each sub folder
  if fldrcntr > 0
    repeat idx from 0 to fldrcntr-1
      fldrptr := @fldrs + (idx * 13)
      Recurse(fldrptr)[/SIZE]
[SIZE=2]uarts.str(vm_port, string("CD ..",$0D))       'change to parent directory
  buffptr := 0
  pathptr := @dirpath + ((dirlvl-1) * 13)
  bytefill(pathptr,0,13)
  dirlvl--[/SIZE]
[SIZE=2]
PUB Read_SubDirs(fldrptr,fldrcntr,fldrs) | iobyte
  iobyte:=0
  repeat
    iobyte:=uarts.rxtime(vm_port,500)
    if iobyte < 0 
      quit
    else
'      debug.tx(iobyte)
      if Process_SubDirectory(iobyte, fldrptr,fldrcntr,fldrs)
'        if debugsw == true 
'          debug.dec(fldrcntr)
'          debug.str(string(" Directories",13))
      
PUB Process_SubDirectory(datain,fldrptr,fldrcntr,fldrs)
'  debug.str(string("proc dir: "))
'  debug.dec(long[fldrptr])
'  debug.tx(32)
'  debug.dec(long[fldrcntr])
'  debug.tx(13)
  if datain == 13                     'carriage return?
    rxbuff[buffptr++] := 0
    if StoreSubDir(fldrptr,fldrcntr,fldrs)
      return true
    buffptr :=0
'    bytefill(@rxbuff, 0, maxbuff)    'Clear Buff to 0
    return
  else  
    if buffptr < maxbuff - 1 
      rxbuff[buffptr++] := datain     'add byte to buffer[/SIZE]
[SIZE=2]PUB StoreSubDir(fldrptr,fldrcntr,fldrs) | dirlen
  if findString(@rxbuff,string("D:\>")) > 0
    return true
  if findString(@rxbuff, string(". DIR")) == @rxbuff 
    return
  if findString(@rxbuff, string(".. DIR")) == @rxbuff
    return
  dirlen := findString(@rxbuff,string(" DIR")) - @rxbuff    'calc length of directory name
  if long[fldrcntr] > (maxsubdirs - 1)                      'fldrs array is full
    debug.str(string("Too many sub folders"))
    debug.tx(13)
    return
  if dirlen > 0              'length of directory name
'    debug.str(string("store dir: "))
'    debug.dec(long[fldrptr])
'    debug.tx(32)
'    debug.dec(long[fldrcntr])
'    debug.tx(32)
'    debug.dec(dirlen)
'    debug.tx(13)
    bytemove(long[fldrptr], @rxbuff, dirlen)
    long[fldrcntr]++
    long[fldrptr] := fldrs + (long[fldrcntr] * 13)    'calc addr to store next dir name
  else
    if byte[@rxbuff][0] <> 0       ' ignore blank line at top of dir listing
      debug.str(@rxbuff)           ' file, not directory
      debug.tx(13)
      if findsw == 1
        if findString(@rxbuff, @fname) == @rxbuff
          debug.str(string("------> Found it!"))
          debug.tx(13)[/SIZE]
[SIZE=2]PUB Read_VMResp | iobyte
  iobyte:=0
  repeat
    iobyte:=uarts.rxtime(vm_port,500)
    if iobyte < 0 
      quit
    else
       Buffer_datain(iobyte)
'     if debugsw == true   
'       debug.tx(iobyte)[/SIZE]
[SIZE=2]PUB Buffer_datain(datain)
  if datain == 13                     'carriage return?
    rxbuff[buffptr++] := 0
    if debugsw == true 
      DisplayBuff
    buffptr :=0
    return
  else  
    if buffptr < maxbuff - 1 
      rxbuff[buffptr++] := datain     'add byte to buffer[/SIZE]
[SIZE=2]PUB DisplayBuff | idx
  if strsize(@rxbuff) < 1                         'suppress blank line after any dir command
    return true
  if findString(@rxbuff,string("D:\>")) > 0       'suppress standard response
'    debug.tx(".")   
    return true
  if findString(@rxbuff,string("Command Failed")) > 0 
    return true[/SIZE]
[SIZE=2]if findsw == 1
    if findString(@rxbuff, @fname) == @rxbuff
      debug.str(string("------> Found it!"))
      debug.tx(13)   [/SIZE]
[SIZE=2]debug.str(@rxbuff)
  debug.tx(13)[/SIZE]
[SIZE=2]PUB findString(stringToSearch, stringToFind) | index, size ' 7 Stack Longs
'// Author: Kwabena W. Agyeman  
' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
' // Searches a string of characters for the first occurence of the specified string of characters.
' //
' // Returns the address of that string of characters if found and zero if not found.
' //
' // StringToSearch - A pointer to the string of characters to search.
' // StringToFind - A pointer to the string of characters to find in the string of characters to search.
' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////[/SIZE]
[SIZE=2]size := strsize(stringToFind)
  if(size--)[/SIZE]
[SIZE=2]repeat strsize(stringToSearch--)
      if(byte[++stringToSearch] == byte[stringToFind])[/SIZE]
[SIZE=2]repeat index from 0 to size
          if(byte[stringToSearch][index] <> byte[stringToFind][index])
            result := true
            quit[/SIZE]
[SIZE=2]ifnot(result~)
          return stringToSearch
  
DAT
  nodisk  byte "No Disk",0
  dirs    byte $00[maxdirs*13]         'array of directory names under root
  dirpath byte $00[maxpath*13]              'allow ten deep directory path [/SIZE]
Here is the terminal output using a some small folders - you can see the line "
> Found it!" when the file has been located.
[SIZE=2]Please wait Ver 03.68VMSC1F On-Line: Device Detected P2 No Upgrade dirs addr: 96 3 Directories 96 JAZZ 109 VARIOU~1 122 PORTER Searching for: STARBU~1.MP3[/SIZE] [SIZE=2]Path: \JAZZ[/SIZE] [SIZE=2]Path: \JAZZ\JAZZ1 BLOWIN~1.MP3 BLUEDA~1.MP3 BODYHE~1.MP3 HEARTS~1.MP3 HEAVEN.MP3 LOSTSU~1.MP3 NORTHE~1.MP3 REALLY~1.MP3 SEEYOU~1.MP3 SOUNDO~1.MP3 STROLL~1.MP3 WITHOU~1.MP3[/SIZE] [SIZE=2]Path: \JAZZ\JAZZ2 CANYOU~1.MP3 DOYOUR~1.MP3 GOODLO~1.MP3 INNERC~1.MP3 JUSTCA~1.MP3 SLOMOT~1.MP3 SMOOTH~1.MP3 SOMUCH~1.MP3 SUMMER~1.MP3 TIMETO~1.MP3 WALKIN~1.MP3 WONDER~1.MP3[/SIZE] [SIZE=2]Path: \JAZZ\JAZZ3 DON'TL~1.MP3 DOWNSO~1.MP3 DREAMS.MP3 LONDON~1.MP3 LONDON~2.MP3 LOSTIN~1.MP3 NEWDAW~1.MP3 NIGHTC~1.MP3 REDZON~1.MP3 STARCH~1.MP3 STILLT~1.MP3 TRIPPI~1.MP3 VENTUR~1.MP3[/SIZE] [SIZE=2]Path: \JAZZ\JAZZ4 KEYS_4.MP3[/SIZE] [SIZE=2]Path: \JAZZ\JAZZ5 KEYS_5.MP3[/SIZE] [SIZE=2]Path: \JAZZ\JAZZ6 KEYS_6.MP3[/SIZE] [SIZE=2]Path: \JAZZ\JAZZ7 KEYS_7.MP3[/SIZE] [SIZE=2]Path: \JAZZ\JAZZ8 KEYS_8.MP3[/SIZE] [SIZE=2]Path: \JAZZ\JAZZ9 KEYS_9.MP3[/SIZE] [SIZE=2]Path: \JAZZ\JAZZ10 KEYS_10.MP3[/SIZE] [SIZE=2]Path: \JAZZ\JAZZ11 KEYS_11.MP3[/SIZE] [SIZE=2]Path: \JAZZ\JAZZ12 KEYS_12.MP3[/SIZE] [SIZE=2]Path: \VARIOU~1[/SIZE] [SIZE=2]Path: \VARIOU~1\THEBIG~1 AWHITE~1.MP3 DANCIN~1.MP3 GOODLO~1.MP3 ISECON~1.MP3 ITSTHE~1.MP3 NATURA~1.MP3 TELLHI~1.MP3 TOOMAN~1.MP3 TRACKS~1.MP3 WHAT'S~1.MP3[/SIZE] [SIZE=2]Path: \VARIOU~1\TEENAG~1 BOBBYS~1.MP3 BORNTO~1.MP3 CHANCE~1.MP3 CRYMEA~1.MP3 DEVILO~1.MP3 HOLDME~1.MP3 IT'SAL~1.MP3 IT'SON~1.MP3 MYHEAR~1.MP3 MYSPEC~1.MP3 PRETTY~1.MP3 SEAOFL~1.MP3 SEALED~1.MP3 TEENAN~1.MP3 TELLLA~1.MP3[/SIZE] [SIZE=2]Path: \VARIOU~1\ONEHIT~1 986~1.MP3 COMEON~1.MP3 DOMINI~1.MP3 JUNGLE~1.MP3 MONTEG~1.MP3 ONETIN~1.MP3 REFLEC~1.MP3 YOUDON~1.MP3[/SIZE] [SIZE=2]Path: \VARIOU~1\MOREPU~1 DOYOUR~1.MP3 HANDST~1.MP3 IKNOWT~1.MP3 I'VEDO~1.MP3 JEOPARDY.MP3 LOVEIS~1.MP3 RIO.MP3 ROCKME~1.MP3 SHOUT.MP3 THELOO~1.MP3 THEPOW~1.MP3 THESAF~1.MP3 WALKIN~1.MP3 WOULDI~1.MP3[/SIZE] [SIZE=2]Path: \VARIOU~1\HARDTO~1.6MO (DOWNA~1.MP3 (JUSTL~1.MP3 AKOOKI~1.MP3 BLACKI~1.MP3 EVERYD~1.MP3 EVERYB~1.MP3 GUANTA~1.MP3 HOLDME~1.MP3 I'MLEA~1.MP3 LAURIE~1.MP3 LIGHTN~1.MP3 MASTER~1.MP3 MYBOYL~1.MP3 NOTHIN~1.MP3 PATAPA~1.MP3 RUMORS.MP3 SAILOR~1.MP3 THEMOR~1.MP3 TOBACC~1.MP3 WALKAW~1.MP3 WITCHI~1.MP3[/SIZE] [SIZE=2]Path: \VARIOU~1\HARDTO~1.560 ANGELO~1.MP3 B-A-B-Y.MP3 DEEPPU~1.MP3 DON'TS~1.MP3 JOHNNY~1.MP3 LET'ST~1.MP3 NEXTPL~1.MP3 ONEBOY~1.MP3 SIXTEE~1.MP3 TAKEAL~1.MP3 TURNAR~1.MP3[/SIZE] [SIZE=2]Path: \VARIOU~1\HARDTO~1.219 BOBBY'~1.MP3 DIANE.MP3 DOMINI~1.MP3 ISAWLI~1.MP3 LITTLE~1.MP3 LITTLE~2.MP3 LOVERP~1.MP3 NAVYBL~1.MP3 PATCHES.MP3 POPSIC~1.MP3 SUGARS~1.MP3 WOODEN~1.MP3 YOUDON~1.MP3[/SIZE] [SIZE=2]Path: \VARIOU~1\DICKCL~1.2 CHAPEL~1.MP3 DUKEOF~1.MP3 EVERYB~1.MP3 HARLEM~1.MP3 LEADER~1.MP3 LETTHE~1.MP3 POETRY~1.MP3 THENYO~1.MP3 THOSEO~1.MP3 TILLIK~1.MP3 TOSSSI~1.MP3 VENUSI~1.MP3[/SIZE] [SIZE=2]Path: \VARIOU~1\DICKBA~1.2 ANGELO~1.MP3 CINNAMON.MP3 EVERLA~1.MP3 EXPRES~1.MP3 GIMMEG~1.MP3 LETITO~1.MP3 MORNIN~1.MP3[/SIZE] [SIZE=2]Path: \VARIOU~1\BILLBO~1 EASIER~1.MP3 FINGER~1.MP3 HE'SSO~1.MP3 LOUIE_~1.MP3 MYBOYF~1.MP3 SUGARS~1.MP3 SURFCI~1.MP3 SURFIN~1.MP3 WALKLI~1.MP3[/SIZE] [SIZE=2]Path: \VARIOU~1\BILLBO~2 ALLEY-~1.MP3 CATHY'~1.MP3 HANDYM~1.MP3 RUNNIN~1.MP3 SAVETH~1.MP3 WALK_D~1.MP3[/SIZE] [SIZE=2]Path: \VARIOU~1\AFTERN~1 CAMPBE~1.MP3 DAWN-K~1.MP3 GLADYS~1.MP3 HARRYN~1.MP3 JIMCRO~1.MP3 JOSEFE~1.MP3 STARBU~1.MP3 ------> Found it! STARLA~1.MP3 STEVEF~1.MP3 THEHOL~1.MP3 THELEM~1.MP3 THERAS~1.MP3[/SIZE] [SIZE=2]Path: \PORTER[/SIZE] [SIZE=2]Path: \PORTER\PORTONE CANDLE~1.MP3 DBBLUE~1.MP3 FLIGHT~1.MP3 FOREVE~1.MP3 JUSTWA~1.MP3 LAKESH~1.MP3 LAYYOU~1.MP3 ONEMOR~1.MP3 WEAREO~1.MP3 WISHFU~1.MP3 Done Searching[/SIZE]

 
                            
Comments
If you're going to be looking up file names often, but changing the contents of the memory stick infrequently, you should consider having a separate program that recursively goes through the directory structure and builds a database that can be easily searched. This database could be stored on a root-level file. If you want to get fancy, you could use a Winbond SPI flash memory to hold the database. These come in sizes up to several megabytes and there's a driver in the ObEx that provides for named files and includes a program loader.
Thanks for the suggestions Mike. I thought about using a vbscript to create a text file with the filenames and paths to load onto the drive beforehand.
The reason behind this effort was that when playing songs randomly on the VMUSIC2, it informs you of the filename playing, but not the path. I wanted to be able to delete the MP3 currently playing but you have to stop playing it first. When you do that, the VMUSIC returns to the root directory so you don't know what folder the file is in.
EDIT: Of course, with the limiting DOS 8.3 filenames, you could end up with two different MP3s with the same name in different folders.
The Winbond flash memory sounds interesting too!
The Winbond flash memories come in sizes up to 8MB in PDIP and the ObEx driver handles up to that size.
I am very familiar with ID3Tag information and have written DLLs, code to modify tag information, and my own MP3 player in VB6 (using the Windows media player API).
I also wrote a vb program to delete unneccesay tag items (like the embedded album art,etc) and convert unicode tags to ascii (the VMUSIC2 won't handle unicode). Zip file (here)
Digikey has the 8Mb PDIP chips for $1.39 - very reasonable!
I attached a ZIP file with the vbscript and this readme.txt file:
I have over 1010 MP3s on my thumbdrive and the sorted list shows many files with the same shortname in different directories.
For example, the are eight different songs named "YOU'RE~1.MP3" - songs that begin with "You're".
It could be a little tricky for the VMUSIC2 to find the right song to delete...