www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik MSP430 mit Circuit Cillar Code für FAT16 - fehlende Funktionen


Autor: Mark M. (mom-jovi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe mir den Source Code für die Anbindung einer SD-Karte an meinen
MSP430 heruntergeladen von Circuit Cellar (sham176.zip) FAT16 MMC/SD mit
MMC/SD Hardwaretreiber für MSP430

Auf den ersten Blick gibt es recht wenige Funktionen, z.B. fehlen 
Suchfunktionen und dgl., aber das kann man sich ja selber 
zusammenbasteln.

Ärgerlich ist aber, dass die Funktion nur dann einen Handle ausgibt, 
wenn es die zu öffnende Datei noch nicht gibt! Das ist ziemlich 
unpraktisch. Wie mach ich das?
/**
 *  opens the file indicated by the input path name.  If the pathname
 *  points to a valid path, the file is created and added to the list of
 *  currently opened files for writing and the unique file handle is returned.
 *
 *  @param  pathname  a pointer to the location of the file to be opened
 *
 *  @return  -1      invalid pathname
 *  @return  -2      file already exist
 *  @return  -3      file already opened for writing
 *  @return  -4      no directory entries left
 *  @return -10      no handles available
 *  @return  -20      memory card error
 *  @return  -128    other error
 *  @return  (non-negative)  file handle of sucessfully opened file
 **/
signed char fat_openWrite(const char *pathname)
{
    unsigned char buf[SECTOR_SIZE];
  const char *tempPathname;
  unsigned long cluster;
  unsigned long tempCluster;
  unsigned long fileSize = 0;
  signed char i = 0;
  signed char index = -1;

  if(detectCard() == FALSE)
  {
    return -20;
  }

  if(filesOpenedWrite >= BUFFER_SIZE)
  {
    return -10;
  }
  else
  {
    while((i < BUFFER_SIZE) && (index < 0))
    {
      if(openedWrite[i].fileHandle == -1)
      {
        index = i;
      }
      i++;
    }
  }
  cluster = fileSys;
  
  if(*pathname == 0x5C)
  {
    pathname++;
  }
  tempPathname = pathname;
  while(*tempPathname)
  {
    if(*tempPathname == 0x5C)
      return -128;
    tempPathname++;
  }  

  tempPathname = pathname;

  if(cluster != 0)
  {
    tempCluster = cluster;
    cluster = getFirstCluster(tempPathname, cluster, buf, FILE, &fileSize);
    if(cluster != 0)
    {
      return -2;
    }
    else
    {  
      cluster = createNewEntry(tempPathname, tempCluster, buf, FILE);
      if(cluster != 0)
      {
        openedWrite[index].currentCluster = cluster;
        openedWrite[index].dirLocation = tempCluster;
        openedWrite[index].fileHandle = getFileHandle();
        openedWrite[index].fileSize = 0;
        openedWrite[index].sectorCount = 0;
        openedWrite[index].firstCluster = cluster;
        openedWrite[index].byteCount = 0;
                openedWrite[index].updateDir = FALSE;
        filesOpenedWrite++;
        return openedWrite[index].fileHandle;
      }
      else
      {
        return -4;
      }
    }
  }
  else
  {
    return -1;
  }
  return -128;
}

Autor: Mark M. (mom-jovi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nochmal zu diesem Thema.
Ich möchte die Dateinamen dynamisch verändern können, wenn eine 
bestimmte Datei schon existiert. Nun verlangt fat_openWrite aber einen 
kostanten String.
Was hat es für Auswirkungen, wenn ich das const an allen Stellen im 
Programm entferne, wo es um pathname geht?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alle Stellen im Programm sieht man nicht. IMHO ist es aber 
wahrscheinlich, dass es Probleme gibt.

An der gezeigten Stelle: Keine Probleme zu erwarten. Das const ist hier 
ein Hinweis, dass die Funktion fat_openWrite pathname selbst nicht 
manipuliert sondern nur lesend darauf zu greift.

Autor: Mark M. (mom-jovi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, hier sind noch die beiden anderen Funktionen,
getFirstCluster,
createNewEntry,
die in fat_openWrite aufgerufen werden und für die der pathname relevant 
ist. Ich poste sie der Übersicht halber einzeln.

Autor: Mark M. (mom-jovi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
/**
 *  determines the location of the cluster of the file or directory
 *  pointed to by the input pathname.  Only the first token in 
 *  the string pointed to by pathname is used (anything before '\').
 *
 *  @param  buf      the buffer to be used to access the MMC/SD card
 *  @param  pathname  pointer to the string of the pathname
 *  @param  cluster    location of the current directory where the
 *            file or directory being seek is located
 *  @param  control    determines whether a file or a directory is being seek
 *  @param  fileSize  stores the size of the file being seeked
 *
 *  @return  0      if the directory or file does not exist
 *  @return ...      the first cluster of the directory or file being seeked
 **/
static unsigned long getFirstCluster(const char *pathname, unsigned long cluster, unsigned char *buf, boolean control, unsigned long * fileSize)
{
  int offset = 0;
  unsigned int sectorCount;
  unsigned long sector;    
  unsigned char i, j;
  unsigned char tokenLength = 0;    // path name contails tokes less than 255 characters long
  const char *tempPathname;
  boolean matchingNames;
  boolean targetFound;

  if((cluster == 1)&&(fileSys == FAT16))
  {
    sector = rootDirectory;
  }
  else
  {
        return 0;
  }

  tempPathname = pathname;

  while((*tempPathname != 0x5C)&&(*tempPathname))
  {
    tokenLength++;
    tempPathname++;
  }
  
  targetFound = FALSE;
  sectorCount = 0;
  i = 0;
  readSector(sector, buf);
  if(((tokenLength < 13)&&(control == FILE)))
  {  
    while((targetFound == FALSE)&&(sector > 0))
    {
      offset = i * 32;
      tempPathname = pathname;
      matchingNames = TRUE;

            if (control == FILE)
      {                
                if (buf[offset] == '\0')
                {
                    // End of entries.
                    break;
                }

                // Check attributes except for ARCHIVE or READONLY, and for deleted entries:
        if(((buf[11+offset] & 0xDE) == 0x00)&&((buf[offset] & 0xFF) != 0xE5))
        {
          for(j = 0; j < 8; j++)
          {          
                        if (*tempPathname != '.' && *tempPathname != '\0')
                        {
                            // Before end of filename, characters must match:
                            if (!charEquals(buf[offset+j], *tempPathname))
                            {
                                matchingNames = FALSE;
                            }

              tempPathname++;
                        }
            else if ((buf[offset+j]) != ' ')
            {
                            // After end of filename, must have blanks.
              matchingNames = FALSE;
            }
          }

                    if (*tempPathname != '\0')
                    {
                        tempPathname++;
                    }

          for(j = 8; j < 11; j++)
          {          
                        if (*tempPathname != '\0')
                        {
                            // Before end of extension, characters must match:
                            if (!charEquals(buf[offset+j], *tempPathname))
                            {
                                matchingNames = FALSE;
                            }

              tempPathname++;
                        }
            else if ((buf[j+offset]) != ' ')
            {
                            // After end of extension, must have blanks.
              matchingNames = FALSE;
            }
          }

          if (matchingNames)
          {
            targetFound = TRUE;
          }
        }

      }
      i++;
      if(i == 16)    // 16 = directory entries per sector (fixed number)
      {
        i = 0;
        sectorCount++;
        if((cluster == 1)&&(fileSys == FAT16))
        {
          if( sectorCount < rootSectors )
          {
            sector++;
          }
          else
          {
            sector = 0;
          }
        }
        else
        {
          if(sectorCount != sectorsPerCluster)
          {
            sector++;
          }
          else
          {
            sectorCount = 0;
            cluster = getNextFAT(cluster, buf);
            if((cluster <= 0xFFF6)&&(cluster >= 2))
            {
              sector = (cluster - 2) * sectorsPerCluster + dataStarts;                
            }
            else
            {
              sector = 0;
            }
          }
        }
        readSector(sector, buf);
      }    
    }
  }

  if(targetFound)
  {
    cluster = buf[26+offset];
    cluster |= (unsigned long int)buf[27+offset] << 8;
    
    *fileSize = buf[28+offset];
    *fileSize += (unsigned long int)buf[29+offset] << 8;
    *fileSize += (unsigned long int)buf[30+offset] << 16;
    *fileSize += (unsigned long int)buf[31+offset] << 24;
  }
  else
  {
    cluster = 0;
  }
  return cluster;
}

Autor: Mark M. (mom-jovi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
/**
 *  creates a new entry (file or directory) at the location indicated by the
 *  input cluster.  The input control determines whether a file or a
 *  directory is created
 *  *****ONLY FILES AND DIRECTORY WITH SHORT FILE NAMES ARE SUPPORTED
 *
 *  @param  buf      the buffer to be used to access the MMC/SD card  
 *  @param  entryName  pointer to the name of the new entry
 *  @param  cluster    location of the current directory where the new entry will be added
 *  @param  control    FILE or DIRECTORY
 *
 *  @return  0      if an error occurs while adding a new entry
 *  @return  ...      the location of the first cluster of the new entry
 **/
static unsigned long createNewEntry(const char *entryName, unsigned long cluster, unsigned char *buf, boolean control)
{
  unsigned int offset;
  unsigned int sectorCount = 0;
  unsigned int tokenLength = 0;    
  unsigned long sector;
  unsigned long newCluster;
  unsigned char i;  
  const char *tempEntryName;  
  boolean done = FALSE;

    // Note:  findEmptyCluster() will mark the returned cluster in the FAT
    // as used.  If we fail for some other reason below, we should really
    // free the newCluster, but we don't right now.  Also, unless we are
    // creating a directory, we really shouldn't allocate a first cluster
    // until some data is written to the file.  Additionally, if we re-use a
    // deleted entry, we should re-use the cluster chain, adding clusters as
    // required, but we don't do that right now either.
  newCluster = findEmptyCluster(buf);
  if(newCluster == 0)
  {
    return 0;  // no more empty cluster
  }

  if((cluster == 1) && (fileSys == FAT16))
  {
    sector = rootDirectory;
  }
  else
  {
    sector = (cluster - 2) * sectorsPerCluster + dataStarts;    
  }

  tempEntryName = entryName;

  while((*tempEntryName != '.')&&(*tempEntryName)&&(*tempEntryName != 0x5C))
  {
    tokenLength++;
    tempEntryName++;
  }

  while(!done)
  {        
    readSector(sector, buf);
    i = 0;
    while(i < 16)
    {
      offset = i * 32;      
      if(((buf[offset] & 0xFF) == 0x00) || ( (buf[offset] & 0xFF) == 0xE5) )
      {
        done = TRUE;
        i = 15;
      }
      i++;
    }
    if(!done)
    {
      sectorCount++;
      if((cluster == 1)&&(fileSys == FAT16))
      {
        if(sectorCount < rootSectors)
        {
          sector++;
        }
        else
        {
          return 0;  // no more root directory
        }
      }
      else
      {
                return 0;
      }        
    }
  }

  if(control == FILE)
  {
    buf[offset+11] = 0x20;
    if(tokenLength < 9)
    {      
      for(i = 0; i < 8; i++)
      {
        if(*entryName != '.')
        {
          if((*entryName >= 'a')&&(*entryName <= 'z'))
          {
            buf[offset+i] = (*entryName - 32);
          }
          else
          {
            buf[offset+i] = *entryName ;
          }
          entryName++;
        }
        else
        {
          buf[offset+i] = 0x20;
        }
      }
      entryName++;
      for(i = 8; i < 11; i++)
      {
        if(*entryName)
        {
          if((*entryName >= 'a')&&(*entryName <= 'z'))
          {
            buf[offset+i] = (*entryName - 32);
          }
          else
          {
            buf[offset+i] = *entryName ;
          }
          entryName++;
        }
        else
        {
          buf[offset+i] = 0x20;
        }
      }            
    }
    else
    {
      // file with long file name
      return 0;
    }
  }

  buf[offset+12] = 0x00;
  buf[offset+13] = 0x00;

    // Set the date and time to January 02, 2005 21:00:00 .
    // If a real time clock is available, we could use it.
  buf[offset+14] = (04 >> 1) & 0x1F;  // Seconds.
  buf[offset+14] |= 03 << 5;  // Part of minutes.
  buf[offset+22] = buf[offset+14];

  buf[offset+15] = (03 >> 3) & 0x07;  // More of minutes.
  buf[offset+15] |= 21 << 3;  // Hours.
  buf[offset+23] = buf[offset+15];      
  
  buf[offset+16] = 02 & 0x1F;     // Day.
  buf[offset+16] |= (01 << 5) & 0xE0;   // Part of month.
  buf[offset+18] = buf[offset+16];
  buf[offset+24] = buf[offset+16];
        
  buf[offset+17] = (01 >> 3) & 0x01;   // More of month.
  buf[offset+17] |= (((2005 - 1980) & 0xFF) << 1) & 0xFE;  // Year.
  buf[offset+19] = buf[offset+17];
  buf[offset+25] = buf[offset+17];

  buf[offset+26] = (newCluster & 0xFF);
  buf[offset+27] = (newCluster >> 8) & 0xFF;

  for(i = 28; i < 32; i++)
  {
    buf[offset+i] = 0x00;
  }
  writeSector(sector, buf);

  return newCluster;
}

Autor: Mark M. (mom-jovi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kommt es zu Problemen, wenn andere Funktionen diese beiden letzten 
Funktionen auch verwenden, dann aber ein const char übergeben, wo ein 
char verlangt wird?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nö, die ändern am Pfadnamen auch nichts. Dein Vorgehen sollte so sein:

1. Du erstellst einen eindeutigen, nicht vorhandenen Dateinamen
   z.B. in einem globalen Array.

2. Die aufrufende Funktion von fat_openWrite() übergibt diesen
   Dateinamen

3. fat_openWrite() und die von fat_openWrite() aufgerufenen Funktionen
   benutzen den Dateinamen lesend wie bisher

Autor: Mark M. (mom-jovi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aber zuvor sollte ich die const entfernen, oder nicht?

Autor: Mark M. (mom-jovi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das funktioniert leider nicht.
Kann man denn irgendwie einen nicht konstanten als konstant übergeben?

Autor: Bjoern (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast Du denn alle const entfernt?

Autor: Mark M. (mom-jovi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bjoern schrieb:
> Hast Du denn alle const entfernt?

Ja.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Das funktioniert leider nicht.

Kann ich mir nicht vorstellen.

Das Prinzip:
#include <string.h>
#include <stdio.h>

char dateiname[23];

int bar(const char *dn)  // Dateinamen benutzen #2
{
  return strlen(dn);
}

int foo(const char *dn)  // Dateinamen benutzen #1
{
  return bar(dn); 
}

int main(void)
{
  strcpy(dateiname, "dreiundzwanzig"); // Dateinamen erzeugen
  printf("%d\n", foo(dateiname));
}

Bekommst du Compilerprobleme oder Laufzeitprobleme?

Autor: Mark M. (mom-jovi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Laufzeitprobleme. Der Compiler geht durch, im Debugger läuft auch alles.
Aber die Datei ist nachher nicht auf der microSD.

Den Aufruf wie in deiner Main hab ich noch nicht ausprobiert, weil ich 
gerade noch an ner anderen Baustelle bin. Aber ich habs mit nem String 
outputFile versucht:
char outputFile[13]={"data.txt"}; //13 Elemente, weil 8.3-Format + Terminator

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daran liegt es nicht, der Code sollte mit deiner Schreibweise auch 
funktionieren. Laufzeitprobleme sind die übelsten. Ich drücke dir die 
Daumen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.