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


von Mark M. (mom-jovi)


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?
1
/**
2
 *  opens the file indicated by the input path name.  If the pathname
3
 *  points to a valid path, the file is created and added to the list of
4
 *  currently opened files for writing and the unique file handle is returned.
5
 *
6
 *  @param  pathname  a pointer to the location of the file to be opened
7
 *
8
 *  @return  -1      invalid pathname
9
 *  @return  -2      file already exist
10
 *  @return  -3      file already opened for writing
11
 *  @return  -4      no directory entries left
12
 *  @return -10      no handles available
13
 *  @return  -20      memory card error
14
 *  @return  -128    other error
15
 *  @return  (non-negative)  file handle of sucessfully opened file
16
 **/
17
signed char fat_openWrite(const char *pathname)
18
{
19
    unsigned char buf[SECTOR_SIZE];
20
  const char *tempPathname;
21
  unsigned long cluster;
22
  unsigned long tempCluster;
23
  unsigned long fileSize = 0;
24
  signed char i = 0;
25
  signed char index = -1;
26
27
  if(detectCard() == FALSE)
28
  {
29
    return -20;
30
  }
31
32
  if(filesOpenedWrite >= BUFFER_SIZE)
33
  {
34
    return -10;
35
  }
36
  else
37
  {
38
    while((i < BUFFER_SIZE) && (index < 0))
39
    {
40
      if(openedWrite[i].fileHandle == -1)
41
      {
42
        index = i;
43
      }
44
      i++;
45
    }
46
  }
47
  cluster = fileSys;
48
  
49
  if(*pathname == 0x5C)
50
  {
51
    pathname++;
52
  }
53
  tempPathname = pathname;
54
  while(*tempPathname)
55
  {
56
    if(*tempPathname == 0x5C)
57
      return -128;
58
    tempPathname++;
59
  }  
60
61
  tempPathname = pathname;
62
63
  if(cluster != 0)
64
  {
65
    tempCluster = cluster;
66
    cluster = getFirstCluster(tempPathname, cluster, buf, FILE, &fileSize);
67
    if(cluster != 0)
68
    {
69
      return -2;
70
    }
71
    else
72
    {  
73
      cluster = createNewEntry(tempPathname, tempCluster, buf, FILE);
74
      if(cluster != 0)
75
      {
76
        openedWrite[index].currentCluster = cluster;
77
        openedWrite[index].dirLocation = tempCluster;
78
        openedWrite[index].fileHandle = getFileHandle();
79
        openedWrite[index].fileSize = 0;
80
        openedWrite[index].sectorCount = 0;
81
        openedWrite[index].firstCluster = cluster;
82
        openedWrite[index].byteCount = 0;
83
                openedWrite[index].updateDir = FALSE;
84
        filesOpenedWrite++;
85
        return openedWrite[index].fileHandle;
86
      }
87
      else
88
      {
89
        return -4;
90
      }
91
    }
92
  }
93
  else
94
  {
95
    return -1;
96
  }
97
  return -128;
98
}

von Mark M. (mom-jovi)


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?

von Stefan B. (stefan) Benutzerseite


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.

von Mark M. (mom-jovi)


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.

von Mark M. (mom-jovi)


Lesenswert?

1
/**
2
 *  determines the location of the cluster of the file or directory
3
 *  pointed to by the input pathname.  Only the first token in 
4
 *  the string pointed to by pathname is used (anything before '\').
5
 *
6
 *  @param  buf      the buffer to be used to access the MMC/SD card
7
 *  @param  pathname  pointer to the string of the pathname
8
 *  @param  cluster    location of the current directory where the
9
 *            file or directory being seek is located
10
 *  @param  control    determines whether a file or a directory is being seek
11
 *  @param  fileSize  stores the size of the file being seeked
12
 *
13
 *  @return  0      if the directory or file does not exist
14
 *  @return ...      the first cluster of the directory or file being seeked
15
 **/
