-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathSdFuncs.cpp
More file actions
313 lines (248 loc) · 8.95 KB
/
SdFuncs.cpp
File metadata and controls
313 lines (248 loc) · 8.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
//=============================================================================
// FILE: SdFuncs.cpp
//
// This contains some functions related to raw accesses of the SD drive. It
// does not handle anything related to the mounted drive emulation.
#include <SPI.h>
#include <SD.h>
#include "link.h"
#include "SdFuncs.h"
#include "Errors.h"
extern Link *link;
// For file operations, have a file handy. Anyone using the file should be
// darned sure it gets closed when done!
static File myFile;
//=============================================================================
// This sends a directory to the host. On entry, it is assumed there is at
// least one Event available. Ie, free it before calling this. This sends
// only file names at the top level, not directories, and it does not
// recurse.
void sendDirectory()
{
Event *eptr;
#ifdef USE_SDFAT
SdFat sd;
SdFile file;
uint32_t pos = 0;
char name[30];
#else
File dir;
#endif
bool go_on = true;
#ifdef DEBUG_DIR
Serial.println("Sending disk directory...");
#endif
// Open the root directory
#ifdef USE_SDFAT
sd.chdir("/");
#else
dir.close();
dir = SD.open("/");
dir.rewindDirectory();
if (!dir.available())
{
Serial.println("DIR not available");
}
File entry;
#endif
while (go_on)
{
#ifdef USE_SDFAT
sd.vwd()->seekSet(pos);
if (!file.openNext(sd.vwd(), O_READ))
{
go_on = false;
}
else
{
pos = sd.vwd()->curPosition();
if (file.isDir() == false)
{
file.getName(name, sizeof(name));
Serial.println(name);
byte *bptr = (byte *)name;
if (*bptr != '_') // filenames starting with underscore are deleted
{
eptr = link->getAnEvent();
eptr->clean(EVT_DIR_INFO); // this is a directory entry
while (*bptr)
{
eptr->addByte(*bptr++);
}
eptr->addByte(0); // terminate the name
link->sendEvent(eptr);
}
}
file.close();
}
}
#else
entry = dir.openNextFile();
if (!entry)
{
// no more files
go_on = false;
}
// Only process file names, not directories.
if (entry && !entry.isDirectory())
{
// Now copy the filename into the event and send it.
byte *bptr = (byte *)(entry.name());
if (*bptr != '_') // filenames starting with underscore are deleted
{
eptr = link->getAnEvent();
eptr->clean(EVT_DIR_INFO); // this is a directory entry
#ifdef DEBUG_DIR
Serial.print(" ");
Serial.println(entry.name());
#endif
while (*bptr)
{
eptr->addByte(*bptr++);
}
eptr->addByte(0); // terminate the name
link->sendEvent(eptr);
}
}
entry.close();
}
dir.close();
#endif
// Send an event letting the host know the directory is done
eptr->clean(EVT_DIR_END);
link->sendEvent(eptr);
}
//=============================================================================
// Given an event with a EVT_TYPE_FILE type, verify the file can be read and
// send back either an ACK or NAK.
void openFileForRead(Event *ep)
{
if (myFile)
{
#ifdef DEBUG_FILE_READ
Serial.println("typeFile found open file... closing");
#endif
myFile.close(); // make sure an existing file is closed
}
// Attempt to open the file
myFile = SD.open((char *)(ep->getData()));
if (myFile)
{
ep->clean(EVT_ACK); // woohoo!
myFile.seek(0);
}
else
{
Serial.print("typeFile: error opening ");
Serial.println((char *)(ep->getData()));
ep->clean(EVT_NAK);
ep->addByte(ERR_FILE_NOT_FOUND); // misc error
}
link->sendEvent(ep);
}
//=============================================================================
// This sends the next block of the open file.
void nextDataBlock(Event *ep)
{
// They sent the maximum length they can handle.
byte length = *(ep->getData()); // get maximum length
#ifdef DEBUG_FILE_READ
Serial.print("Byte count: ");
Serial.println(length);
#endif
ep->clean(EVT_FILE_DATA);
// We're going to cheat a bit here. Add a length of 0.
// Once we have written the data and know the length,
// go back and put the actual length into the buffer.
ep->addByte(0); // length is first
byte actualCount = 0;
while (myFile.available() && actualCount < length)
{
ep->addByte(myFile.read());
actualCount++;
}
// Now go back and put in the actual length
byte *bptr = ep->getData(); // get start of buffer
*bptr = actualCount; // and drop in the actual length
// If end of file, close the file
if (actualCount == 0)
{
#ifdef DEBUG_FILE_READ
Serial.println("Reached EOF, closing file");
#endif
myFile.close();
}
#ifdef DEBUG_FILE_READ
Serial.print("Actual bytes sent: ");
Serial.println(actualCount);
#endif
link->sendEvent(ep);
}
//=============================================================================
// This opens a file for writing. Pass in the event with the filename. This
// closes any open file, then opens the new one.
void openFileForWrite(Event *ep)
{
// If there is an open file, close it.
if (myFile)
myFile.close();
byte *ptr = ep->getData();
#ifdef DEBUG_FILE_WRITE
Serial.print("Got request to open a file for writing: \"");
Serial.print((char *)ptr);
Serial.print("\"");
#endif
SD.remove((char *)(ep->getData())); // remove existing file
myFile = SD.open((char *)(ep->getData()), FILE_WRITE);
if (myFile)
{
#ifdef DEBUG_FILE_WRITE
Serial.println(" - success");
#endif
ep->clean(EVT_ACK);
}
else
{
#ifdef DEBUG_FILE_WRITE
Serial.println(" - FAILURE");
#endif
ep->clean(EVT_NAK);
ep->addByte(ERR_WRITE_ERROR);
}
link->sendEvent(ep);
}
//=============================================================================
// Given an event with bytes to write to an open disk file, do the writes.
void writeBytes(Event *ep)
{
// The first byte is the length. If zero then the length is actually 256,
// else the length is the actual length.
byte *ptr = ep->getData();
unsigned length = *ptr++;
if (length == 0)
length = 256;
#ifdef DEBUG_FILE_WRITE
Serial.print("Writing ");
Serial.print(length);
Serial.println(" bytes to the raw file");
#endif
// Now write the block of data
if (myFile.write(ptr, length) == length)
{
ep->clean(EVT_ACK); // send back an ACK.
}
else
{
Serial.println("Got a NAK!");
ep->clean(EVT_NAK);
ep->addByte(ERR_WRITE_ERROR);
}
myFile.flush();
link->sendEvent(ep);
}
//=============================================================================
// Make sure files are closed.
void closeFiles(void)
{
myFile.close(); // be sure it's closed
}