16
static unsigned long getFirstCluster(const char *pathname, unsigned long cluster, unsigned char *buf, boolean control, unsigned long * fileSize)
17
{
18
  int offset = 0;
19
  unsigned int sectorCount;
20
  unsigned long sector;    
21
  unsigned char i, j;
22
  unsigned char tokenLength = 0;    // path name contails tokes less than 255 characters long
23
  const char *tempPathname;
24
  boolean matchingNames;
25
  boolean targetFound;
26
27
  if((cluster == 1)&&(fileSys == FAT16))
28
  {
29
    sector = rootDirectory;
30
  }
31
  else
32
  {
33
        return 0;
34
  }
35
36
  tempPathname = pathname;
37
38
  while((*tempPathname != 0x5C)&&(*tempPathname))
39
  {
40
    tokenLength++;
41
    tempPathname++;
42
  }
43
  
44
  targetFound = FALSE;
45
  sectorCount = 0;
46
  i = 0;
47
  readSector(sector, buf);
48
  if(((tokenLength < 13)&&(control == FILE)))
49
  {  
50
    while((targetFound == FALSE)&&(sector > 0))
51
    {
52
      offset = i * 32;
53
      tempPathname = pathname;
54
      matchingNames = TRUE;
55
56
            if (control == FILE)
57
      {                
58
                if (buf[offset] == '\0')
59
                {
60
                    // End of entries.
61
                    break;
62
                }
63
64
                // Check attributes except for ARCHIVE or READONLY, and for deleted entries:
65
        if(((buf[11+offset] & 0xDE) == 0x00)&&((buf[offset] & 0xFF) != 0xE5))
66
        {
67
          for(j = 0; j < 8; j++)
68
          {          
69
                        if (*tempPathname != '.' && *tempPathname != '\0')
70
                        {
71
                            // Before end of filename, characters must match:
72
                            if (!charEquals(buf[offset+j], *tempPathname))
73
                            {
74
                                matchingNames = FALSE;
75
                            }
76
77
              tempPathname++;
78
                        }
79
            else if ((buf[offset+j]) != ' ')
80
            {
81
                            // After end of filename, must have blanks.
82
              matchingNames = FALSE;
83
            }
84
          }
85
86
                    if (*tempPathname != '\0')
87
                    {
88
                        tempPathname++;
89
                    }
90
91
          for(j = 8; j < 11; j++)
92
          {          
93
                        if (*tempPathname != '\0')
94
                        {
95
                            // Before end of extension, characters must match:
96
                            if (!charEquals(buf[offset+j], *tempPathname))
97
                            {
98
                                matchingNames = FALSE;
99
                            }
100
101
              tempPathname++;
102
                        }
103
            else if ((buf[j+offset]) != ' ')
104
            {
105
                            // After end of extension, must have blanks.
106
              matchingNames = FALSE;
107
            }
108
          }
109
110
          if (matchingNames)
111
          {
112
            targetFound = TRUE;
113
          }
114
        }
115
116
      }
117
      i++;
118
      if(i == 16)    // 16 = directory entries per sector (fixed number)
119
      {
120
        i = 0;
121
        sectorCount++;
122
        if((cluster == 1)&&(fileSys == FAT16))
123
        {
124
          if( sectorCount < rootSectors )
125
          {
126
            sector++;
127
          }
128
          else
129
          {
130
            sector = 0;
131
          }
132
        }
133
        else
134
        {
135
          if(sectorCount != sectorsPerCluster)
136
          {
137
            sector++;
138
          }
139
          else
140
          {
141
            sectorCount = 0;
142
            cluster = getNextFAT(cluster, buf);
143
            if((cluster <= 0xFFF6)&&(cluster >= 2))
144
            {
145
              sector = (cluster - 2) * sectorsPerCluster + dataStarts;                
146
            }
147
            else
148
            {
149
              sector = 0;
150
            }
151
          }
152
        }
153
        readSector(sector, buf);
154
      }    
155
    }
156
  }
157
158
  if(targetFound)
159
  {
160
    cluster = buf[26+offset];
161
    cluster |= (unsigned long int)buf[27+offset] << 8;
162
    
163
    *fileSize = buf[28+offset];
164
    *fileSize += (unsigned long int)buf[29+offset] << 8;
165
    *fileSize += (unsigned long int)buf[30+offset] << 16;
166
    *fileSize += (unsigned long int)buf[31+offset] << 24;
167
  }
168
  else
169
  {
170
    cluster = 0;
171
  }
172
  return cluster;
173
}

von Mark M. (mom-jovi)


Lesenswert?

1
/**
2
 *  creates a new entry (file or directory) at the location indicated by the
3
 *  input cluster.  The input control determines whether a file or a
4
 *  directory is created
5
 *  *****ONLY FILES AND DIRECTORY WITH SHORT FILE NAMES ARE SUPPORTED
6
 *
7
 *  @param  buf      the buffer to be used to access the MMC/SD card  
8
 *  @param  entryName  pointer to the name of the new entry
9
 *  @param  cluster    location of the current directory where the new entry will be added
10
 *  @param  control    FILE or DIRECTORY
11
 *
12
 *  @return  0      if an error occurs while adding a new entry
13
 *  @return  ...      the location of the first cluster of the new entry
14
 **/
15
static unsigned long createNewEntry(const char *entryName, unsigned long cluster, unsigned char *buf, boolean control)
16
{
17
  unsigned int offset;
18
  unsigned int sectorCount = 0;
19
  unsigned int tokenLength = 0;    
20
  unsigned long sector;
21
  unsigned long newCluster;
22
  unsigned char i;  
23
  const char *tempEntryName;  
24
  boolean done = FALSE;
25
26
    // Note:  findEmptyCluster() will mark the returned cluster in the FAT
27
    // as used.  If we fail for some other reason below, we should really
28
    // free the newCluster, but we don't right now.  Also, unless we are
29
    // creating a directory, we really shouldn't allocate a first cluster
30
    // until some data is written to the file.  Additionally, if we re-use a
31
    // deleted entry, we should re-use the cluster chain, adding clusters as
32
    // required, but we don't do that right now either.
33
  newCluster = findEmptyCluster(buf);
34
  if(newCluster == 0)
35
  {
36
    return 0;  // no more empty cluster
37
  }
38
39
  if((cluster == 1) && (fileSys == FAT16))
40
  {
41
    sector = rootDirectory;
42
  }
43
  else
44
  {
45
    sector = (cluster - 2) * sectorsPerCluster + dataStarts;    
46
  }
47
48
  tempEntryName = entryName;
49
50
  while((*tempEntryName != '.')&&(*tempEntryName)&&(*tempEntryName != 0x5C))
51
  {
52
    tokenLength++;
53
    tempEntryName++;
54
  }
55
56
  while(!done)
57
  {        
58
    readSector(sector, buf);
59
    i = 0;
60
    while(i < 16)
61
    {
62
      offset = i * 32;      
63
      if(((buf[offset] & 0xFF) == 0x00) || ( (buf[offset] & 0xFF) == 0xE5) )
64
      {
65
        done = TRUE;
66
        i = 15;
67
      }
68
      i++;
69
    }
70
    if(!done)
71
    {
72
      sectorCount++;
73
      if((cluster == 1)&&(fileSys == FAT16))
74
      {
75
        if(sectorCount < rootSectors)
76
        {
77
          sector++;
78
        }
79
        else
80
        {
81
          return 0;  // no more root directory
82
        }
83
      }
84
      else
85
      {
86
                return 0;
87
      }        
88
    }
89
  }
90
91
  if(control == FILE)
92
  {
93
    buf[offset+11] = 0x20;
94
    if(tokenLength < 9)
95
    {      
96
      for(i = 0; i < 8; i++)
97
      {
98
        if(*entryName != '.')
99
        {
100
          if((*entryName >= 'a')&&(*entryName <= 'z'))
101
          {
102
            buf[offset+i] = (*entryName - 32);
103
          }
104
          else
105
          {
106
            buf[offset+i] = *entryName ;
107
          }
108
          entryName++;
109
        }
110
        else
111
        {
112
          buf[offset+i] = 0x20;
113
        }
114
      }
115
      entryName++;
116
      for(i = 8; i < 11; i++)
117
      {
118
        if(*entryName)
119
        {
120
          if((*entryName >= 'a')&&(*entryName <= 'z'))
121
          {
122
            buf[offset+i] = (*entryName - 32);
123
          }
124
          else
125
          {
126
            buf[offset+i] = *entryName ;
127
          }
128
          entryName++;
129
        }
130
        else
131
        {
132
          buf[offset+i] = 0x20;
133
        }
134
      }            
135
    }
136
    else
137
    {
138
      // file with long file name
139
      return 0;
140
    }
141
  }
142
143
  buf[offset+12] = 0x00;
144
  buf[offset+13] = 0x00;
145
146
    // Set the date and time to January 02, 2005 21:00:00 .
147
    // If a real time clock is available, we could use it.
148
  buf[offset+14] = (04 >> 1) & 0x1F;  // Seconds.
149
  buf[offset+14] |= 03 << 5;  // Part of minutes.
150
  buf[offset+22] = buf[offset+14];
151
152
  buf[offset+15] = (03 >> 3) & 0x07;  // More of minutes.
153
  buf[offset+15] |= 21 << 3;  // Hours.
154
  buf[offset+23] = buf[offset+15];      
155
  
156
  buf[offset+16] = 02 & 0x1F;     // Day.
157
  buf[offset+16] |= (01 << 5) & 0xE0;   // Part of month.
158
  buf[offset+18] = buf[offset+16];
159
  buf[offset+24] = buf[offset+16];
160
        
161
  buf[offset+17] = (01 >> 3) & 0x01;   // More of month.
162
  buf[offset+17] |= (((2005 - 1980) & 0xFF) << 1) & 0xFE;  // Year.
163
  buf[offset+19] = buf[offset+17];
164
  buf[offset+25] = buf[offset+17];
165
166
  buf[offset+26] = (newCluster & 0xFF);
167
  buf[offset+27] = (newCluster >> 8) & 0xFF;
168
169
  for(i = 28; i < 32; i++)
170
  {
171
    buf[offset+i] = 0x00;
172
  }
173
  writeSector(sector, buf);
174
175
  return newCluster;
176
}

von Mark M. (mom-jovi)


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?

von Stefan B. (stefan) Benutzerseite


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

von Mark M. (mom-jovi)


Lesenswert?

Aber zuvor sollte ich die const entfernen, oder nicht?

von Mark M. (mom-jovi)


Lesenswert?

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

von Bjoern (Gast)


Lesenswert?

Hast Du denn alle const entfernt?

von Mark M. (mom-jovi)


Lesenswert?

Bjoern schrieb:
> Hast Du denn alle const entfernt?

Ja.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

> Das funktioniert leider nicht.

Kann ich mir nicht vorstellen.

Das Prinzip:
1
#include <string.h>
2
#include <stdio.h>
3
4
char dateiname[23];
5
6
int bar(const char *dn)  // Dateinamen benutzen #2
7
{
8
  return strlen(dn);
9
}
10
11
int foo(const char *dn)  // Dateinamen benutzen #1
12
{
13
  return bar(dn); 
14
}
15
16
int main(void)
17
{
18
  strcpy(dateiname, "dreiundzwanzig"); // Dateinamen erzeugen
19
  printf("%d\n", foo(dateiname));
20
}

Bekommst du Compilerprobleme oder Laufzeitprobleme?

von Mark M. (mom-jovi)


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:
1
char outputFile[13]={"data.txt"}; //13 Elemente, weil 8.3-Format + Terminator

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.