Subversion Repositories svn.mios32

Rev

Rev 2617 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2617 Rev 2621
1
// $Id: file.c 2617 2018-12-20 00:02:42Z tk $
1
// $Id: file.c 2621 2018-12-20 15:53:13Z tk $
2
//! \defgroup FILE
2
//! \defgroup FILE
3
//!
3
//!
4
//! File access layer for FatFS
4
//! File access layer for FatFS
5
//!
5
//!
6
//! Frontend functions to read/write files.\n
6
//! Frontend functions to read/write files.\n
7
//! Optimized for Memory Size and Speed!
7
//! Optimized for Memory Size and Speed!
8
//!
8
//!
9
//! For the whole application only single file handlers for read and write
9
//! For the whole application only single file handlers for read and write
10
//! operations are available. They are shared globally to save memory (because
10
//! operations are available. They are shared globally to save memory (because
11
//! each FatFs handler allocates more than 512 bytes to store the last read
11
//! each FatFs handler allocates more than 512 bytes to store the last read
12
//! sector)
12
//! sector)
13
//!
13
//!
14
//! For read operations it is possible to re-open a file via a file_t reference
14
//! For read operations it is possible to re-open a file via a file_t reference
15
//! so that no directory access is required to find the first sector of the
15
//! so that no directory access is required to find the first sector of the
16
//! file (again).
16
//! file (again).
17
//!
17
//!
18
//! NOTE: before accessing the SD Card, the upper level function should
18
//! NOTE: before accessing the SD Card, the upper level function should
19
//! synchronize with a SD Card semaphore!
19
//! synchronize with a SD Card semaphore!
20
//! E.g. (defined in tasks.h in various projects):
20
//! E.g. (defined in tasks.h in various projects):
21
//!   MUTEX_SDCARD_TAKE; // to take the semaphore
21
//!   MUTEX_SDCARD_TAKE; // to take the semaphore
22
//!   MUTEX_SDCARD_GIVE; // to release the semaphore
22
//!   MUTEX_SDCARD_GIVE; // to release the semaphore
23
//!
23
//!
24
//! \{
24
//! \{
25
/* ==========================================================================
25
/* ==========================================================================
26
 *
26
 *
27
 *  Copyright (C) 2008 Thorsten Klose (tk@midibox.org)
27
 *  Copyright (C) 2008 Thorsten Klose (tk@midibox.org)
28
 *  Licensed for personal non-commercial use only.
28
 *  Licensed for personal non-commercial use only.
29
 *  All other rights reserved.
29
 *  All other rights reserved.
30
 *
30
 *
31
 * ==========================================================================
31
 * ==========================================================================
32
 */
32
 */
33
33
34
/////////////////////////////////////////////////////////////////////////////
34
/////////////////////////////////////////////////////////////////////////////
35
// Include files
35
// Include files
36
/////////////////////////////////////////////////////////////////////////////
36
/////////////////////////////////////////////////////////////////////////////
37
37
38
#include <mios32.h>
38
#include <mios32.h>
39
39
40
#include <ff.h>
40
#include <ff.h>
41
#include <diskio.h>
41
#include <diskio.h>
42
#include <string.h>
42
#include <string.h>
43
#include <ctype.h>
43
#include <ctype.h>
44
44
45
#include "file.h"
45
#include "file.h"
46
46
47
#ifndef MIOS32_FAMILY_EMULATION
47
#ifndef MIOS32_FAMILY_EMULATION
48
# include <FreeRTOS.h>
48
# include <FreeRTOS.h>
49
# include <portmacro.h>
49
# include <portmacro.h>
50
# include <task.h>
50
# include <task.h>
51
#endif
51
#endif
52
52
53
53
54
/////////////////////////////////////////////////////////////////////////////
54
/////////////////////////////////////////////////////////////////////////////
55
// for optional debugging messages via DEBUG_MSG (defined in mios32_config.h)
55
// for optional debugging messages via DEBUG_MSG (defined in mios32_config.h)
56
/////////////////////////////////////////////////////////////////////////////
56
/////////////////////////////////////////////////////////////////////////////
57
57
58
// Note: verbose level 1 is default - it prints error messages
58
// Note: verbose level 1 is default - it prints error messages
59
// and useful info messages during backups
59
// and useful info messages during backups
60
#define DEBUG_VERBOSE_LEVEL 1
60
#define DEBUG_VERBOSE_LEVEL 1
61
61
62
#ifndef DEBUG_MSG
62
#ifndef DEBUG_MSG
63
#define DEBUG_MSG MIOS32_MIDI_SendDebugMessage
63
#define DEBUG_MSG MIOS32_MIDI_SendDebugMessage
64
#endif
64
#endif
65
65
66
66
67
/////////////////////////////////////////////////////////////////////////////
67
/////////////////////////////////////////////////////////////////////////////
68
// Global variables
68
// Global variables
69
/////////////////////////////////////////////////////////////////////////////
69
/////////////////////////////////////////////////////////////////////////////
70
70
71
// last error status returned by DFS
71
// last error status returned by DFS
72
// can be used as additional debugging help if FILE_*ERR returned by function
72
// can be used as additional debugging help if FILE_*ERR returned by function
73
u32 file_dfs_errno;
73
u32 file_dfs_errno;
74
74
75
// for percentage display during copy operations
75
// for percentage display during copy operations
76
u8 file_copy_percentage;
76
u8 file_copy_percentage;
77
77
78
78
79
/////////////////////////////////////////////////////////////////////////////
79
/////////////////////////////////////////////////////////////////////////////
80
// Local types
80
// Local types
81
/////////////////////////////////////////////////////////////////////////////
81
/////////////////////////////////////////////////////////////////////////////
82
82
83
// from https://www.gnu.org/software/tar/manual/html_node/Standard.html
83
// from https://www.gnu.org/software/tar/manual/html_node/Standard.html
84
typedef struct
84
typedef struct
85
{                              /* byte offset */
85
{                              /* byte offset */
86
  char name[100];               /*   0 */
86
  char name[100];               /*   0 */
87
  char mode[8];                 /* 100 */
87
  char mode[8];                 /* 100 */
88
  char uid[8];                  /* 108 */
88
  char uid[8];                  /* 108 */
89
  char gid[8];                  /* 116 */
89
  char gid[8];                  /* 116 */
90
  char size[12];                /* 124 */
90
  char size[12];                /* 124 */
91
  char mtime[12];               /* 136 */
91
  char mtime[12];               /* 136 */
92
  char chksum[8];               /* 148 */
92
  char chksum[8];               /* 148 */
93
  char typeflag;                /* 156 */
93
  char typeflag;                /* 156 */
94
  char linkname[100];           /* 157 */
94
  char linkname[100];           /* 157 */
95
  char magic[6];                /* 257 */
95
  char magic[6];                /* 257 */
96
  char version[2];              /* 263 */
96
  char version[2];              /* 263 */
97
  char uname[32];               /* 265 */
97
  char uname[32];               /* 265 */
98
  char gname[32];               /* 297 */
98
  char gname[32];               /* 297 */
99
  char devmajor[8];             /* 329 */
99
  char devmajor[8];             /* 329 */
100
  char devminor[8];             /* 337 */
100
  char devminor[8];             /* 337 */
101
  char prefix[155];             /* 345 */
101
  char prefix[155];             /* 345 */
102
  char fill_to_512[12];         /* 500 */
102
  char fill_to_512[12];         /* 500 */
103
                                /* 512 */
103
                                /* 512 */
104
} tar_posix_header;
104
} tar_posix_header;
105
105
106
106
107
/////////////////////////////////////////////////////////////////////////////
107
/////////////////////////////////////////////////////////////////////////////
108
// Local prototypes
108
// Local prototypes
109
/////////////////////////////////////////////////////////////////////////////
109
/////////////////////////////////////////////////////////////////////////////
110
110
111
static s32 FILE_MountFS(void);
111
static s32 FILE_MountFS(void);
112
112
113
static s32 FILE_CreateTarRecursive(char *filename, char *src_path, u8 exclude_tar_files, u8 depth, u8 max_depth, u32 *num_dirs, u32 *num_files);
113
static s32 FILE_CreateTarRecursive(char *filename, char *src_path, u8 exclude_tar_files, u8 depth, u8 max_depth, u32 *num_dirs, u32 *num_files);
114
static s32 FILE_CreateTarHeader(char *filename, char *src_path, u8 is_dir, u32 filesize);
114
static s32 FILE_CreateTarHeader(char *filename, char *src_path, u8 is_dir, u32 filesize);
115
115
116
116
117
/////////////////////////////////////////////////////////////////////////////
117
/////////////////////////////////////////////////////////////////////////////
118
// Local variables
118
// Local variables
119
/////////////////////////////////////////////////////////////////////////////
119
/////////////////////////////////////////////////////////////////////////////
120
120
121
// FatFs variables
121
// FatFs variables
122
#define SECTOR_SIZE _MAX_SS
122
#define SECTOR_SIZE _MAX_SS
123
123
124
// Work area (file system object) for logical drives
124
// Work area (file system object) for logical drives
125
static FATFS fs;
125
static FATFS fs;
126
126
127
// disk label
127
// disk label
128
static char disk_label[12];
128
static char disk_label[12];
129
129
130
// complete file structure for read/write accesses
130
// complete file structure for read/write accesses
131
static FIL file_read;
131
static FIL file_read;
132
static u8 file_read_is_open; // only for safety purposes
132
static u8 file_read_is_open; // only for safety purposes
133
static FIL file_write;
133
static FIL file_write;
134
static u8 file_write_is_open; // only for safety purposes
134
static u8 file_write_is_open; // only for safety purposes
135
135
136
// SD Card status
136
// SD Card status
137
static u8 sdcard_available;
137
static u8 sdcard_available;
138
static u8 volume_available;
138
static u8 volume_available;
139
static u32 volume_free_bytes;
139
static u32 volume_free_bytes;
140
140
141
static u8 status_msg_ctr;
141
static u8 status_msg_ctr;
142
142
143
// buffer for copy operations and SysEx sender
143
// buffer for copy operations and SysEx sender
144
#define TMP_BUFFER_SIZE _MAX_SS
144
#define TMP_BUFFER_SIZE _MAX_SS
145
static u8 tmp_buffer[TMP_BUFFER_SIZE];
145
static u8 tmp_buffer[TMP_BUFFER_SIZE];
146
146
147
// for FILE_BrowserHandler
147
// for FILE_BrowserHandler
148
static u32 browser_write_file_size;
148
static u32 browser_write_file_size;
149
static u32 browser_write_file_pos;
149
static u32 browser_write_file_pos;
150
150
151
static s32 (*browser_upload_callback_func)(char *filename);
151
static s32 (*browser_upload_callback_func)(char *filename);
152
152
153
153
154
/////////////////////////////////////////////////////////////////////////////
154
/////////////////////////////////////////////////////////////////////////////
155
//! Initialisation
155
//! Initialisation
156
/////////////////////////////////////////////////////////////////////////////
156
/////////////////////////////////////////////////////////////////////////////
157
s32 FILE_Init(u32 mode)
157
s32 FILE_Init(u32 mode)
158
{
158
{
159
  file_read_is_open = 0;
159
  file_read_is_open = 0;
160
  file_write_is_open = 0;
160
  file_write_is_open = 0;
161
  sdcard_available = 0;
161
  sdcard_available = 0;
162
  volume_available = 0;
162
  volume_available = 0;
163
  volume_free_bytes = 0;
163
  volume_free_bytes = 0;
164
164
165
  browser_upload_callback_func = NULL;
165
  browser_upload_callback_func = NULL;
166
166
167
  // init SDCard access
167
  // init SDCard access
168
  s32 error = MIOS32_SDCARD_Init(0);
168
  s32 error = MIOS32_SDCARD_Init(0);
169
#if DEBUG_VERBOSE_LEVEL >= 2
169
#if DEBUG_VERBOSE_LEVEL >= 2
170
  DEBUG_MSG("[FILE] SD Card interface initialized, status: %d\n", error);
170
  DEBUG_MSG("[FILE] SD Card interface initialized, status: %d\n", error);
171
#endif
171
#endif
172
172
173
  // for status message
173
  // for status message
174
  status_msg_ctr = 5;
174
  status_msg_ctr = 5;
175
175
176
  return error;
176
  return error;
177
}
177
}
178
178
179
179
180
/////////////////////////////////////////////////////////////////////////////
180
/////////////////////////////////////////////////////////////////////////////
181
//! This function should be called periodically to check the availability
181
//! This function should be called periodically to check the availability
182
//! of the SD Card
182
//! of the SD Card
183
//! \return < 0 on errors (error codes are documented in file.h)
183
//! \return < 0 on errors (error codes are documented in file.h)
184
//! \return 1 if SD card has been connected
184
//! \return 1 if SD card has been connected
185
//! \return 2 if SD card has been disconnected
185
//! \return 2 if SD card has been disconnected
186
//! \return 3 if new files should be loaded, e.g. after startup or SD Card change
186
//! \return 3 if new files should be loaded, e.g. after startup or SD Card change
187
/////////////////////////////////////////////////////////////////////////////
187
/////////////////////////////////////////////////////////////////////////////
188
s32 FILE_CheckSDCard(void)
188
s32 FILE_CheckSDCard(void)
189
{
189
{
190
  // check if SD card is available
190
  // check if SD card is available
191
  // High-speed access if SD card was previously available
191
  // High-speed access if SD card was previously available
192
  u8 prev_sdcard_available = sdcard_available;
192
  u8 prev_sdcard_available = sdcard_available;
193
  sdcard_available = MIOS32_SDCARD_CheckAvailable(prev_sdcard_available);
193
  sdcard_available = MIOS32_SDCARD_CheckAvailable(prev_sdcard_available);
194
194
195
  if( sdcard_available && !prev_sdcard_available ) {
195
  if( sdcard_available && !prev_sdcard_available ) {
196
#if DEBUG_VERBOSE_LEVEL >= 2
196
#if DEBUG_VERBOSE_LEVEL >= 2
197
    DEBUG_MSG("[FILE] SD Card has been connected!\n");
197
    DEBUG_MSG("[FILE] SD Card has been connected!\n");
198
#endif
198
#endif
199
199
200
    s32 error = FILE_MountFS();
200
    s32 error = FILE_MountFS();
201
#if DEBUG_VERBOSE_LEVEL >= 2
201
#if DEBUG_VERBOSE_LEVEL >= 2
202
    DEBUG_MSG("[FILE] Tried to mount file system, status: %d\n", error);
202
    DEBUG_MSG("[FILE] Tried to mount file system, status: %d\n", error);
203
#endif
203
#endif
204
204
205
    if( error < 0 ) {
205
    if( error < 0 ) {
206
      // ensure that volume flagged as not available
206
      // ensure that volume flagged as not available
207
      volume_available = 0;
207
      volume_available = 0;
208
208
209
      return error; // break here!
209
      return error; // break here!
210
    }
210
    }
211
211
212
    // status message after 3 seconds
212
    // status message after 3 seconds
213
    status_msg_ctr = 3;
213
    status_msg_ctr = 3;
214
214
215
    return 1; // SD card has been connected
215
    return 1; // SD card has been connected
216
216
217
  } else if( !sdcard_available && prev_sdcard_available ) {
217
  } else if( !sdcard_available && prev_sdcard_available ) {
218
#if DEBUG_VERBOSE_LEVEL >= 2
218
#if DEBUG_VERBOSE_LEVEL >= 2
219
    DEBUG_MSG("[FILE] SD Card disconnected!\n");
219
    DEBUG_MSG("[FILE] SD Card disconnected!\n");
220
#endif
220
#endif
221
    volume_available = 0;
221
    volume_available = 0;
222
222
223
    return 2; // SD card has been disconnected
223
    return 2; // SD card has been disconnected
224
  }
224
  }
225
225
226
  if( status_msg_ctr ) {
226
  if( status_msg_ctr ) {
227
    if( !--status_msg_ctr )
227
    if( !--status_msg_ctr )
228
      return 3;
228
      return 3;
229
  }
229
  }
230
230
231
  return 0; // no error
231
  return 0; // no error
232
}
232
}
233
233
234
234
235
/////////////////////////////////////////////////////////////////////////////
235
/////////////////////////////////////////////////////////////////////////////
236
//! Mount the file system
236
//! Mount the file system
237
//! \return < 0 on errors (error codes are documented in file.h)
237
//! \return < 0 on errors (error codes are documented in file.h)
238
/////////////////////////////////////////////////////////////////////////////
238
/////////////////////////////////////////////////////////////////////////////
239
static s32 FILE_MountFS(void)
239
static s32 FILE_MountFS(void)
240
{
240
{
241
  FRESULT res;
241
  FRESULT res;
242
  DIR dir;
242
  DIR dir;
243
243
244
  file_read_is_open = 0;
244
  file_read_is_open = 0;
245
  file_write_is_open = 0;
245
  file_write_is_open = 0;
246
246
247
  if( (res=f_mount(0, &fs)) != FR_OK ) {
247
  if( (res=f_mount(0, &fs)) != FR_OK ) {
248
    DEBUG_MSG("[FILE] Failed to mount SD Card - error status: %d\n", res);
248
    DEBUG_MSG("[FILE] Failed to mount SD Card - error status: %d\n", res);
249
    return -1; // error
249
    return -1; // error
250
  }
250
  }
251
251
252
  if( (res=f_opendir(&dir, "/")) != FR_OK ) {
252
  if( (res=f_opendir(&dir, "/")) != FR_OK ) {
253
    DEBUG_MSG("[FILE] Failed to open root directory - error status: %d\n", res);
253
    DEBUG_MSG("[FILE] Failed to open root directory - error status: %d\n", res);
254
    return -2; // error
254
    return -2; // error
255
  }
255
  }
256
256
257
  // TODO: read from master sector
257
  // TODO: read from master sector
258
  disk_label[0] = 0;
258
  disk_label[0] = 0;
259
259
260
  volume_available = 1;
260
  volume_available = 1;
261
261
262
  return 0; // no error
262
  return 0; // no error
263
}
263
}
264
264
265
265
266
/////////////////////////////////////////////////////////////////////////////
266
/////////////////////////////////////////////////////////////////////////////
267
//! This function updates the number of free bytes by scanning the FAT for
267
//! This function updates the number of free bytes by scanning the FAT for
268
//! unused clusters.\n
268
//! unused clusters.\n
269
//! should be called before FILE_Volume* bytes are read
269
//! should be called before FILE_Volume* bytes are read
270
/////////////////////////////////////////////////////////////////////////////
270
/////////////////////////////////////////////////////////////////////////////
271
s32 FILE_UpdateFreeBytes(void)
271
s32 FILE_UpdateFreeBytes(void)
272
{
272
{
273
  FRESULT res;
273
  FRESULT res;
274
  DIR dir;
274
  DIR dir;
275
  DWORD free_clust;
275
  DWORD free_clust;
276
276
277
  if( (res=f_opendir(&dir, "/")) != FR_OK ) {
277
  if( (res=f_opendir(&dir, "/")) != FR_OK ) {
278
    DEBUG_MSG("[FILE_UpdateFreeBytes] f_opendir failed with status %d!\n", res);
278
    DEBUG_MSG("[FILE_UpdateFreeBytes] f_opendir failed with status %d!\n", res);
279
    return FILE_ERR_UPDATE_FREE;
279
    return FILE_ERR_UPDATE_FREE;
280
  }
280
  }
281
281
282
  if( (res=f_getfree("/", &free_clust, &dir.fs)) != FR_OK ) {
282
  if( (res=f_getfree("/", &free_clust, &dir.fs)) != FR_OK ) {
283
#if DEBUG_VERBOSE_LEVEL >= 1
283
#if DEBUG_VERBOSE_LEVEL >= 1
284
    DEBUG_MSG("[FILE_UpdateFreeBytes] f_getfree failed with status %d!\n", res);
284
    DEBUG_MSG("[FILE_UpdateFreeBytes] f_getfree failed with status %d!\n", res);
285
#endif
285
#endif
286
    return FILE_ERR_UPDATE_FREE;
286
    return FILE_ERR_UPDATE_FREE;
287
  }
287
  }
288
288
289
  volume_free_bytes = free_clust * fs.csize * 512;
289
  volume_free_bytes = free_clust * fs.csize * 512;
290
290
291
  return 0; // no error
291
  return 0; // no error
292
}
292
}
293
293
294
294
295
/////////////////////////////////////////////////////////////////////////////
295
/////////////////////////////////////////////////////////////////////////////
296
//! \return number of sectors per cluster
296
//! \return number of sectors per cluster
297
/////////////////////////////////////////////////////////////////////////////
297
/////////////////////////////////////////////////////////////////////////////
298
u32 FILE_VolumeSectorsPerCluster(void)
298
u32 FILE_VolumeSectorsPerCluster(void)
299
{
299
{
300
  return fs.csize;
300
  return fs.csize;
301
}
301
}
302
302
303
303
304
/////////////////////////////////////////////////////////////////////////////
304
/////////////////////////////////////////////////////////////////////////////
305
//! \return the physical sector of the given cluster
305
//! \return the physical sector of the given cluster
306
/////////////////////////////////////////////////////////////////////////////
306
/////////////////////////////////////////////////////////////////////////////
307
u32 FILE_VolumeCluster2Sector(u32 cluster)
307
u32 FILE_VolumeCluster2Sector(u32 cluster)
308
{
308
{
309
  // from ff.c
309
  // from ff.c
310
  cluster -= 2;
310
  cluster -= 2;
311
  if( cluster >= (fs.max_clust - 2) )
311
  if( cluster >= (fs.max_clust - 2) )
312
    return 0;              /* Invalid cluster# */
312
    return 0;              /* Invalid cluster# */
313
313
314
  return cluster * fs.csize + fs.database;
314
  return cluster * fs.csize + fs.database;
315
}
315
}
316
316
317
317
318
/////////////////////////////////////////////////////////////////////////////
318
/////////////////////////////////////////////////////////////////////////////
319
//! \return 1 if SD card available
319
//! \return 1 if SD card available
320
/////////////////////////////////////////////////////////////////////////////
320
/////////////////////////////////////////////////////////////////////////////
321
s32 FILE_SDCardAvailable(void)
321
s32 FILE_SDCardAvailable(void)
322
{
322
{
323
  return sdcard_available;
323
  return sdcard_available;
324
}
324
}
325
325
326
326
327
/////////////////////////////////////////////////////////////////////////////
327
/////////////////////////////////////////////////////////////////////////////
328
//! \return 1 if volume available
328
//! \return 1 if volume available
329
/////////////////////////////////////////////////////////////////////////////
329
/////////////////////////////////////////////////////////////////////////////
330
s32 FILE_VolumeAvailable(void)
330
s32 FILE_VolumeAvailable(void)
331
{
331
{
332
  return volume_available;
332
  return volume_available;
333
}
333
}
334
334
335
335
336
/////////////////////////////////////////////////////////////////////////////
336
/////////////////////////////////////////////////////////////////////////////
337
//! \return number of available bytes
337
//! \return number of available bytes
338
/////////////////////////////////////////////////////////////////////////////
338
/////////////////////////////////////////////////////////////////////////////
339
u32 FILE_VolumeBytesFree(void)
339
u32 FILE_VolumeBytesFree(void)
340
{
340
{
341
  return volume_free_bytes;
341
  return volume_free_bytes;
342
}
342
}
343
343
344
344
345
/////////////////////////////////////////////////////////////////////////////
345
/////////////////////////////////////////////////////////////////////////////
346
//! \return total number of available bytes
346
//! \return total number of available bytes
347
/////////////////////////////////////////////////////////////////////////////
347
/////////////////////////////////////////////////////////////////////////////
348
u32 FILE_VolumeBytesTotal(void)
348
u32 FILE_VolumeBytesTotal(void)
349
{
349
{
350
  return (fs.max_clust-2)*fs.csize * 512;
350
  return (fs.max_clust-2)*fs.csize * 512;
351
}
351
}
352
352
353
353
354
/////////////////////////////////////////////////////////////////////////////
354
/////////////////////////////////////////////////////////////////////////////
355
//! \return volume label
355
//! \return volume label
356
/////////////////////////////////////////////////////////////////////////////
356
/////////////////////////////////////////////////////////////////////////////
357
char *FILE_VolumeLabel(void)
357
char *FILE_VolumeLabel(void)
358
{
358
{
359
  return disk_label;
359
  return disk_label;
360
}
360
}
361
361
362
362
363
/////////////////////////////////////////////////////////////////////////////
363
/////////////////////////////////////////////////////////////////////////////
364
//! opens a file for reading
364
//! opens a file for reading
365
//! Note: to save memory, one a single file is allowed to be opened per
365
//! Note: to save memory, one a single file is allowed to be opened per
366
//! time - always use FILE_ReadClose() before opening a new file!
366
//! time - always use FILE_ReadClose() before opening a new file!
367
//! Use FILE_ReadReOpen() to continue reading
367
//! Use FILE_ReadReOpen() to continue reading
368
//! \return < 0 on errors (error codes are documented in file.h)
368
//! \return < 0 on errors (error codes are documented in file.h)
369
/////////////////////////////////////////////////////////////////////////////
369
/////////////////////////////////////////////////////////////////////////////
370
s32 FILE_ReadOpen(file_t* file, char *filepath)
370
s32 FILE_ReadOpen(file_t* file, char *filepath)
371
{
371
{
372
#if DEBUG_VERBOSE_LEVEL >= 2
372
#if DEBUG_VERBOSE_LEVEL >= 2
373
  DEBUG_MSG("[FILE] Opening file '%s'\n", filepath);
373
  DEBUG_MSG("[FILE] Opening file '%s'\n", filepath);
374
#endif
374
#endif
375
375
376
  if( file_read_is_open ) {
376
  if( file_read_is_open ) {
377
#if DEBUG_VERBOSE_LEVEL >= 1
377
#if DEBUG_VERBOSE_LEVEL >= 1
378
    DEBUG_MSG("[FILE] FAILURE: tried to open file '%s' for reading, but previous file hasn't been closed!\n", filepath);
378
    DEBUG_MSG("[FILE] FAILURE: tried to open file '%s' for reading, but previous file hasn't been closed!\n", filepath);
379
#endif
379
#endif
380
    return FILE_ERR_OPEN_READ_WITHOUT_CLOSE;
380
    return FILE_ERR_OPEN_READ_WITHOUT_CLOSE;
381
  }
381
  }
382
382
383
  if( (file_dfs_errno=f_open(&file_read, filepath, FA_OPEN_EXISTING | FA_READ)) != FR_OK ) {
383
  if( (file_dfs_errno=f_open(&file_read, filepath, FA_OPEN_EXISTING | FA_READ)) != FR_OK ) {
384
#if DEBUG_VERBOSE_LEVEL >= 2
384
#if DEBUG_VERBOSE_LEVEL >= 2
385
    DEBUG_MSG("[FILE] Error opening file - try mounting the partition again\n");
385
    DEBUG_MSG("[FILE] Error opening file - try mounting the partition again\n");
386
#endif
386
#endif
387
387
388
    s32 error;
388
    s32 error;
389
    if( (error = FILE_MountFS()) < 0 ) {
389
    if( (error = FILE_MountFS()) < 0 ) {
390
#if DEBUG_VERBOSE_LEVEL >= 2
390
#if DEBUG_VERBOSE_LEVEL >= 2
391
      DEBUG_MSG("[FILE] mounting failed with status: %d\n", error);
391
      DEBUG_MSG("[FILE] mounting failed with status: %d\n", error);
392
#endif
392
#endif
393
      return FILE_ERR_SD_CARD;
393
      return FILE_ERR_SD_CARD;
394
    }
394
    }
395
395
396
    if( (file_dfs_errno=f_open(&file_read, filepath, FA_OPEN_EXISTING | FA_READ)) != FR_OK ) {
396
    if( (file_dfs_errno=f_open(&file_read, filepath, FA_OPEN_EXISTING | FA_READ)) != FR_OK ) {
397
#if DEBUG_VERBOSE_LEVEL >= 2
397
#if DEBUG_VERBOSE_LEVEL >= 2
398
      DEBUG_MSG("[FILE] Still not able to open file - giving up!\n");
398
      DEBUG_MSG("[FILE] Still not able to open file - giving up!\n");
399
#endif
399
#endif
400
      return FILE_ERR_OPEN_READ;
400
      return FILE_ERR_OPEN_READ;
401
    }
401
    }
402
  }
402
  }
403
403
404
#if DEBUG_VERBOSE_LEVEL >= 2
404
#if DEBUG_VERBOSE_LEVEL >= 2
405
  DEBUG_MSG("[FILE] found '%s' of length %u\n", filepath, file_read.fsize);
405
  DEBUG_MSG("[FILE] found '%s' of length %u\n", filepath, file_read.fsize);
406
#endif
406
#endif
407
407
408
  // store current file variables in file_t
408
  // store current file variables in file_t
409
  file->flag = file_read.flag;
409
  file->flag = file_read.flag;
410
  file->csect = file_read.csect;
410
  file->csect = file_read.csect;
411
  file->fptr = file_read.fptr;
411
  file->fptr = file_read.fptr;
412
  file->fsize = file_read.fsize;
412
  file->fsize = file_read.fsize;
413
  file->org_clust = file_read.org_clust;
413
  file->org_clust = file_read.org_clust;
414
  file->curr_clust = file_read.curr_clust;
414
  file->curr_clust = file_read.curr_clust;
415
  file->dsect = file_read.dsect;
415
  file->dsect = file_read.dsect;
416
  file->dir_sect = file_read.dir_sect;
416
  file->dir_sect = file_read.dir_sect;
417
  file->dir_ptr = file_read.dir_ptr;
417
  file->dir_ptr = file_read.dir_ptr;
418
418
419
  // file is opened
419
  // file is opened
420
  file_read_is_open = 1;
420
  file_read_is_open = 1;
421
421
422
  return 0;
422
  return 0;
423
}
423
}
424
424
425
425
426
/////////////////////////////////////////////////////////////////////////////
426
/////////////////////////////////////////////////////////////////////////////
427
//! reopens a file for reading
427
//! reopens a file for reading
428
//! \return < 0 on errors (error codes are documented in file.h)
428
//! \return < 0 on errors (error codes are documented in file.h)
429
/////////////////////////////////////////////////////////////////////////////
429
/////////////////////////////////////////////////////////////////////////////
430
s32 FILE_ReadReOpen(file_t* file)
430
s32 FILE_ReadReOpen(file_t* file)
431
{
431
{
432
#if DEBUG_VERBOSE_LEVEL >= 2
432
#if DEBUG_VERBOSE_LEVEL >= 2
433
  DEBUG_MSG("[FILE] Reopening file\n");
433
  DEBUG_MSG("[FILE] Reopening file\n");
434
#endif
434
#endif
435
435
436
  if( file_read_is_open ) {
436
  if( file_read_is_open ) {
437
#if DEBUG_VERBOSE_LEVEL >= 1
437
#if DEBUG_VERBOSE_LEVEL >= 1
438
    DEBUG_MSG("[FILE] FAILURE: tried to reopen file, but previous file hasn't been closed!\n");
438
    DEBUG_MSG("[FILE] FAILURE: tried to reopen file, but previous file hasn't been closed!\n");
439
#endif
439
#endif
440
    return FILE_ERR_OPEN_READ_WITHOUT_CLOSE;
440
    return FILE_ERR_OPEN_READ_WITHOUT_CLOSE;
441
  }
441
  }
442
442
443
  // for later check if we need to reload the sector
443
  // for later check if we need to reload the sector
444
  u32 prev_dsect = file_read.dsect;
444
  u32 prev_dsect = file_read.dsect;
445
445
446
  // restore file variables from file_t
446
  // restore file variables from file_t
447
  file_read.fs = &fs;
447
  file_read.fs = &fs;
448
  file_read.id = fs.id;
448
  file_read.id = fs.id;
449
  file_read.flag = file->flag;
449
  file_read.flag = file->flag;
450
  file_read.csect = file->csect;
450
  file_read.csect = file->csect;
451
  file_read.fptr = file->fptr;
451
  file_read.fptr = file->fptr;
452
  file_read.fsize = file->fsize;
452
  file_read.fsize = file->fsize;
453
  file_read.org_clust = file->org_clust;
453
  file_read.org_clust = file->org_clust;
454
  file_read.curr_clust = file->curr_clust;
454
  file_read.curr_clust = file->curr_clust;
455
  file_read.dsect = file->dsect;
455
  file_read.dsect = file->dsect;
456
  file_read.dir_sect = file->dir_sect;
456
  file_read.dir_sect = file->dir_sect;
457
  file_read.dir_ptr = file->dir_ptr;
457
  file_read.dir_ptr = file->dir_ptr;
458
458
459
  if( prev_dsect != file_read.dsect ) {
459
  if( prev_dsect != file_read.dsect ) {
460
    disk_read(file_read.fs->drive, file_read.buf, file_read.dsect, 1);
460
    disk_read(file_read.fs->drive, file_read.buf, file_read.dsect, 1);
461
  }
461
  }
462
462
463
  // file is opened (again)
463
  // file is opened (again)
464
  file_read_is_open = 1;
464
  file_read_is_open = 1;
465
465
466
  return 0;
466
  return 0;
467
}
467
}
468
468
469
469
470
/////////////////////////////////////////////////////////////////////////////
470
/////////////////////////////////////////////////////////////////////////////
471
//! Closes a file which has been read
471
//! Closes a file which has been read
472
//! File can be re-opened if required thereafter w/o performance issues
472
//! File can be re-opened if required thereafter w/o performance issues
473
//! \return < 0 on errors (error codes are documented in file.h)
473
//! \return < 0 on errors (error codes are documented in file.h)
474
/////////////////////////////////////////////////////////////////////////////
474
/////////////////////////////////////////////////////////////////////////////
475
s32 FILE_ReadClose(file_t *file)
475
s32 FILE_ReadClose(file_t *file)
476
{
476
{
477
  // store current file variables in file_t
477
  // store current file variables in file_t
478
  file->flag = file_read.flag;
478
  file->flag = file_read.flag;
479
  file->csect = file_read.csect;
479
  file->csect = file_read.csect;
480
  file->fptr = file_read.fptr;
480
  file->fptr = file_read.fptr;
481
  file->fsize = file_read.fsize;
481
  file->fsize = file_read.fsize;
482
  file->org_clust = file_read.org_clust;
482
  file->org_clust = file_read.org_clust;
483
  file->curr_clust = file_read.curr_clust;
483
  file->curr_clust = file_read.curr_clust;
484
  file->dsect = file_read.dsect;
484
  file->dsect = file_read.dsect;
485
  file->dir_sect = file_read.dir_sect;
485
  file->dir_sect = file_read.dir_sect;
486
  file->dir_ptr = file_read.dir_ptr;
486
  file->dir_ptr = file_read.dir_ptr;
487
487
488
  // file has been closed
488
  // file has been closed
489
  file_read_is_open = 0;
489
  file_read_is_open = 0;
490
490
491
491
492
  // don't close file via f_close()! We allow to open the file again
492
  // don't close file via f_close()! We allow to open the file again
493
  return 0;
493
  return 0;
494
}
494
}
495
495
496
496
497
/////////////////////////////////////////////////////////////////////////////
497
/////////////////////////////////////////////////////////////////////////////
498
//! Changes to a new file position
498
//! Changes to a new file position
499
//! \return < 0 on errors (error codes are documented in file.h)
499
//! \return < 0 on errors (error codes are documented in file.h)
500
/////////////////////////////////////////////////////////////////////////////
500
/////////////////////////////////////////////////////////////////////////////
501
s32 FILE_ReadSeek(u32 offset)
501
s32 FILE_ReadSeek(u32 offset)
502
{
502
{
503
  if( (file_dfs_errno=f_lseek(&file_read, offset)) != FR_OK ) {
503
  if( (file_dfs_errno=f_lseek(&file_read, offset)) != FR_OK ) {
504
#if DEBUG_VERBOSE_LEVEL >= 2
504
#if DEBUG_VERBOSE_LEVEL >= 2
505
    DEBUG_MSG("[FILE_ReadSeek] ERROR: seek to offset %u failed (FatFs status: %d)\n", offset, file_dfs_errno);
505
    DEBUG_MSG("[FILE_ReadSeek] ERROR: seek to offset %u failed (FatFs status: %d)\n", offset, file_dfs_errno);
506
#endif
506
#endif
507
    return FILE_ERR_SEEK;
507
    return FILE_ERR_SEEK;
508
  }
508
  }
509
  return 0; // no error
509
  return 0; // no error
510
}
510
}
511
511
512
512
513
/////////////////////////////////////////////////////////////////////////////
513
/////////////////////////////////////////////////////////////////////////////
514
//! Returns current size of write file
514
//! Returns current size of write file
515
/////////////////////////////////////////////////////////////////////////////
515
/////////////////////////////////////////////////////////////////////////////
516
u32 FILE_ReadGetCurrentSize(void)
516
u32 FILE_ReadGetCurrentSize(void)
517
{
517
{
518
  return file_read.fsize;
518
  return file_read.fsize;
519
}
519
}
520
520
521
/////////////////////////////////////////////////////////////////////////////
521
/////////////////////////////////////////////////////////////////////////////
522
//! Returns current file pointer of the write file
522
//! Returns current file pointer of the write file
523
/////////////////////////////////////////////////////////////////////////////
523
/////////////////////////////////////////////////////////////////////////////
524
u32 FILE_ReadGetCurrentPosition(void)
524
u32 FILE_ReadGetCurrentPosition(void)
525
{
525
{
526
  return file_read.fptr;
526
  return file_read.fptr;
527
}
527
}
528
528
529
529
530
530
531
/////////////////////////////////////////////////////////////////////////////
531
/////////////////////////////////////////////////////////////////////////////
532
//! Read from file
532
//! Read from file
533
//! \return < 0 on errors (error codes are documented in file.h)
533
//! \return < 0 on errors (error codes are documented in file.h)
534
/////////////////////////////////////////////////////////////////////////////
534
/////////////////////////////////////////////////////////////////////////////
535
s32 FILE_ReadBuffer(u8 *buffer, u32 len)
535
s32 FILE_ReadBuffer(u8 *buffer, u32 len)
536
{
536
{
537
  UINT successcount;
537
  UINT successcount;
538
538
539
  // exit if volume not available
539
  // exit if volume not available
540
  if( !volume_available )
540
  if( !volume_available )
541
    return FILE_ERR_NO_VOLUME;
541
    return FILE_ERR_NO_VOLUME;
542
542
543
  if( (file_dfs_errno=f_read(&file_read, buffer, len, &successcount)) != FR_OK ) {
543
  if( (file_dfs_errno=f_read(&file_read, buffer, len, &successcount)) != FR_OK ) {
544
#if DEBUG_VERBOSE_LEVEL >= 3
544
#if DEBUG_VERBOSE_LEVEL >= 3
545
    DEBUG_MSG("[FILE] Failed to read sector at position 0x%08x, status: %u\n", file_read.fptr, file_dfs_errno);
545
    DEBUG_MSG("[FILE] Failed to read sector at position 0x%08x, status: %u\n", file_read.fptr, file_dfs_errno);
546
#endif
546
#endif
547
      return FILE_ERR_READ;
547
      return FILE_ERR_READ;
548
  }
548
  }
549
  if( successcount != len ) {
549
  if( successcount != len ) {
550
#if DEBUG_VERBOSE_LEVEL >= 3
550
#if DEBUG_VERBOSE_LEVEL >= 3
551
    DEBUG_MSG("[FILE] Wrong successcount while reading from position 0x%08x (count: %d)\n", file_read.fptr, successcount);
551
    DEBUG_MSG("[FILE] Wrong successcount while reading from position 0x%08x (count: %d)\n", file_read.fptr, successcount);
552
#endif
552
#endif
553
    return FILE_ERR_READCOUNT;
553
    return FILE_ERR_READCOUNT;
554
  }
554
  }
555
555
556
  return 0; // no error
556
  return 0; // no error
557
}
557
}
558
558
559
559
560
/////////////////////////////////////////////////////////////////////////////
560
/////////////////////////////////////////////////////////////////////////////
561
//! Read from file with unknown size
561
//! Read from file with unknown size
562
//! \return < 0 on errors (error codes are documented in file.h)
562
//! \return < 0 on errors (error codes are documented in file.h)
563
//! \return >= 0: value contains the actual read bytes
563
//! \return >= 0: value contains the actual read bytes
564
/////////////////////////////////////////////////////////////////////////////
564
/////////////////////////////////////////////////////////////////////////////
565
s32 FILE_ReadBufferUnknownLen(u8 *buffer, u32 len)
565
s32 FILE_ReadBufferUnknownLen(u8 *buffer, u32 len)
566
{
566
{
567
  UINT successcount;
567
  UINT successcount;
568
568
569
  // exit if volume not available
569
  // exit if volume not available
570
  if( !volume_available )
570
  if( !volume_available )
571
    return FILE_ERR_NO_VOLUME;
571
    return FILE_ERR_NO_VOLUME;
572
572
573
  if( (file_dfs_errno=f_read(&file_read, buffer, len, &successcount)) != FR_OK ) {
573
  if( (file_dfs_errno=f_read(&file_read, buffer, len, &successcount)) != FR_OK ) {
574
#if DEBUG_VERBOSE_LEVEL >= 3
574
#if DEBUG_VERBOSE_LEVEL >= 3
575
    DEBUG_MSG("[FILE] Failed to read sector at position 0x%08x, status: %u\n", file_read.fptr, file_dfs_errno);
575
    DEBUG_MSG("[FILE] Failed to read sector at position 0x%08x, status: %u\n", file_read.fptr, file_dfs_errno);
576
#endif
576
#endif
577
      return FILE_ERR_READ;
577
      return FILE_ERR_READ;
578
  }
578
  }
579
579
580
  return successcount;
580
  return successcount;
581
}
581
}
582
582
583
583
584
/////////////////////////////////////////////////////////////////////////////
584
/////////////////////////////////////////////////////////////////////////////
585
//! Read a string (terminated with CR) from file
585
//! Read a string (terminated with CR) from file
586
//! \return < 0 on errors (error codes are documented in file.h)
586
//! \return < 0 on errors (error codes are documented in file.h)
587
/////////////////////////////////////////////////////////////////////////////
587
/////////////////////////////////////////////////////////////////////////////
588
s32 FILE_ReadLine(u8 *buffer, u32 max_len)
588
s32 FILE_ReadLine(u8 *buffer, u32 max_len)
589
{
589
{
590
  s32 status;
590
  s32 status;
591
  u32 num_read = 0;
591
  u32 num_read = 0;
592
592
593
  while( file_read.fptr < file_read.fsize ) {
593
  while( file_read.fptr < file_read.fsize ) {
594
    status = FILE_ReadBuffer(buffer, 1);
594
    status = FILE_ReadBuffer(buffer, 1);
595
595
596
    if( status < 0 )
596
    if( status < 0 )
597
      return status;
597
      return status;
598
598
599
    ++num_read;
599
    ++num_read;
600
600
601
    if( *buffer == '\n' || *buffer == '\r' )
601
    if( *buffer == '\n' || *buffer == '\r' )
602
      break;
602
      break;
603
603
604
    if( num_read < max_len )
604
    if( num_read < max_len )
605
      ++buffer;
605
      ++buffer;
606
  }
606
  }
607
607
608
  // replace newline by terminator
608
  // replace newline by terminator
609
  *buffer = 0;
609
  *buffer = 0;
610
610
611
  return num_read;
611
  return num_read;
612
}
612
}
613
613
614
/////////////////////////////////////////////////////////////////////////////
614
/////////////////////////////////////////////////////////////////////////////
615
//! Read a 8bit value from file
615
//! Read a 8bit value from file
616
//! \return < 0 on errors (error codes are documented in file.h)
616
//! \return < 0 on errors (error codes are documented in file.h)
617
/////////////////////////////////////////////////////////////////////////////
617
/////////////////////////////////////////////////////////////////////////////
618
s32 FILE_ReadByte(u8 *byte)
618
s32 FILE_ReadByte(u8 *byte)
619
{
619
{
620
  return FILE_ReadBuffer(byte, 1);
620
  return FILE_ReadBuffer(byte, 1);
621
}
621
}
622
622
623
/////////////////////////////////////////////////////////////////////////////
623
/////////////////////////////////////////////////////////////////////////////
624
//! Read a 16bit value from file
624
//! Read a 16bit value from file
625
//! \return < 0 on errors (error codes are documented in file.h)
625
//! \return < 0 on errors (error codes are documented in file.h)
626
/////////////////////////////////////////////////////////////////////////////
626
/////////////////////////////////////////////////////////////////////////////
627
s32 FILE_ReadHWord(u16 *hword)
627
s32 FILE_ReadHWord(u16 *hword)
628
{
628
{
629
  // ensure little endian coding
629
  // ensure little endian coding
630
  u8 tmp[2];
630
  u8 tmp[2];
631
  s32 status = FILE_ReadBuffer(tmp, 2);
631
  s32 status = FILE_ReadBuffer(tmp, 2);
632
  *hword = ((u16)tmp[0] << 0) | ((u16)tmp[1] << 8);
632
  *hword = ((u16)tmp[0] << 0) | ((u16)tmp[1] << 8);
633
  return status;
633
  return status;
634
}
634
}
635
635
636
/////////////////////////////////////////////////////////////////////////////
636
/////////////////////////////////////////////////////////////////////////////
637
//! Read a 32bit value from file
637
//! Read a 32bit value from file
638
//! \return < 0 on errors (error codes are documented in file.h)
638
//! \return < 0 on errors (error codes are documented in file.h)
639
/////////////////////////////////////////////////////////////////////////////
639
/////////////////////////////////////////////////////////////////////////////
640
s32 FILE_ReadWord(u32 *word)
640
s32 FILE_ReadWord(u32 *word)
641
{
641
{
642
  // ensure little endian coding
642
  // ensure little endian coding
643
  u8 tmp[4];
643
  u8 tmp[4];
644
  s32 status = FILE_ReadBuffer(tmp, 4);
644
  s32 status = FILE_ReadBuffer(tmp, 4);
645
  *word = ((u32)tmp[0] << 0) | ((u32)tmp[1] << 8) | ((u32)tmp[2] << 16) | ((u32)tmp[3] << 24);
645
  *word = ((u32)tmp[0] << 0) | ((u32)tmp[1] << 8) | ((u32)tmp[2] << 16) | ((u32)tmp[3] << 24);
646
  return status;
646
  return status;
647
}
647
}
648
648
649
649
650
/////////////////////////////////////////////////////////////////////////////
650
/////////////////////////////////////////////////////////////////////////////
651
//! Opens a file for writing
651
//! Opens a file for writing
652
//! \return < 0 on errors (error codes are documented in file.h)
652
//! \return < 0 on errors (error codes are documented in file.h)
653
/////////////////////////////////////////////////////////////////////////////
653
/////////////////////////////////////////////////////////////////////////////
654
s32 FILE_WriteOpen(char *filepath, u8 create)
654
s32 FILE_WriteOpen(char *filepath, u8 create)
655
{
655
{
656
  if( file_write_is_open ) {
656
  if( file_write_is_open ) {
657
#if DEBUG_VERBOSE_LEVEL >= 1
657
#if DEBUG_VERBOSE_LEVEL >= 1
658
    DEBUG_MSG("[FILE] FAILURE: tried to open file '%s' for writing, but previous file hasn't been closed!\n", filepath);
658
    DEBUG_MSG("[FILE] FAILURE: tried to open file '%s' for writing, but previous file hasn't been closed!\n", filepath);
659
#endif
659
#endif
660
    return FILE_ERR_OPEN_WRITE_WITHOUT_CLOSE;
660
    return FILE_ERR_OPEN_WRITE_WITHOUT_CLOSE;
661
  }
661
  }
662
662
663
  if( (file_dfs_errno=f_open(&file_write, filepath, (create ? FA_CREATE_ALWAYS : FA_OPEN_EXISTING) | FA_WRITE)) != FR_OK ) {
663
  if( (file_dfs_errno=f_open(&file_write, filepath, (create ? FA_CREATE_ALWAYS : FA_OPEN_EXISTING) | FA_WRITE)) != FR_OK ) {
664
#if DEBUG_VERBOSE_LEVEL >= 2
664
#if DEBUG_VERBOSE_LEVEL >= 2
665
    DEBUG_MSG("[FILE] error opening file '%s' for writing!\n", filepath);
665
    DEBUG_MSG("[FILE] error opening file '%s' for writing!\n", filepath);
666
#endif
666
#endif
667
    return FILE_ERR_OPEN_WRITE;
667
    return FILE_ERR_OPEN_WRITE;
668
  }
668
  }
669
669
670
  // remember state
670
  // remember state
671
  file_write_is_open = 1;
671
  file_write_is_open = 1;
672
672
673
  return 0; // no error
673
  return 0; // no error
674
}
674
}
675
675
676
676
677
/////////////////////////////////////////////////////////////////////////////
677
/////////////////////////////////////////////////////////////////////////////
678
//! Closes a file by writing the last bytes
678
//! Closes a file by writing the last bytes
679
//! \return < 0 on errors (error codes are documented in file.h)
679
//! \return < 0 on errors (error codes are documented in file.h)
680
/////////////////////////////////////////////////////////////////////////////
680
/////////////////////////////////////////////////////////////////////////////
681
s32 FILE_WriteClose(void)
681
s32 FILE_WriteClose(void)
682
{
682
{
683
  s32 status = 0;
683
  s32 status = 0;
684
684
685
  // close file
685
  // close file
686
  if( (file_dfs_errno=f_close(&file_write)) != FR_OK )
686
  if( (file_dfs_errno=f_close(&file_write)) != FR_OK )
687
    status = FILE_ERR_WRITECLOSE;
687
    status = FILE_ERR_WRITECLOSE;
688
688
689
  file_write_is_open = 0;
689
  file_write_is_open = 0;
690
690
691
  return status;
691
  return status;
692
}
692
}
693
693
694
694
695
695
696
/////////////////////////////////////////////////////////////////////////////
696
/////////////////////////////////////////////////////////////////////////////
697
//! Changes to a new file position
697
//! Changes to a new file position
698
//! \return < 0 on errors (error codes are documented in file.h)
698
//! \return < 0 on errors (error codes are documented in file.h)
699
/////////////////////////////////////////////////////////////////////////////
699
/////////////////////////////////////////////////////////////////////////////
700
s32 FILE_WriteSeek(u32 offset)
700
s32 FILE_WriteSeek(u32 offset)
701
{
701
{
702
  if( (file_dfs_errno=f_lseek(&file_write, offset)) != FR_OK ) {
702
  if( (file_dfs_errno=f_lseek(&file_write, offset)) != FR_OK ) {
703
#if DEBUG_VERBOSE_LEVEL >= 2
703
#if DEBUG_VERBOSE_LEVEL >= 2
704
    DEBUG_MSG("[FILE_ReadSeek] ERROR: seek to offset %u failed (FatFs status: %d)\n", offset, file_dfs_errno);
704
    DEBUG_MSG("[FILE_ReadSeek] ERROR: seek to offset %u failed (FatFs status: %d)\n", offset, file_dfs_errno);
705
#endif
705
#endif
706
    return FILE_ERR_SEEK;
706
    return FILE_ERR_SEEK;
707
  }
707
  }
708
  return 0; // no error
708
  return 0; // no error
709
}
709
}
710
710
711
711
712
/////////////////////////////////////////////////////////////////////////////
712
/////////////////////////////////////////////////////////////////////////////
713
//! Returns current size of write file
713
//! Returns current size of write file
714
/////////////////////////////////////////////////////////////////////////////
714
/////////////////////////////////////////////////////////////////////////////
715
u32 FILE_WriteGetCurrentSize(void)
715
u32 FILE_WriteGetCurrentSize(void)
716
{
716
{
717
  if( !file_write_is_open )
717
  if( !file_write_is_open )
718
    return 0;
718
    return 0;
719
  return file_write.fsize;
719
  return file_write.fsize;
720
}
720
}
721
721
722
/////////////////////////////////////////////////////////////////////////////
722
/////////////////////////////////////////////////////////////////////////////
723
//! Returns current file pointer of the write file
723
//! Returns current file pointer of the write file
724
/////////////////////////////////////////////////////////////////////////////
724
/////////////////////////////////////////////////////////////////////////////
725
u32 FILE_WriteGetCurrentPosition(void)
725
u32 FILE_WriteGetCurrentPosition(void)
726
{
726
{
727
  if( !file_write_is_open )
727
  if( !file_write_is_open )
728
    return 0;
728
    return 0;
729
  return file_write.fptr;
729
  return file_write.fptr;
730
}
730
}
731
731
732
732
733
/////////////////////////////////////////////////////////////////////////////
733
/////////////////////////////////////////////////////////////////////////////
734
//! Writes into a file with caching mechanism (actual write at end of sector)
734
//! Writes into a file with caching mechanism (actual write at end of sector)
735
//! File has to be closed via FILE_WriteClose() after the last byte has
735
//! File has to be closed via FILE_WriteClose() after the last byte has
736
//! been written
736
//! been written
737
//! \return < 0 on errors (error codes are documented in file.h)
737
//! \return < 0 on errors (error codes are documented in file.h)
738
/////////////////////////////////////////////////////////////////////////////
738
/////////////////////////////////////////////////////////////////////////////
739
s32 FILE_WriteBuffer(u8 *buffer, u32 len)
739
s32 FILE_WriteBuffer(u8 *buffer, u32 len)
740
{
740
{
741
  // exit if volume not available
741
  // exit if volume not available
742
  if( !volume_available )
742
  if( !volume_available )
743
    return FILE_ERR_NO_VOLUME;
743
    return FILE_ERR_NO_VOLUME;
744
744
745
  UINT successcount;
745
  UINT successcount;
746
  if( (file_dfs_errno=f_write(&file_write, buffer, len, &successcount)) != FR_OK ) {
746
  if( (file_dfs_errno=f_write(&file_write, buffer, len, &successcount)) != FR_OK ) {
747
#if DEBUG_VERBOSE_LEVEL >= 3
747
#if DEBUG_VERBOSE_LEVEL >= 3
748
    DEBUG_MSG("[FILE] Failed to write buffer, status: %u\n", file_dfs_errno);
748
    DEBUG_MSG("[FILE] Failed to write buffer, status: %u\n", file_dfs_errno);
749
#endif
749
#endif
750
    return FILE_ERR_WRITE;
750
    return FILE_ERR_WRITE;
751
  }
751
  }
752
  if( successcount != len ) {
752
  if( successcount != len ) {
753
#if DEBUG_VERBOSE_LEVEL >= 3
753
#if DEBUG_VERBOSE_LEVEL >= 3
754
    DEBUG_MSG("[FILE] Wrong successcount while writing buffer (count: %d)\n", successcount);
754
    DEBUG_MSG("[FILE] Wrong successcount while writing buffer (count: %d)\n", successcount);
755
#endif
755
#endif
756
    return FILE_ERR_WRITECOUNT;
756
    return FILE_ERR_WRITECOUNT;
757
  }
757
  }
758
758
759
  return 0; // no error
759
  return 0; // no error
760
}
760
}
761
761
762
/////////////////////////////////////////////////////////////////////////////
762
/////////////////////////////////////////////////////////////////////////////
763
//! Writes a 8bit value into file
763
//! Writes a 8bit value into file
764
//! \return < 0 on errors (error codes are documented in file.h)
764
//! \return < 0 on errors (error codes are documented in file.h)
765
/////////////////////////////////////////////////////////////////////////////
765
/////////////////////////////////////////////////////////////////////////////
766
s32 FILE_WriteByte(u8 byte)
766
s32 FILE_WriteByte(u8 byte)
767
{
767
{
768
  return FILE_WriteBuffer(&byte, 1);
768
  return FILE_WriteBuffer(&byte, 1);
769
}
769
}
770
770
771
/////////////////////////////////////////////////////////////////////////////
771
/////////////////////////////////////////////////////////////////////////////
772
//! Writes a 16bit value into file
772
//! Writes a 16bit value into file
773
//! \return < 0 on errors (error codes are documented in file.h)
773
//! \return < 0 on errors (error codes are documented in file.h)
774
/////////////////////////////////////////////////////////////////////////////
774
/////////////////////////////////////////////////////////////////////////////
775
s32 FILE_WriteHWord(u16 hword)
775
s32 FILE_WriteHWord(u16 hword)
776
{
776
{
777
  // ensure little endian coding
777
  // ensure little endian coding
778
  u8 tmp[2];
778
  u8 tmp[2];
779
  tmp[0] = (u8)(hword >> 0);
779
  tmp[0] = (u8)(hword >> 0);
780
  tmp[1] = (u8)(hword >> 8);
780
  tmp[1] = (u8)(hword >> 8);
781
  return FILE_WriteBuffer(tmp, 2);
781
  return FILE_WriteBuffer(tmp, 2);
782
}
782
}
783
783
784
/////////////////////////////////////////////////////////////////////////////
784
/////////////////////////////////////////////////////////////////////////////
785
//! Writes a 32bit value into file
785
//! Writes a 32bit value into file
786
//! \return < 0 on errors (error codes are documented in file.h)
786
//! \return < 0 on errors (error codes are documented in file.h)
787
/////////////////////////////////////////////////////////////////////////////
787
/////////////////////////////////////////////////////////////////////////////
788
s32 FILE_WriteWord(u32 word)
788
s32 FILE_WriteWord(u32 word)
789
{
789
{
790
  // ensure little endian coding
790
  // ensure little endian coding
791
  u8 tmp[4];
791
  u8 tmp[4];
792
  tmp[0] = (u8)(word >> 0);
792
  tmp[0] = (u8)(word >> 0);
793
  tmp[1] = (u8)(word >> 8);
793
  tmp[1] = (u8)(word >> 8);
794
  tmp[2] = (u8)(word >> 16);
794
  tmp[2] = (u8)(word >> 16);
795
  tmp[3] = (u8)(word >> 24);
795
  tmp[3] = (u8)(word >> 24);
796
  return FILE_WriteBuffer(tmp, 4);
796
  return FILE_WriteBuffer(tmp, 4);
797
}
797
}
798
798
799
799
800
/////////////////////////////////////////////////////////////////////////////
800
/////////////////////////////////////////////////////////////////////////////
801
//! This function copies a file
801
//! This function copies a file
802
//! \param[in] src_file the source file which should be copied
802
//! \param[in] src_file the source file which should be copied
803
//! \param[in] dst_file the destination file
803
//! \param[in] dst_file the destination file
804
/////////////////////////////////////////////////////////////////////////////
804
/////////////////////////////////////////////////////////////////////////////
805
s32 FILE_Copy(char *src_file, char *dst_file)
805
s32 FILE_Copy(char *src_file, char *dst_file)
806
{
806
{
807
  s32 status = 0;
807
  s32 status = 0;
808
808
809
  if( !volume_available ) {
809
  if( !volume_available ) {
810
#if DEBUG_VERBOSE_LEVEL >= 2
810
#if DEBUG_VERBOSE_LEVEL >= 2
811
    DEBUG_MSG("[FILE_Copy] ERROR: volume doesn't exist!\n");
811
    DEBUG_MSG("[FILE_Copy] ERROR: volume doesn't exist!\n");
812
#endif
812
#endif
813
    return FILE_ERR_NO_VOLUME;
813
    return FILE_ERR_NO_VOLUME;
814
  }
814
  }
815
815
816
#if DEBUG_VERBOSE_LEVEL >= 2
816
#if DEBUG_VERBOSE_LEVEL >= 2
817
  DEBUG_MSG("[FILE_Copy] copy %s to %s\n", src_file, dst_file);
817
  DEBUG_MSG("[FILE_Copy] copy %s to %s\n", src_file, dst_file);
818
#endif
818
#endif
819
819
820
  if( (file_dfs_errno=f_open(&file_read, src_file, FA_OPEN_EXISTING | FA_READ)) != FR_OK ) {
820
  if( (file_dfs_errno=f_open(&file_read, src_file, FA_OPEN_EXISTING | FA_READ)) != FR_OK ) {
821
#if DEBUG_VERBOSE_LEVEL >= 2
821
#if DEBUG_VERBOSE_LEVEL >= 2
822
    DEBUG_MSG("[FILE_Copy] %s doesn't exist!\n", src_file);
822
    DEBUG_MSG("[FILE_Copy] %s doesn't exist!\n", src_file);
823
#endif
823
#endif
824
    status = FILE_ERR_COPY_NO_FILE;
824
    status = FILE_ERR_COPY_NO_FILE;
825
  } else {
825
  } else {
826
    if( (file_dfs_errno=f_open(&file_write, dst_file, FA_CREATE_ALWAYS | FA_WRITE)) != FR_OK ) {
826
    if( (file_dfs_errno=f_open(&file_write, dst_file, FA_CREATE_ALWAYS | FA_WRITE)) != FR_OK ) {
827
#if DEBUG_VERBOSE_LEVEL >= 2
827
#if DEBUG_VERBOSE_LEVEL >= 2
828
      DEBUG_MSG("[FILE_Copy] wasn't able to create %s - exit!\n", dst_file);
828
      DEBUG_MSG("[FILE_Copy] wasn't able to create %s - exit!\n", dst_file);
829
#endif
829
#endif
830
      status = FILE_ERR_COPY;
830
      status = FILE_ERR_COPY;
831
      //f_close(&file_read); // never close read files to avoid "invalid object"
831
      //f_close(&file_read); // never close read files to avoid "invalid object"
832
    }
832
    }
833
  }
833
  }
834
834
835
  if( status < 0 ) {
835
  if( status < 0 ) {
836
#if DEBUG_VERBOSE_LEVEL >= 2
836
#if DEBUG_VERBOSE_LEVEL >= 2
837
    DEBUG_MSG("[FILE_Copy] Copy aborted due to previous errors (%d)!\n", status);
837
    DEBUG_MSG("[FILE_Copy] Copy aborted due to previous errors (%d)!\n", status);
838
#endif
838
#endif
839
  } else {
839
  } else {
840
    // copy operation
840
    // copy operation
841
#if DEBUG_VERBOSE_LEVEL >= 2
841
#if DEBUG_VERBOSE_LEVEL >= 2
842
    DEBUG_MSG("[FILE_Copy] Starting copy operation!\n");
842
    DEBUG_MSG("[FILE_Copy] Starting copy operation!\n");
843
#endif
843
#endif
844
844
845
    file_copy_percentage = 0; // for percentage display
845
    file_copy_percentage = 0; // for percentage display
846
846
847
    UINT successcount;
847
    UINT successcount;
848
    UINT successcount_wr;
848
    UINT successcount_wr;
849
    u32 num_bytes = 0;
849
    u32 num_bytes = 0;
850
    do {
850
    do {
851
      if( (file_dfs_errno=f_read(&file_read, tmp_buffer, TMP_BUFFER_SIZE, &successcount)) != FR_OK ) {
851
      if( (file_dfs_errno=f_read(&file_read, tmp_buffer, TMP_BUFFER_SIZE, &successcount)) != FR_OK ) {
852
#if DEBUG_VERBOSE_LEVEL >= 2
852
#if DEBUG_VERBOSE_LEVEL >= 2
853
    DEBUG_MSG("[FILE_Copy] Failed to read sector at position 0x%08x, status: %u\n", file_read.fptr, file_dfs_errno);
853
    DEBUG_MSG("[FILE_Copy] Failed to read sector at position 0x%08x, status: %u\n", file_read.fptr, file_dfs_errno);
854
#endif
854
#endif
855
    successcount = 0;
855
    successcount = 0;
856
    status = FILE_ERR_READ;
856
    status = FILE_ERR_READ;
857
      } else if( successcount && (file_dfs_errno=f_write(&file_write, tmp_buffer, successcount, &successcount_wr)) != FR_OK ) {
857
      } else if( successcount && (file_dfs_errno=f_write(&file_write, tmp_buffer, successcount, &successcount_wr)) != FR_OK ) {
858
#if DEBUG_VERBOSE_LEVEL >= 2
858
#if DEBUG_VERBOSE_LEVEL >= 2
859
    DEBUG_MSG("[FILE_Copy] Failed to write sector at position 0x%08x, status: %u\n", file_write.fptr, file_dfs_errno);
859
    DEBUG_MSG("[FILE_Copy] Failed to write sector at position 0x%08x, status: %u\n", file_write.fptr, file_dfs_errno);
860
#endif
860
#endif
861
    status = FILE_ERR_WRITE;
861
    status = FILE_ERR_WRITE;
862
      } else {
862
      } else {
863
    num_bytes += successcount_wr;
863
    num_bytes += successcount_wr;
864
    file_copy_percentage = (u8)((100 * num_bytes) / file_read.fsize);
864
    file_copy_percentage = (u8)((100 * num_bytes) / file_read.fsize);
865
      }
865
      }
866
    } while( status == 0 && successcount > 0 );
866
    } while( status == 0 && successcount > 0 );
867
867
868
#if DEBUG_VERBOSE_LEVEL >= 2
868
#if DEBUG_VERBOSE_LEVEL >= 2
869
    DEBUG_MSG("[FILE_Copy] Finished copy operation (%d bytes)!\n", num_bytes);
869
    DEBUG_MSG("[FILE_Copy] Finished copy operation (%d bytes)!\n", num_bytes);
870
#endif
870
#endif
871
871
872
    //f_close(&file_read); // never close read files to avoid "invalid object"
872
    //f_close(&file_read); // never close read files to avoid "invalid object"
873
    f_close(&file_write);
873
    f_close(&file_write);
874
  }
874
  }
875
875
876
  return status;
876
  return status;
877
}
877
}
878
878
879
879
880
/////////////////////////////////////////////////////////////////////////////
880
/////////////////////////////////////////////////////////////////////////////
881
//! Creates a directory
881
//! Creates a directory
882
/////////////////////////////////////////////////////////////////////////////
882
/////////////////////////////////////////////////////////////////////////////
883
s32 FILE_MakeDir(char *path)
883
s32 FILE_MakeDir(char *path)
884
{
884
{
885
  // exit if volume not available
885
  // exit if volume not available
886
  if( !volume_available ) {
886
  if( !volume_available ) {
887
#if DEBUG_VERBOSE_LEVEL >= 2
887
#if DEBUG_VERBOSE_LEVEL >= 2
888
    DEBUG_MSG("[FILE_MakeDir] ERROR: volume doesn't exist!\n");
888
    DEBUG_MSG("[FILE_MakeDir] ERROR: volume doesn't exist!\n");
889
#endif
889
#endif
890
    return FILE_ERR_NO_VOLUME;
890
    return FILE_ERR_NO_VOLUME;
891
  }
891
  }
892
892
893
  if( (file_dfs_errno=f_mkdir(path)) != FR_OK )
893
  if( (file_dfs_errno=f_mkdir(path)) != FR_OK )
894
    return FILE_ERR_MKDIR;
894
    return FILE_ERR_MKDIR;
895
895
896
  return 0; // directory created
896
  return 0; // directory created
897
}
897
}
898
898
899
899
900
/////////////////////////////////////////////////////////////////////////////
900
/////////////////////////////////////////////////////////////////////////////
901
//! Removes a file or directory
901
//! Removes a file or directory
902
/////////////////////////////////////////////////////////////////////////////
902
/////////////////////////////////////////////////////////////////////////////
903
s32 FILE_Remove(char *path)
903
s32 FILE_Remove(char *path)
904
{
904
{
905
  // exit if volume not available
905
  // exit if volume not available
906
  if( !volume_available ) {
906
  if( !volume_available ) {
907
#if DEBUG_VERBOSE_LEVEL >= 2
907
#if DEBUG_VERBOSE_LEVEL >= 2
908
    DEBUG_MSG("[FILE_MakeDir] ERROR: volume doesn't exist!\n");
908
    DEBUG_MSG("[FILE_MakeDir] ERROR: volume doesn't exist!\n");
909
#endif
909
#endif
910
    return FILE_ERR_NO_VOLUME;
910
    return FILE_ERR_NO_VOLUME;
911
  }
911
  }
912
912
913
#ifdef MIOS32_FAMILY_EMULATION
913
#ifdef MIOS32_FAMILY_EMULATION
914
  if( (file_dfs_errno=unlink(path)) != FR_OK )
914
  if( (file_dfs_errno=unlink(path)) != FR_OK )
915
    return FILE_ERR_REMOVE;
915
    return FILE_ERR_REMOVE;
916
#else
916
#else
917
  if( (file_dfs_errno=f_unlink(path)) != FR_OK )
917
  if( (file_dfs_errno=f_unlink(path)) != FR_OK )
918
    return FILE_ERR_REMOVE;
918
    return FILE_ERR_REMOVE;
919
#endif
919
#endif
920
920
921
  return 0; // directory created
921
  return 0; // directory created
922
}
922
}
923
923
924
924
925
/////////////////////////////////////////////////////////////////////////////
925
/////////////////////////////////////////////////////////////////////////////
926
//! Returns 1 if file exists, 0 if it doesn't exist, < 0 on errors
926
//! Returns 1 if file exists, 0 if it doesn't exist, < 0 on errors
927
/////////////////////////////////////////////////////////////////////////////
927
/////////////////////////////////////////////////////////////////////////////
928
s32 FILE_FileExists(char *filepath)
928
s32 FILE_FileExists(char *filepath)
929
{
929
{
930
  // exit if volume not available
930
  // exit if volume not available
931
  if( !volume_available ) {
931
  if( !volume_available ) {
932
#if DEBUG_VERBOSE_LEVEL >= 2
932
#if DEBUG_VERBOSE_LEVEL >= 2
933
    DEBUG_MSG("[FILE_FileExists] ERROR: volume doesn't exist!\n");
933
    DEBUG_MSG("[FILE_FileExists] ERROR: volume doesn't exist!\n");
934
#endif
934
#endif
935
    return FILE_ERR_NO_VOLUME;
935
    return FILE_ERR_NO_VOLUME;
936
  }
936
  }
937
937
938
  if( !filepath || !filepath[0] )
938
  if( !filepath || !filepath[0] )
939
    return 0; // empty file name - handle like if it doesn't exist
939
    return 0; // empty file name - handle like if it doesn't exist
940
940
941
  if( f_open(&file_read, filepath, FA_OPEN_EXISTING | FA_READ) != FR_OK )
941
  if( f_open(&file_read, filepath, FA_OPEN_EXISTING | FA_READ) != FR_OK )
942
    return 0; // file doesn't exist
942
    return 0; // file doesn't exist
943
  //f_close(&file_read); // never close read files to avoid "invalid object"
943
  //f_close(&file_read); // never close read files to avoid "invalid object"
944
  return 1; // file exists
944
  return 1; // file exists
945
}
945
}
946
946
947
947
948
/////////////////////////////////////////////////////////////////////////////
948
/////////////////////////////////////////////////////////////////////////////
949
//! Returns 1 if directory exists, 0 if it doesn't exist, < 0 on errors
949
//! Returns 1 if directory exists, 0 if it doesn't exist, < 0 on errors
950
/////////////////////////////////////////////////////////////////////////////
950
/////////////////////////////////////////////////////////////////////////////
951
s32 FILE_DirExists(char *path)
951
s32 FILE_DirExists(char *path)
952
{
952
{
953
  DIR dir;
953
  DIR dir;
954
954
955
  if( !volume_available ) {
955
  if( !volume_available ) {
956
#if DEBUG_VERBOSE_LEVEL >= 2
956
#if DEBUG_VERBOSE_LEVEL >= 2
957
    DEBUG_MSG("[FILE_DirExists] ERROR: volume doesn't exist!\n");
957
    DEBUG_MSG("[FILE_DirExists] ERROR: volume doesn't exist!\n");
958
#endif
958
#endif
959
    return FILE_ERR_NO_VOLUME;
959
    return FILE_ERR_NO_VOLUME;
960
  }
960
  }
961
961
962
  if( !path || !path[0] )
962
  if( !path || !path[0] )
963
    return 0; // empty directory name - handle like if it doesn't exist
963
    return 0; // empty directory name - handle like if it doesn't exist
964
964
965
  return (file_dfs_errno=f_opendir(&dir, path)) == FR_OK;
965
  return (file_dfs_errno=f_opendir(&dir, path)) == FR_OK;
966
}
966
}
967
967
968
968
969
/////////////////////////////////////////////////////////////////////////////
969
/////////////////////////////////////////////////////////////////////////////
970
// This function searches for directories under given path and copies the names
970
// This function searches for directories under given path and copies the names
971
// into a list (e.g. used by seq_ui_sysex.c)
971
// into a list (e.g. used by seq_ui_sysex.c)
972
// !!TEMPORARY VERSION!! will be combined with FILE_GetFiles later
972
// !!TEMPORARY VERSION!! will be combined with FILE_GetFiles later
973
/////////////////////////////////////////////////////////////////////////////
973
/////////////////////////////////////////////////////////////////////////////
974
s32 FILE_GetDirs(char *path, char *dir_list, u8 num_of_items, u8 dir_offset)
974
s32 FILE_GetDirs(char *path, char *dir_list, u8 num_of_items, u8 dir_offset)
975
{
975
{
976
  s32 status = 0;
976
  s32 status = 0;
977
  DIR di;
977
  DIR di;
978
  FILINFO de;
978
  FILINFO de;
979
979
980
  if( !volume_available ) {
980
  if( !volume_available ) {
981
#if DEBUG_VERBOSE_LEVEL >= 2
981
#if DEBUG_VERBOSE_LEVEL >= 2
982
    DEBUG_MSG("[FILE_GetDirs] ERROR: volume doesn't exist!\n");
982
    DEBUG_MSG("[FILE_GetDirs] ERROR: volume doesn't exist!\n");
983
#endif
983
#endif
984
    return FILE_ERR_NO_VOLUME;
984
    return FILE_ERR_NO_VOLUME;
985
  }
985
  }
986
986
987
  if( f_opendir(&di, path) != FR_OK ) {
987
  if( f_opendir(&di, path) != FR_OK ) {
988
#if DEBUG_VERBOSE_LEVEL >= 2
988
#if DEBUG_VERBOSE_LEVEL >= 2
989
    DEBUG_MSG("[FILE_GetDirs] ERROR: opening %s directory - please create it!\n", path);
989
    DEBUG_MSG("[FILE_GetDirs] ERROR: opening %s directory - please create it!\n", path);
990
#endif
990
#endif
991
    status = FILE_ERR_NO_DIR;
991
    status = FILE_ERR_NO_DIR;
992
  }
992
  }
993
993
994
  int num_dirs = 0;
994
  int num_dirs = 0;
995
  while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
995
  while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
996
    if( de.fname[0] && de.fname[0] != '.' && (de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
996
    if( de.fname[0] && de.fname[0] != '.' && (de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
997
      ++num_dirs;
997
      ++num_dirs;
998
998
999
#if DEBUG_VERBOSE_LEVEL >= 2
999
#if DEBUG_VERBOSE_LEVEL >= 2
1000
      DEBUG_MSG("--> %s\n", de.fname);
1000
      DEBUG_MSG("--> %s\n", de.fname);
1001
#endif
1001
#endif
1002
1002
1003
      if( num_dirs > dir_offset && num_dirs <= (dir_offset+num_of_items) ) {
1003
      if( num_dirs > dir_offset && num_dirs <= (dir_offset+num_of_items) ) {
1004
    int item_pos = 9 * (num_dirs-1-dir_offset);
1004
    int item_pos = 9 * (num_dirs-1-dir_offset);
1005
    char *p = (char *)&dir_list[item_pos];
1005
    char *p = (char *)&dir_list[item_pos];
1006
    int i;
1006
    int i;
1007
    for(i=0; i<8; ++i) {
1007
    for(i=0; i<8; ++i) {
1008
      char c = de.fname[i];
1008
      char c = de.fname[i];
1009
      if( !c || c == '.' )
1009
      if( !c || c == '.' )
1010
        break;
1010
        break;
1011
      *p++ = c;
1011
      *p++ = c;
1012
    }
1012
    }
1013
    for(;i<9; ++i)
1013
    for(;i<9; ++i)
1014
      *p++ = ' ';
1014
      *p++ = ' ';
1015
      }
1015
      }
1016
    }
1016
    }
1017
  }
1017
  }
1018
1018
1019
  return (status < 0) ? status : num_dirs;
1019
  return (status < 0) ? status : num_dirs;
1020
}
1020
}
1021
1021
1022
1022
1023
/////////////////////////////////////////////////////////////////////////////
1023
/////////////////////////////////////////////////////////////////////////////
1024
// This function searches for files under given path and copies the names
1024
// This function searches for files under given path and copies the names
1025
// into a list (e.g. used by seq_ui_sysex.c)
1025
// into a list (e.g. used by seq_ui_sysex.c)
1026
// !!TEMPORARY VERSION!! will be combined with FILE_GetDirs later
1026
// !!TEMPORARY VERSION!! will be combined with FILE_GetDirs later
1027
/////////////////////////////////////////////////////////////////////////////
1027
/////////////////////////////////////////////////////////////////////////////
1028
s32 FILE_GetFiles(char *path, char *ext_filter, char *file_list, u8 num_of_items, u8 file_offset)
1028
s32 FILE_GetFiles(char *path, char *ext_filter, char *file_list, u8 num_of_items, u8 file_offset)
1029
{
1029
{
1030
  s32 status = 0;
1030
  s32 status = 0;
1031
  DIR di;
1031
  DIR di;
1032
  FILINFO de;
1032
  FILINFO de;
1033
1033
1034
  if( !volume_available ) {
1034
  if( !volume_available ) {
1035
#if DEBUG_VERBOSE_LEVEL >= 2
1035
#if DEBUG_VERBOSE_LEVEL >= 2
1036
    DEBUG_MSG("[FILE_GetFiles] ERROR: volume doesn't exist!\n");
1036
    DEBUG_MSG("[FILE_GetFiles] ERROR: volume doesn't exist!\n");
1037
#endif
1037
#endif
1038
    return FILE_ERR_NO_VOLUME;
1038
    return FILE_ERR_NO_VOLUME;
1039
  }
1039
  }
1040
1040
1041
  if( f_opendir(&di, path) != FR_OK ) {
1041
  if( f_opendir(&di, path) != FR_OK ) {
1042
#if DEBUG_VERBOSE_LEVEL >= 2
1042
#if DEBUG_VERBOSE_LEVEL >= 2
1043
    DEBUG_MSG("[FILE_GetFiles] ERROR: opening %s directory - please create it!\n", path);
1043
    DEBUG_MSG("[FILE_GetFiles] ERROR: opening %s directory - please create it!\n", path);
1044
#endif
1044
#endif
1045
    status = FILE_ERR_NO_DIR;
1045
    status = FILE_ERR_NO_DIR;
1046
  }
1046
  }
1047
1047
1048
  int num_files = 0;
1048
  int num_files = 0;
1049
  while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
1049
  while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
1050
    if( de.fname[0] && de.fname[0] != '.' &&
1050
    if( de.fname[0] && de.fname[0] != '.' &&
1051
    !(de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
1051
    !(de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
1052
1052
1053
      char *p = (char *)&de.fname[0];
1053
      char *p = (char *)&de.fname[0];
1054
      int i;
1054
      int i;
1055
      for(i=0; i<9; ++i, p++) {
1055
      for(i=0; i<9; ++i, p++) {
1056
    if( *p == '.' )
1056
    if( *p == '.' )
1057
      break;
1057
      break;
1058
      }
1058
      }
1059
1059
1060
      if( ext_filter && *p++ != '.' )
1060
      if( ext_filter && *p++ != '.' )
1061
    continue;
1061
    continue;
1062
1062
1063
      if( ext_filter && strncasecmp(p, ext_filter, 3) != 0 )
1063
      if( ext_filter && strncasecmp(p, ext_filter, 3) != 0 )
1064
    continue;
1064
    continue;
1065
1065
1066
      ++num_files;
1066
      ++num_files;
1067
1067
1068
#if DEBUG_VERBOSE_LEVEL >= 2
1068
#if DEBUG_VERBOSE_LEVEL >= 2
1069
      DEBUG_MSG("--> %s\n", de.fname);
1069
      DEBUG_MSG("--> %s\n", de.fname);
1070
#endif
1070
#endif
1071
      if( num_files > file_offset && num_files <= (file_offset+num_of_items) ) {
1071
      if( num_files > file_offset && num_files <= (file_offset+num_of_items) ) {
1072
    int item_pos = 9 * (num_files-1-file_offset);
1072
    int item_pos = 9 * (num_files-1-file_offset);
1073
    char *p = (char *)&file_list[item_pos];
1073
    char *p = (char *)&file_list[item_pos];
1074
1074
1075
    for(i=0; i<8; ++i) {
1075
    for(i=0; i<8; ++i) {
1076
      char c = de.fname[i];
1076
      char c = de.fname[i];
1077
      if( !c || c == '.' )
1077
      if( !c || c == '.' )
1078
        break;
1078
        break;
1079
      *p++ = c;
1079
      *p++ = c;
1080
    }
1080
    }
1081
1081
1082
    for(;i<9; ++i)
1082
    for(;i<9; ++i)
1083
      *p++ = ' ';
1083
      *p++ = ' ';
1084
      }
1084
      }
1085
    }
1085
    }
1086
  }
1086
  }
1087
1087
1088
  return (status < 0) ? status : num_files;
1088
  return (status < 0) ? status : num_files;
1089
}
1089
}
1090
1090
1091
/////////////////////////////////////////////////////////////////////////////
1091
/////////////////////////////////////////////////////////////////////////////
1092
//! Returns a directory next to the given directory
1092
//! Returns a directory next to the given directory
1093
//! if dirname == NULL, the first directory will be returned in next_dirname
1093
//! if dirname == NULL, the first directory will be returned in next_dirname
1094
//! \param[in] path directory in which we want to search for subdirectories
1094
//! \param[in] path directory in which we want to search for subdirectories
1095
//! \param[in] dirname current subdirectory (if NULL, the first directory will be returned)
1095
//! \param[in] dirname current subdirectory (if NULL, the first directory will be returned)
1096
//! \param[out] next_dirname the next subdirectory if return status is 1; an empty
1096
//! \param[out] next_dirname the next subdirectory if return status is 1; an empty
1097
//! string if return status is 0; no change on error
1097
//! string if return status is 0; no change on error
1098
//! \return < 0 on errors (error codes are documented in file.h)
1098
//! \return < 0 on errors (error codes are documented in file.h)
1099
//! \return 1 if next directory has been found
1099
//! \return 1 if next directory has been found
1100
//! \return 0 if no additional directory
1100
//! \return 0 if no additional directory
1101
/////////////////////////////////////////////////////////////////////////////
1101
/////////////////////////////////////////////////////////////////////////////
1102
s32 FILE_FindNextDir(char *path, char *dirname, char *next_dirname){
1102
s32 FILE_FindNextDir(char *path, char *dirname, char *next_dirname){
1103
    s32 status = 0;
1103
    s32 status = 0;
1104
  DIR di;
1104
  DIR di;
1105
  FILINFO de;
1105
  FILINFO de;
1106
1106
1107
  if( !volume_available ) {
1107
  if( !volume_available ) {
1108
    #if DEBUG_VERBOSE_LEVEL >= 2
1108
    #if DEBUG_VERBOSE_LEVEL >= 2
1109
    DEBUG_MSG("[FILE_FindNextDir] ERROR: volume doesn't exist!\n");
1109
    DEBUG_MSG("[FILE_FindNextDir] ERROR: volume doesn't exist!\n");
1110
    #endif
1110
    #endif
1111
    return FILE_ERR_NO_VOLUME;
1111
    return FILE_ERR_NO_VOLUME;
1112
  }
1112
  }
1113
1113
1114
  if( f_opendir(&di, path) != FR_OK ) {
1114
  if( f_opendir(&di, path) != FR_OK ) {
1115
    #if DEBUG_VERBOSE_LEVEL >= 2
1115
    #if DEBUG_VERBOSE_LEVEL >= 2
1116
    DEBUG_MSG("[FILE_FindNextDir] ERROR: opening %s directory - please create it!\n", path);
1116
    DEBUG_MSG("[FILE_FindNextDir] ERROR: opening %s directory - please create it!\n", path);
1117
    #endif
1117
    #endif
1118
    return FILE_ERR_NO_DIR;
1118
    return FILE_ERR_NO_DIR;
1119
  }
1119
  }
1120
1120
1121
  u8 take_next = 0;
1121
  u8 take_next = 0;
1122
  while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
1122
  while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
1123
    if( de.fname[0] && de.fname[0] != '.' &&
1123
    if( de.fname[0] && de.fname[0] != '.' &&
1124
        (de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
1124
        (de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
1125
1125
1126
      #if DEBUG_VERBOSE_LEVEL >= 2
1126
      #if DEBUG_VERBOSE_LEVEL >= 2
1127
      DEBUG_MSG("--> %s\n", de.fname);
1127
      DEBUG_MSG("--> %s\n", de.fname);
1128
      #endif
1128
      #endif
1129
     
1129
     
1130
      //Are we done? First/next file?
1130
      //Are we done? First/next file?
1131
      if( take_next || dirname == NULL ) {
1131
      if( take_next || dirname == NULL ) {
1132
        memcpy((char *)next_dirname, (char *)&de.fname[0], 9);
1132
        memcpy((char *)next_dirname, (char *)&de.fname[0], 9);
1133
        return 1; // dir found
1133
        return 1; // dir found
1134
      }
1134
      }
1135
     
1135
     
1136
      //Compare names
1136
      //Compare names
1137
      char *p = (char *)&de.fname[0];
1137
      char *p = (char *)&de.fname[0];
1138
      int i;
1138
      int i;
1139
      u8 dirname_matches = 1;
1139
      u8 dirname_matches = 1;
1140
      char *p_check = dirname;
1140
      char *p_check = dirname;
1141
      for(i=0; i<8; ++i, p++) {
1141
      for(i=0; i<8; ++i, p++) {
1142
        if( *p != *p_check++ ) {
1142
        if( *p != *p_check++ ) {
1143
          dirname_matches = 0;
1143
          dirname_matches = 0;
1144
          break;
1144
          break;
1145
        }
1145
        }
1146
        if(!*p) break; //Both names end here
1146
        if(!*p) break; //Both names end here
1147
      }
1147
      }
1148
      if( dirname_matches ) take_next = 1;
1148
      if( dirname_matches ) take_next = 1;
1149
    }
1149
    }
1150
  }
1150
  }
1151
1151
1152
  next_dirname[0] = 0; // set terminator (empty string)
1152
  next_dirname[0] = 0; // set terminator (empty string)
1153
  return 0; // dir not found
1153
  return 0; // dir not found
1154
}
1154
}
1155
/////////////////////////////////////////////////////////////////////////////
1155
/////////////////////////////////////////////////////////////////////////////
1156
//! Returns the previous directory next to the given directory
1156
//! Returns the previous directory next to the given directory
1157
//! if dirname == NULL, the last directory will be returned
1157
//! if dirname == NULL, the last directory will be returned
1158
//! \param[in] path directory in which we want to search for subdirectories
1158
//! \param[in] path directory in which we want to search for subdirectories
1159
//! \param[in] dirname current subdirectory (if NULL, will return the last subdirectory)
1159
//! \param[in] dirname current subdirectory (if NULL, will return the last subdirectory)
1160
//! \param[out] prev_dirname the previous subdirectory if return status is 1; an empty
1160
//! \param[out] prev_dirname the previous subdirectory if return status is 1; an empty
1161
//! string if return status is 0; no change on error
1161
//! string if return status is 0; no change on error
1162
//! \return < 0 on errors (error codes are documented in file.h)
1162
//! \return < 0 on errors (error codes are documented in file.h)
1163
//! \return 1 if previous directory has been found
1163
//! \return 1 if previous directory has been found
1164
//! \return 0 if no additional directory
1164
//! \return 0 if no additional directory
1165
/////////////////////////////////////////////////////////////////////////////
1165
/////////////////////////////////////////////////////////////////////////////
1166
s32 FILE_FindPreviousDir(char *path, char *dirname, char *prev_dirname)
1166
s32 FILE_FindPreviousDir(char *path, char *dirname, char *prev_dirname)
1167
{
1167
{
1168
  s32 status = 0;
1168
  s32 status = 0;
1169
  DIR di;
1169
  DIR di;
1170
  FILINFO de;
1170
  FILINFO de;
1171
1171
1172
  if( !volume_available ) {
1172
  if( !volume_available ) {
1173
    #if DEBUG_VERBOSE_LEVEL >= 2
1173
    #if DEBUG_VERBOSE_LEVEL >= 2
1174
    DEBUG_MSG("[FILE_FindPreviousDir] ERROR: volume doesn't exist!\n");
1174
    DEBUG_MSG("[FILE_FindPreviousDir] ERROR: volume doesn't exist!\n");
1175
    #endif
1175
    #endif
1176
    return FILE_ERR_NO_VOLUME;
1176
    return FILE_ERR_NO_VOLUME;
1177
  }
1177
  }
1178
1178
1179
  if( f_opendir(&di, path) != FR_OK ) {
1179
  if( f_opendir(&di, path) != FR_OK ) {
1180
    #if DEBUG_VERBOSE_LEVEL >= 2
1180
    #if DEBUG_VERBOSE_LEVEL >= 2
1181
    DEBUG_MSG("[FILE_FindPreviousDir] ERROR: opening %s directory - please create it!\n", path);
1181
    DEBUG_MSG("[FILE_FindPreviousDir] ERROR: opening %s directory - please create it!\n", path);
1182
    #endif
1182
    #endif
1183
    return FILE_ERR_NO_DIR;
1183
    return FILE_ERR_NO_DIR;
1184
  }
1184
  }
1185
1185
1186
  prev_dirname[0] = 0;
1186
  prev_dirname[0] = 0;
1187
  while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
1187
  while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
1188
    if( de.fname[0] && de.fname[0] != '.' &&
1188
    if( de.fname[0] && de.fname[0] != '.' &&
1189
          (de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
1189
          (de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
1190
1190
1191
      #if DEBUG_VERBOSE_LEVEL >= 2
1191
      #if DEBUG_VERBOSE_LEVEL >= 2
1192
      DEBUG_MSG("--> %s\n", de.fname);
1192
      DEBUG_MSG("--> %s\n", de.fname);
1193
      #endif
1193
      #endif
1194
     
1194
     
1195
      if(dirname != NULL){
1195
      if(dirname != NULL){
1196
        char *p = (char *)&de.fname[0];
1196
        char *p = (char *)&de.fname[0];
1197
        int i;
1197
        int i;
1198
        u8 dirname_matches = 1;
1198
        u8 dirname_matches = 1;
1199
        char *p_check = dirname;
1199
        char *p_check = dirname;
1200
        for(i=0; i<8; ++i, p++) {
1200
        for(i=0; i<8; ++i, p++) {
1201
            if( *p != *p_check++ ) {
1201
            if( *p != *p_check++ ) {
1202
              dirname_matches = 0;
1202
              dirname_matches = 0;
1203
              break;
1203
              break;
1204
            }
1204
            }
1205
          if(!*p) break; //Both names end here
1205
          if(!*p) break; //Both names end here
1206
        }
1206
        }
1207
        if( dirname_matches ) {
1207
        if( dirname_matches ) {
1208
            return prev_dirname[0] ? 1 : 0; // We're done, was the last dirname valid?
1208
            return prev_dirname[0] ? 1 : 0; // We're done, was the last dirname valid?
1209
        }
1209
        }
1210
      }
1210
      }
1211
1211
1212
      // copy dirname into prev_dirname for next iteration
1212
      // copy dirname into prev_dirname for next iteration
1213
      memcpy((char *)prev_dirname, (char *)&de.fname[0], 9);
1213
      memcpy((char *)prev_dirname, (char *)&de.fname[0], 9);
1214
    }
1214
    }
1215
  }
1215
  }
1216
1216
1217
  // last file?
1217
  // last file?
1218
  if( dirname == NULL && prev_dirname[0] != 0 )
1218
  if( dirname == NULL && prev_dirname[0] != 0 )
1219
    return 1;
1219
    return 1;
1220
1220
1221
  prev_dirname[0] = 0; // set terminator (empty string)
1221
  prev_dirname[0] = 0; // set terminator (empty string)
1222
  return 0; // file not found
1222
  return 0; // file not found
1223
}
1223
}
1224
1224
1225
/////////////////////////////////////////////////////////////////////////////
1225
/////////////////////////////////////////////////////////////////////////////
1226
//! Returns a file next to the given filename with the given extension
1226
//! Returns a file next to the given filename with the given extension
1227
//! if filename == NULL, the first file will be returned in next_filename
1227
//! if filename == NULL, the first file will be returned in next_filename
1228
//! \param[in] path directory in which we want to search
1228
//! \param[in] path directory in which we want to search
1229
//! \param[in] filename current file (if NULL, the first file will be returned)
1229
//! \param[in] filename current file (if NULL, the first file will be returned)
1230
//! \param[in] ext_filter optional extension filter (if NULL: no extension)
1230
//! \param[in] ext_filter optional extension filter (if NULL: no extension)
1231
//! \param[out] next_filename the next file if return status is 1
1231
//! \param[out] next_filename the next file if return status is 1
1232
//! \return < 0 on errors (error codes are documented in file.h)
1232
//! \return < 0 on errors (error codes are documented in file.h)
1233
//! \return 1 if next file has been found
1233
//! \return 1 if next file has been found
1234
//! \return 0 if no additional file
1234
//! \return 0 if no additional file
1235
/////////////////////////////////////////////////////////////////////////////
1235
/////////////////////////////////////////////////////////////////////////////
1236
s32 FILE_FindNextFile(char *path, char *filename, char *ext_filter, char *next_filename)
1236
s32 FILE_FindNextFile(char *path, char *filename, char *ext_filter, char *next_filename)
1237
{
1237
{
1238
  s32 status = 0;
1238
  s32 status = 0;
1239
  DIR di;
1239
  DIR di;
1240
  FILINFO de;
1240
  FILINFO de;
1241
1241
1242
  if( !volume_available ) {
1242
  if( !volume_available ) {
1243
#if DEBUG_VERBOSE_LEVEL >= 2
1243
#if DEBUG_VERBOSE_LEVEL >= 2
1244
    DEBUG_MSG("[FILE_FindNextFile] ERROR: volume doesn't exist!\n");
1244
    DEBUG_MSG("[FILE_FindNextFile] ERROR: volume doesn't exist!\n");
1245
#endif
1245
#endif
1246
    return FILE_ERR_NO_VOLUME;
1246
    return FILE_ERR_NO_VOLUME;
1247
  }
1247
  }
1248
1248
1249
  if( f_opendir(&di, path) != FR_OK ) {
1249
  if( f_opendir(&di, path) != FR_OK ) {
1250
#if DEBUG_VERBOSE_LEVEL >= 2
1250
#if DEBUG_VERBOSE_LEVEL >= 2
1251
    DEBUG_MSG("[FILE_FindNextFile] ERROR: opening %s directory - please create it!\n", path);
1251
    DEBUG_MSG("[FILE_FindNextFile] ERROR: opening %s directory - please create it!\n", path);
1252
#endif
1252
#endif
1253
    return FILE_ERR_NO_DIR;
1253
    return FILE_ERR_NO_DIR;
1254
  }
1254
  }
1255
1255
1256
  u8 take_next = 0;
1256
  u8 take_next = 0;
1257
  while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
1257
  while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
1258
    if( de.fname[0] && de.fname[0] != '.' &&
1258
    if( de.fname[0] && de.fname[0] != '.' &&
1259
    !(de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
1259
    !(de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
1260
1260
1261
      char *p = (char *)&de.fname[0];
1261
      char *p = (char *)&de.fname[0];
1262
      int i;
1262
      int i;
1263
      u8 filename_matches = 1;
1263
      u8 filename_matches = 1;
1264
      char *p_check = filename;
1264
      char *p_check = filename;
1265
      for(i=0; i<9; ++i, p++) {
1265
      for(i=0; i<9; ++i, p++) {
1266
    if( p_check && *p != *p_check++ ) {
1266
    if( p_check && *p != *p_check++ ) {
1267
      filename_matches = 0;
1267
      filename_matches = 0;
1268
    }
1268
    }
1269
1269
1270
    if( *p == '.' )
1270
    if( *p == '.' )
1271
      break;
1271
      break;
1272
      }
1272
      }
1273
1273
1274
      if( ext_filter && *p++ != '.' )
1274
      if( ext_filter && *p++ != '.' )
1275
    continue;
1275
    continue;
1276
1276
1277
      if( ext_filter && strncasecmp(p, ext_filter, 3) != 0 )
1277
      if( ext_filter && strncasecmp(p, ext_filter, 3) != 0 )
1278
    continue;
1278
    continue;
1279
1279
1280
      if( take_next || filename == NULL ) {
1280
      if( take_next || filename == NULL ) {
1281
    memcpy((char *)next_filename, (char *)&de.fname[0], 13);
1281
    memcpy((char *)next_filename, (char *)&de.fname[0], 13);
1282
    return 1; // file found
1282
    return 1; // file found
1283
      }
1283
      }
1284
1284
1285
#if DEBUG_VERBOSE_LEVEL >= 2
1285
#if DEBUG_VERBOSE_LEVEL >= 2
1286
      DEBUG_MSG("--> %s\n", de.fname);
1286
      DEBUG_MSG("--> %s\n", de.fname);
1287
#endif
1287
#endif
1288
1288
1289
      if( filename_matches )
1289
      if( filename_matches )
1290
    take_next = 1;
1290
    take_next = 1;
1291
    }
1291
    }
1292
  }
1292
  }
1293
1293
1294
  next_filename[0] = 0; // set terminator (empty string)
1294
  next_filename[0] = 0; // set terminator (empty string)
1295
  return 0; // file not found
1295
  return 0; // file not found
1296
}
1296
}
1297
1297
1298
1298
1299
/////////////////////////////////////////////////////////////////////////////
1299
/////////////////////////////////////////////////////////////////////////////
1300
//! Returns a previous file of the given filename with the given extension
1300
//! Returns a previous file of the given filename with the given extension
1301
//! if filename == NULL, the last file will be returned in prev_filename
1301
//! if filename == NULL, the last file will be returned in prev_filename
1302
//! \param[in] path directory in which we want to search
1302
//! \param[in] path directory in which we want to search
1303
//! \param[in] filename current file (if NULL, the last file will be returned)
1303
//! \param[in] filename current file (if NULL, the last file will be returned)
1304
//! \param[in] ext_filter optional extension filter (if NULL: no extension)
1304
//! \param[in] ext_filter optional extension filter (if NULL: no extension)
1305
//! \param[out] prev_filename the previous file if return status is 1
1305
//! \param[out] prev_filename the previous file if return status is 1
1306
//! \return < 0 on errors (error codes are documented in file.h)
1306
//! \return < 0 on errors (error codes are documented in file.h)
1307
//! \return 1 if previous file has been found
1307
//! \return 1 if previous file has been found
1308
//! \return 0 if no additional file
1308
//! \return 0 if no additional file
1309
/////////////////////////////////////////////////////////////////////////////
1309
/////////////////////////////////////////////////////////////////////////////
1310
s32 FILE_FindPreviousFile(char *path, char *filename, char *ext_filter, char *prev_filename)
1310
s32 FILE_FindPreviousFile(char *path, char *filename, char *ext_filter, char *prev_filename)
1311
{
1311
{
1312
  s32 status = 0;
1312
  s32 status = 0;
1313
  DIR di;
1313
  DIR di;
1314
  FILINFO de;
1314
  FILINFO de;
1315
1315
1316
  if( !volume_available ) {
1316
  if( !volume_available ) {
1317
#if DEBUG_VERBOSE_LEVEL >= 2
1317
#if DEBUG_VERBOSE_LEVEL >= 2
1318
    DEBUG_MSG("[FILE_FindPreviousFile] ERROR: volume doesn't exist!\n");
1318
    DEBUG_MSG("[FILE_FindPreviousFile] ERROR: volume doesn't exist!\n");
1319
#endif
1319
#endif
1320
    return FILE_ERR_NO_VOLUME;
1320
    return FILE_ERR_NO_VOLUME;
1321
  }
1321
  }
1322
1322
1323
  if( f_opendir(&di, path) != FR_OK ) {
1323
  if( f_opendir(&di, path) != FR_OK ) {
1324
#if DEBUG_VERBOSE_LEVEL >= 2
1324
#if DEBUG_VERBOSE_LEVEL >= 2
1325
    DEBUG_MSG("[FILE_FindPreviousFile] ERROR: opening %s directory - please create it!\n", path);
1325
    DEBUG_MSG("[FILE_FindPreviousFile] ERROR: opening %s directory - please create it!\n", path);
1326
#endif
1326
#endif
1327
    return FILE_ERR_NO_DIR;
1327
    return FILE_ERR_NO_DIR;
1328
  }
1328
  }
1329
1329
1330
  prev_filename[0] = 0;
1330
  prev_filename[0] = 0;
1331
  while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
1331
  while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
1332
    if( de.fname[0] && de.fname[0] != '.' &&
1332
    if( de.fname[0] && de.fname[0] != '.' &&
1333
    !(de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
1333
    !(de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
1334
1334
1335
      char *p = (char *)&de.fname[0];
1335
      char *p = (char *)&de.fname[0];
1336
      int i;
1336
      int i;
1337
      u8 filename_matches = 1;
1337
      u8 filename_matches = 1;
1338
      char *p_check = filename;
1338
      char *p_check = filename;
1339
      for(i=0; i<9; ++i, p++) {
1339
      for(i=0; i<9; ++i, p++) {
1340
    if( p_check && *p != *p_check++ ) {
1340
    if( p_check && *p != *p_check++ ) {
1341
      filename_matches = 0;
1341
      filename_matches = 0;
1342
    }
1342
    }
1343
1343
1344
    if( *p == '.' )
1344
    if( *p == '.' )
1345
      break;
1345
      break;
1346
      }
1346
      }
1347
1347
1348
      if( ext_filter && *p++ != '.' )
1348
      if( ext_filter && *p++ != '.' )
1349
    continue;
1349
    continue;
1350
1350
1351
      if( ext_filter && strncasecmp(p, ext_filter, 3) != 0 )
1351
      if( ext_filter && strncasecmp(p, ext_filter, 3) != 0 )
1352
    continue;
1352
    continue;
1353
1353
1354
#if DEBUG_VERBOSE_LEVEL >= 2
1354
#if DEBUG_VERBOSE_LEVEL >= 2
1355
      DEBUG_MSG("--> %s\n", de.fname);
1355
      DEBUG_MSG("--> %s\n", de.fname);
1356
#endif
1356
#endif
1357
1357
1358
      if( p_check != NULL && filename_matches ) { // if not the last file should be returned
1358
      if( p_check != NULL && filename_matches ) { // if not the last file should be returned
1359
    return prev_filename[0] ? 1 : 0; // return this one
1359
    return prev_filename[0] ? 1 : 0; // return this one
1360
      }
1360
      }
1361
1361
1362
      // copy filename into prev_filename for next iteration
1362
      // copy filename into prev_filename for next iteration
1363
      memcpy((char *)prev_filename, (char *)&de.fname[0], 13);
1363
      memcpy((char *)prev_filename, (char *)&de.fname[0], 13);
1364
    }
1364
    }
1365
  }
1365
  }
1366
1366
1367
  // last file?
1367
  // last file?
1368
  if( filename == NULL && prev_filename[0] != 0 )
1368
  if( filename == NULL && prev_filename[0] != 0 )
1369
    return 1;
1369
    return 1;
1370
1370
1371
  prev_filename[0] = 0; // set terminator (empty string)
1371
  prev_filename[0] = 0; // set terminator (empty string)
1372
  return 0; // file not found
1372
  return 0; // file not found
1373
}
1373
}
1374
1374
1375
1375
1376
/////////////////////////////////////////////////////////////////////////////
1376
/////////////////////////////////////////////////////////////////////////////
1377
//! This function sends a .syx file to given MIDI out port
1377
//! This function sends a .syx file to given MIDI out port
1378
/////////////////////////////////////////////////////////////////////////////
1378
/////////////////////////////////////////////////////////////////////////////
1379
s32 FILE_SendSyxDump(char *path, mios32_midi_port_t port, u32 ms_delay_between_dumps)
1379
s32 FILE_SendSyxDump(char *path, mios32_midi_port_t port, u32 ms_delay_between_dumps)
1380
{
1380
{
1381
  s32 status = 0;
1381
  s32 status = 0;
1382
  u32 num_dumps = 0;
1382
  u32 num_dumps = 0;
1383
  file_t file;
1383
  file_t file;
1384
1384
1385
  if( !volume_available ) {
1385
  if( !volume_available ) {
1386
#if DEBUG_VERBOSE_LEVEL >= 2
1386
#if DEBUG_VERBOSE_LEVEL >= 2
1387
    DEBUG_MSG("[FILE_SendSyxDump] ERROR: volume doesn't exist!\n");
1387
    DEBUG_MSG("[FILE_SendSyxDump] ERROR: volume doesn't exist!\n");
1388
#endif
1388
#endif
1389
    return FILE_ERR_NO_VOLUME;
1389
    return FILE_ERR_NO_VOLUME;
1390
  }
1390
  }
1391
1391
1392
#if DEBUG_VERBOSE_LEVEL >= 2
1392
#if DEBUG_VERBOSE_LEVEL >= 2
1393
  DEBUG_MSG("[FILE_SendSyxDump] Open file '%s'\n", path);
1393
  DEBUG_MSG("[FILE_SendSyxDump] Open file '%s'\n", path);
1394
#endif
1394
#endif
1395
1395
1396
  if( (status=FILE_ReadOpen(&file, path)) < 0 ) {
1396
  if( (status=FILE_ReadOpen(&file, path)) < 0 ) {
1397
#if DEBUG_VERBOSE_LEVEL >= 2
1397
#if DEBUG_VERBOSE_LEVEL >= 2
1398
    DEBUG_MSG("[FILE_SendSyxDump] failed to open file, status: %d\n", status);
1398
    DEBUG_MSG("[FILE_SendSyxDump] failed to open file, status: %d\n", status);
1399
#endif
1399
#endif
1400
    return status;
1400
    return status;
1401
  }
1401
  }
1402
1402
1403
  // stream SysEx to MIDI port
1403
  // stream SysEx to MIDI port
1404
  UINT successcount;
1404
  UINT successcount;
1405
  u32 num_bytes = 0;
1405
  u32 num_bytes = 0;
1406
  do {
1406
  do {
1407
    if( (file_dfs_errno=f_read(&file_read, tmp_buffer, TMP_BUFFER_SIZE, &successcount)) != FR_OK ) {
1407
    if( (file_dfs_errno=f_read(&file_read, tmp_buffer, TMP_BUFFER_SIZE, &successcount)) != FR_OK ) {
1408
#if DEBUG_VERBOSE_LEVEL >= 2
1408
#if DEBUG_VERBOSE_LEVEL >= 2
1409
      DEBUG_MSG("[FILE] Failed to read sector at position 0x%08x, status: %u\n", file_read.fptr, file_dfs_errno);
1409
      DEBUG_MSG("[FILE] Failed to read sector at position 0x%08x, status: %u\n", file_read.fptr, file_dfs_errno);
1410
#endif
1410
#endif
1411
      successcount = 0;
1411
      successcount = 0;
1412
      status = FILE_ERR_SYSEX_READ;
1412
      status = FILE_ERR_SYSEX_READ;
1413
    } else if( successcount ) {
1413
    } else if( successcount ) {
1414
      // ensure that only a single sysex string is sent
1414
      // ensure that only a single sysex string is sent
1415
      // if buffer contains multiple strings, continue file read at the next F0
1415
      // if buffer contains multiple strings, continue file read at the next F0
1416
      u32 len = (tmp_buffer[0] >= 0x80) ? 1 : 0;
1416
      u32 len = (tmp_buffer[0] >= 0x80) ? 1 : 0;
1417
      u8 *ptr = (u8 *)&tmp_buffer[len];
1417
      u8 *ptr = (u8 *)&tmp_buffer[len];
1418
      for(; len<successcount; ++len, ++ptr) {
1418
      for(; len<successcount; ++len, ++ptr) {
1419
    if( *ptr >= 0x80 && *ptr != 0xf7 ) // like "== 0xf0", but we also consider unusual content, such as CCs, Notes, etc...
1419
    if( *ptr >= 0x80 && *ptr != 0xf7 ) // like "== 0xf0", but we also consider unusual content, such as CCs, Notes, etc...
1420
      break;
1420
      break;
1421
      }
1421
      }
1422
#if DEBUG_VERBOSE_LEVEL >= 2
1422
#if DEBUG_VERBOSE_LEVEL >= 2
1423
      MIOS32_MIDI_SendDebugHexDump(tmp_buffer, len);
1423
      MIOS32_MIDI_SendDebugHexDump(tmp_buffer, len);
1424
#endif
1424
#endif
1425
      ++num_dumps;
1425
      ++num_dumps;
1426
#ifndef MIOS32_FAMILY_EMULATION
1426
#ifndef MIOS32_FAMILY_EMULATION
1427
      if( ms_delay_between_dumps > 0 && num_dumps > 1 ) {
1427
      if( ms_delay_between_dumps > 0 && num_dumps > 1 ) {
1428
    // insert delay between the Syx dumps
1428
    // insert delay between the Syx dumps
1429
    vTaskDelay(ms_delay_between_dumps);
1429
    vTaskDelay(ms_delay_between_dumps);
1430
    taskYIELD();
1430
    taskYIELD();
1431
      }
1431
      }
1432
#endif
1432
#endif
1433
1433
1434
      MIOS32_MIDI_SendSysEx(port, tmp_buffer, len);
1434
      MIOS32_MIDI_SendSysEx(port, tmp_buffer, len);
1435
      num_bytes += len;
1435
      num_bytes += len;
1436
1436
1437
      if( len != successcount ) {
1437
      if( len != successcount ) {
1438
    FILE_ReadSeek(num_bytes);
1438
    FILE_ReadSeek(num_bytes);
1439
      }
1439
      }
1440
    }
1440
    }
1441
  } while( status == 0 && successcount > 0 );
1441
  } while( status == 0 && successcount > 0 );
1442
1442
1443
#if DEBUG_VERBOSE_LEVEL >= 2
1443
#if DEBUG_VERBOSE_LEVEL >= 2
1444
  DEBUG_MSG("[FILE_SendSyxDump] sent %d bytes!\n", num_bytes);
1444
  DEBUG_MSG("[FILE_SendSyxDump] sent %d bytes!\n", num_bytes);
1445
#endif
1445
#endif
1446
1446
1447
  // close file
1447
  // close file
1448
  status |= FILE_ReadClose(&file);
1448
  status |= FILE_ReadClose(&file);
1449
1449
1450
  if( status < 0 ) {
1450
  if( status < 0 ) {
1451
#if DEBUG_VERBOSE_LEVEL >= 1
1451
#if DEBUG_VERBOSE_LEVEL >= 1
1452
    DEBUG_MSG("[FILE_SendSyxDump] ERROR while reading file, status: %d\n", status);
1452
    DEBUG_MSG("[FILE_SendSyxDump] ERROR while reading file, status: %d\n", status);
1453
#endif
1453
#endif
1454
    return FILE_ERR_SYSEX_READ;
1454
    return FILE_ERR_SYSEX_READ;
1455
  }
1455
  }
1456
1456
1457
  return num_bytes;
1457
  return num_bytes;
1458
}
1458
}
1459
1459
1460
1460
1461
/////////////////////////////////////////////////////////////////////////////
1461
/////////////////////////////////////////////////////////////////////////////
1462
// Creates a tar file (recursively)
1462
// Creates a tar file (recursively)
1463
/////////////////////////////////////////////////////////////////////////////
1463
/////////////////////////////////////////////////////////////////////////////
1464
s32 FILE_CreateTar(char *filename, char *src_path, u8 exclude_tar_files, u8 max_depth)
1464
s32 FILE_CreateTar(char *filename, char *src_path, u8 exclude_tar_files, u8 max_depth)
1465
{
1465
{
1466
  s32 status = 0;
1466
  s32 status = 0;
1467
1467
1468
  if( !volume_available ) {
1468
  if( !volume_available ) {
1469
#if DEBUG_VERBOSE_LEVEL >= 2
1469
#if DEBUG_VERBOSE_LEVEL >= 2
1470
    DEBUG_MSG("[FILE_CreateTar] ERROR: volume doesn't exist!\n");
1470
    DEBUG_MSG("[FILE_CreateTar] ERROR: volume doesn't exist!\n");
1471
#endif
1471
#endif
1472
    return FILE_ERR_NO_VOLUME;
1472
    return FILE_ERR_NO_VOLUME;
1473
  }
1473
  }
1474
1474
1475
  // convert filename to uppercase
1475
  // convert filename to uppercase
1476
  {
1476
  {
1477
    char *filename_ptr = filename;
1477
    char *filename_ptr = filename;
1478
    while( *filename_ptr != 0 ) {
1478
    while( *filename_ptr != 0 ) {
1479
      *filename_ptr = toupper((int)*filename_ptr);
1479
      *filename_ptr = toupper((int)*filename_ptr);
1480
      ++filename_ptr;
1480
      ++filename_ptr;
1481
    }
1481
    }
1482
  }
1482
  }
1483
1483
1484
  // create file
1484
  // create file
1485
  if( (status=FILE_WriteOpen(filename, 1)) < 0 ) {
1485
  if( (status=FILE_WriteOpen(filename, 1)) < 0 ) {
1486
#if DEBUG_VERBOSE_LEVEL >= 1
1486
#if DEBUG_VERBOSE_LEVEL >= 1
1487
    DEBUG_MSG("[FILE_CreateTar] ERROR: failed to create %s (error code: %d)!\n", filename, status);
1487
    DEBUG_MSG("[FILE_CreateTar] ERROR: failed to create %s (error code: %d)!\n", filename, status);
1488
#endif
1488
#endif
1489
    return status;
1489
    return status;
1490
  }
1490
  }
1491
1491
1492
#if DEBUG_VERBOSE_LEVEL >= 1
1492
#if DEBUG_VERBOSE_LEVEL >= 1
1493
  DEBUG_MSG("[FILE_CreateTar] Creating %s for path: %s\n", filename, src_path);
1493
  DEBUG_MSG("[FILE_CreateTar] Creating %s for path: %s\n", filename, src_path);
1494
#endif
1494
#endif
1495
1495
1496
  // walk directory
1496
  // walk directory
1497
  u32 num_dirs = 1;
1497
  u32 num_dirs = 1;
1498
  u32 num_files = 0;
1498
  u32 num_files = 0;
1499
  status = FILE_CreateTarRecursive(filename, src_path, exclude_tar_files, 1, max_depth, &num_dirs, &num_files);
1499
  status = FILE_CreateTarRecursive(filename, src_path, exclude_tar_files, 1, max_depth, &num_dirs, &num_files);
1500
1500
1501
  if( status < 0 ) {
1501
  if( status < 0 ) {
1502
    DEBUG_MSG("[FILE_CreateTar] failed with error code: %d\n", status);
1502
    DEBUG_MSG("[FILE_CreateTar] failed with error code: %d\n", status);
1503
  } else {
1503
  } else {
1504
#if DEBUG_VERBOSE_LEVEL >= 1
1504
#if DEBUG_VERBOSE_LEVEL >= 1
1505
    DEBUG_MSG("[FILE_CreateTar] archived %d files in %d directories under %s (%d bytes)\n", num_dirs, num_files, filename, FILE_WriteGetCurrentSize());
1505
    DEBUG_MSG("[FILE_CreateTar] archived %d files in %d directories under %s (%d bytes)\n", num_files, num_dirs, filename, FILE_WriteGetCurrentSize());
1506
#endif
1506
#endif
1507
  }
1507
  }
1508
1508
1509
  // finalize file by adding two dummy all-zero blocks
1509
  // finalize file by adding two dummy all-zero blocks
1510
  {
1510
  {
1511
    u8 dummy[512];
1511
    u8 dummy[512];
1512
    memset(dummy, 0, 512);
1512
    memset(dummy, 0, 512);
1513
1513
1514
    int i;
1514
    int i;
1515
    for(i=0; i<2; ++i) {
1515
    for(i=0; i<2; ++i) {
1516
      UINT successcount;  
1516
      UINT successcount;  
1517
      if( (file_dfs_errno=f_write(&file_write, &dummy, 512, &successcount)) != FR_OK || successcount != 512 ) {
1517
      if( (file_dfs_errno=f_write(&file_write, &dummy, 512, &successcount)) != FR_OK || successcount != 512 ) {
1518
#if DEBUG_VERBOSE_LEVEL >= 1
1518
#if DEBUG_VERBOSE_LEVEL >= 1
1519
    DEBUG_MSG("[FILE_CreateTar] Failed to write sector at position 0x%08x, status: %u\n", file_write.fptr, file_dfs_errno);
1519
    DEBUG_MSG("[FILE_CreateTar] Failed to write sector at position 0x%08x, status: %u\n", file_write.fptr, file_dfs_errno);
1520
#endif
1520
#endif
1521
    status = FILE_ERR_WRITE;
1521
    status = FILE_ERR_WRITE;
1522
      }
1522
      }
1523
    }
1523
    }
1524
  }
1524
  }
1525
1525
1526
  FILE_WriteClose();
1526
  FILE_WriteClose();
1527
 
1527
 
1528
  return status;
1528
  return status;
1529
}
1529
}
1530
1530
1531
1531
1532
static s32 FILE_CreateTarHeader(char *filename, char *src_path, u8 is_dir, u32 filesize)
1532
static s32 FILE_CreateTarHeader(char *filename, char *src_path, u8 is_dir, u32 filesize)
1533
{
1533
{
1534
  s32 status = 0;
1534
  s32 status = 0;
1535
  tar_posix_header *header;
1535
  tar_posix_header *header;
1536
  header = (tar_posix_header *)&tmp_buffer;
1536
  header = (tar_posix_header *)&tmp_buffer;
1537
1537
1538
#if TMP_BUFFER_SIZE != 512
1538
#if TMP_BUFFER_SIZE != 512
1539
# error "We've a problem here!"
1539
# error "We've a problem here!"
1540
#endif
1540
#endif
1541
1541
1542
  memset(header, 0, sizeof(header));
1542
  memset(header, 0, sizeof(header));
1543
1543
1544
  strncpy(header->name, &filename[1], strlen(filename)-5); // remove initial / and .tar
1544
  strncpy(header->name, &filename[1], strlen(filename)-5); // remove initial / and .tar
1545
  header->name[strlen(filename)-5] = 0;
1545
  header->name[strlen(filename)-5] = 0;
1546
  strcat(header->name, src_path);
1546
  strcat(header->name, src_path);
1547
  if( is_dir ) {
1547
  if( is_dir ) {
1548
    strcat(header->name, "/");
1548
    strcat(header->name, "/");
1549
  }
1549
  }
1550
1550
1551
  strcpy(header->mode, is_dir ? "000755 " : "000644 ");
1551
  strcpy(header->mode, is_dir ? "000755 " : "000644 ");
1552
  strcpy(header->uid, "000000 ");
1552
  strcpy(header->uid, "000000 ");
1553
  strcpy(header->gid, "000000 ");
1553
  strcpy(header->gid, "000000 ");
1554
1554
1555
  // filesize in octal format
1555
  // filesize in octal format
1556
  {
1556
  {
1557
    int i;
1557
    int i;
1558
    for(i=0; i<11; ++i) {
1558
    for(i=0; i<11; ++i) {
1559
      header->size[i] = '0' + ((filesize >> 3*(10-i)) & 0x7);
1559
      header->size[i] = '0' + ((filesize >> 3*(10-i)) & 0x7);
1560
    }
1560
    }
1561
    header->size[11] = ' ';
1561
    header->size[11] = ' ';
1562
  }
1562
  }
1563
1563
1564
  strcpy(header->mtime, "00000000000 ");
1564
  strcpy(header->mtime, "00000000000 ");
1565
  strcat(header->chksum, "        "); // will be calculated once header is complete
1565
  strcat(header->chksum, "        "); // will be calculated once header is complete
1566
  header->typeflag = is_dir ? '5' : '0';
1566
  header->typeflag = is_dir ? '5' : '0';
1567
  //strcpy(header->linkname, "");
1567
  //strcpy(header->linkname, "");
1568
  strcpy(header->magic, "ustar");
1568
  strcpy(header->magic, "ustar");
1569
  strcpy(header->version, "00");
1569
  strcpy(header->version, "00");
1570
  strcpy(header->uname, "mios32");
1570
  strcpy(header->uname, "mios32");
1571
  strcpy(header->gname, "mios32");
1571
  strcpy(header->gname, "mios32");
1572
  strcat(header->devmajor, "000000 ");
1572
  strcat(header->devmajor, "000000 ");
1573
  strcpy(header->devminor, "000000 ");
1573
  strcpy(header->devminor, "000000 ");
1574
  //strcpy(header->prefix, "");
1574
  //strcpy(header->prefix, "");
1575
1575
1576
  {
1576
  {
1577
    u32 chksum = 0;
1577
    u32 chksum = 0;
1578
    int i;
1578
    int i;
1579
    u8 *header_ptr = (u8 *)header;
1579
    u8 *header_ptr = (u8 *)header;
1580
    for(i=0; i<512; ++i, header_ptr++) {
1580
    for(i=0; i<512; ++i, header_ptr++) {
1581
      chksum += *header_ptr;
1581
      chksum += *header_ptr;
1582
    }
1582
    }
1583
1583
1584
    // checksum in octal format
1584
    // checksum in octal format
1585
    for(i=0; i<6; ++i) {
1585
    for(i=0; i<6; ++i) {
1586
      header->chksum[i] = '0' + ((chksum >> 3*(5-i)) & 0x7);
1586
      header->chksum[i] = '0' + ((chksum >> 3*(5-i)) & 0x7);
1587
    }
1587
    }
1588
    header->chksum[6] = 0;
1588
    header->chksum[6] = 0;
1589
  }
1589
  }
1590
1590
1591
1591
1592
  UINT successcount;  
1592
  UINT successcount;  
1593
  if( (file_dfs_errno=f_write(&file_write, header, 512, &successcount)) != FR_OK || successcount != 512 ) {
1593
  if( (file_dfs_errno=f_write(&file_write, header, 512, &successcount)) != FR_OK || successcount != 512 ) {
1594
#if DEBUG_VERBOSE_LEVEL >= 1
1594
#if DEBUG_VERBOSE_LEVEL >= 1
1595
    DEBUG_MSG("[FILE_CreateTarHeader] Failed to write sector at position 0x%08x, status: %u\n", file_write.fptr, file_dfs_errno);
1595
    DEBUG_MSG("[FILE_CreateTarHeader] Failed to write sector at position 0x%08x, status: %u\n", file_write.fptr, file_dfs_errno);
1596
#endif
1596
#endif
1597
    status = FILE_ERR_WRITE;
1597
    status = FILE_ERR_WRITE;
1598
  }
1598
  }
1599
1599
1600
  return status;
1600
  return status;
1601
}
1601
}
1602
1602
1603
static s32 FILE_CreateTarRecursive(char *filename, char *src_path, u8 exclude_tar_files, u8 depth, u8 max_depth, u32 *num_dirs, u32 *num_files)
1603
static s32 FILE_CreateTarRecursive(char *filename, char *src_path, u8 exclude_tar_files, u8 depth, u8 max_depth, u32 *num_dirs, u32 *num_files)
1604
{
1604
{
1605
  s32 status = 0;
1605
  s32 status = 0;
1606
1606
1607
  DIR di;
1607
  DIR di;
1608
  FILINFO de;
1608
  FILINFO de;
1609
1609
1610
  // format from https://www.gnu.org/software/tar/manual/html_node/Standard.html
1610
  // format from https://www.gnu.org/software/tar/manual/html_node/Standard.html
1611
1611
1612
  if( f_opendir(&di, src_path) != FR_OK ) {
1612
  if( f_opendir(&di, src_path) != FR_OK ) {
1613
#if DEBUG_VERBOSE_LEVEL >= 1
1613
#if DEBUG_VERBOSE_LEVEL >= 1
1614
    DEBUG_MSG("[FILE_CreateTar] ERROR: couldn't open %s directory!\n", src_path);
1614
    DEBUG_MSG("[FILE_CreateTar] ERROR: couldn't open %s directory!\n", src_path);
1615
#endif
1615
#endif
1616
    return FILE_ERR_NO_DIR;
1616
    return FILE_ERR_NO_DIR;
1617
  }
1617
  }
1618
1618
1619
  // create header for new directory
1619
  // create header for new directory
1620
  if( (status=FILE_CreateTarHeader(filename, src_path, 1, 0)) < 0 ) {
1620
  if( (status=FILE_CreateTarHeader(filename, src_path, 1, 0)) < 0 ) {
1621
    return status;
1621
    return status;
1622
  }
1622
  }
1623
1623
1624
  while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
1624
  while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
1625
    char full_path[13 * (max_depth+1) + 1];
1625
    char full_path[13 * (max_depth+1) + 1];
1626
    sprintf(full_path, "%s/%s", src_path, de.fname);
1626
    sprintf(full_path, "%s/%s", src_path, de.fname);
1627
1627
1628
    if( de.fname[0] && de.fname[0] != '.' ) {
1628
    if( de.fname[0] && de.fname[0] != '.' ) {
1629
      if( (de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
1629
      if( (de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
1630
    *num_dirs += 1;
1630
    *num_dirs += 1;
1631
1631
1632
#if DEBUG_VERBOSE_LEVEL >= 1
1632
#if DEBUG_VERBOSE_LEVEL >= 1
1633
    DEBUG_MSG("[FILE_CreateTar] D %s\n", full_path);
1633
    DEBUG_MSG("[FILE_CreateTar] D %s\n", full_path);
1634
#endif
1634
#endif
1635
    if( depth >= max_depth ) {
1635
    if( depth >= max_depth ) {
1636
#if DEBUG_VERBOSE_LEVEL >= 1
1636
#if DEBUG_VERBOSE_LEVEL >= 1
1637
      DEBUG_MSG("[FILE_CreateTar] Maximum depth of %d reached - won't go down further!\n", max_depth);
1637
      DEBUG_MSG("[FILE_CreateTar] Maximum depth of %d reached - won't go down further!\n", max_depth);
1638
#endif
1638
#endif
1639
    } else {
1639
    } else {
1640
      status = FILE_CreateTarRecursive(filename, full_path, exclude_tar_files, depth+1, max_depth, num_dirs, num_files);
1640
      status = FILE_CreateTarRecursive(filename, full_path, exclude_tar_files, depth+1, max_depth, num_dirs, num_files);
1641
      if( status < 0 )
1641
      if( status < 0 )
1642
        break;
1642
        break;
1643
    }
1643
    }
1644
      } else if( !(de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
1644
      } else if( !(de.fattrib & AM_DIR) && !(de.fattrib & AM_HID) ) {
1645
    if( strcasecmp(de.fname, (char *)&filename[1]) == 0 ) {
1645
    if( strcasecmp(de.fname, (char *)&filename[1]) == 0 ) {
1646
#if DEBUG_VERBOSE_LEVEL >= 1
1646
#if DEBUG_VERBOSE_LEVEL >= 1
1647
      DEBUG_MSG("[FILE_CreateTar] Skip %s (same file)\n", full_path);
1647
      DEBUG_MSG("[FILE_CreateTar] Skip %s (same file)\n", full_path);
1648
#endif
1648
#endif
1649
    } else if( exclude_tar_files && strcasestr(de.fname, ".TAR") != 0 ) {
1649
    } else if( exclude_tar_files && strcasestr(de.fname, ".TAR") != 0 ) {
1650
#if DEBUG_VERBOSE_LEVEL >= 1
1650
#if DEBUG_VERBOSE_LEVEL >= 1
1651
      DEBUG_MSG("[FILE_CreateTar] Skip %s\n", full_path);
1651
      DEBUG_MSG("[FILE_CreateTar] Skip %s\n", full_path);
1652
#endif
1652
#endif
1653
    } else {
1653
    } else {
1654
      *num_files += 1;
1654
      *num_files += 1;
1655
#if DEBUG_VERBOSE_LEVEL >= 1
1655
#if DEBUG_VERBOSE_LEVEL >= 1
1656
      DEBUG_MSG("[FILE_CreateTar] F %s (%d bytes)\n", full_path, de.fsize);
1656
      DEBUG_MSG("[FILE_CreateTar] F %s (%d bytes)\n", full_path, de.fsize);
1657
#endif
1657
#endif
1658
1658
1659
      // create header for new file
1659
      // create header for new file
1660
      if( (status=FILE_CreateTarHeader(filename, full_path, 0, de.fsize)) < 0 ) {
1660
      if( (status=FILE_CreateTarHeader(filename, full_path, 0, de.fsize)) < 0 ) {
1661
        return status;
1661
        return status;
1662
      }
1662
      }
1663
1663
1664
      // copy file
1664
      // copy file
1665
      if( (file_dfs_errno=f_open(&file_read, full_path, FA_OPEN_EXISTING | FA_READ)) != FR_OK ) {
1665
      if( (file_dfs_errno=f_open(&file_read, full_path, FA_OPEN_EXISTING | FA_READ)) != FR_OK ) {
1666
#if DEBUG_VERBOSE_LEVEL >= 1
1666
#if DEBUG_VERBOSE_LEVEL >= 1
1667
        DEBUG_MSG("[FILE_CreateTar] Failed to open %s!\n", full_path);
1667
        DEBUG_MSG("[FILE_CreateTar] Failed to open %s!\n", full_path);
1668
#endif
1668
#endif
1669
        return FILE_ERR_COPY_NO_FILE;
1669
        return FILE_ERR_COPY_NO_FILE;
1670
      }
1670
      }
1671
1671
1672
      UINT successcount;
1672
      UINT successcount;
1673
      UINT successcount_wr;
1673
      UINT successcount_wr;
1674
      u32 num_bytes = 0;
1674
      u32 num_bytes = 0;
1675
      do {
1675
      do {
1676
        if( (file_dfs_errno=f_read(&file_read, tmp_buffer, TMP_BUFFER_SIZE, &successcount)) != FR_OK ) {
1676
        if( (file_dfs_errno=f_read(&file_read, tmp_buffer, TMP_BUFFER_SIZE, &successcount)) != FR_OK ) {
1677
#if DEBUG_VERBOSE_LEVEL >= 1
1677
#if DEBUG_VERBOSE_LEVEL >= 1
1678
          DEBUG_MSG("[FILE_CreateTar] Failed to read sector at position 0x%08x, status: %u\n", file_read.fptr, file_dfs_errno);
1678
          DEBUG_MSG("[FILE_CreateTar] Failed to read sector at position 0x%08x, status: %u\n", file_read.fptr, file_dfs_errno);
1679
#endif
1679
#endif
1680
          successcount = 0;
1680
          successcount = 0;
1681
          status = FILE_ERR_READ;
1681
          status = FILE_ERR_READ;
1682
        } else if( successcount && (file_dfs_errno=f_write(&file_write, tmp_buffer, successcount, &successcount_wr)) != FR_OK ) {
1682
        } else if( successcount && (file_dfs_errno=f_write(&file_write, tmp_buffer, successcount, &successcount_wr)) != FR_OK ) {
1683
#if DEBUG_VERBOSE_LEVEL >= 1
1683
#if DEBUG_VERBOSE_LEVEL >= 1
1684
          DEBUG_MSG("[FILE_CreateTar] Failed to write sector at position 0x%08x, status: %u\n", file_write.fptr, file_dfs_errno);
1684
          DEBUG_MSG("[FILE_CreateTar] Failed to write sector at position 0x%08x, status: %u\n", file_write.fptr, file_dfs_errno);
1685
#endif
1685
#endif
1686
          status = FILE_ERR_WRITE;
1686
          status = FILE_ERR_WRITE;
1687
        } else {
1687
        } else {
1688
          num_bytes += successcount_wr;
1688
          num_bytes += successcount_wr;
1689
        }
1689
        }
1690
      } while( status == 0 && successcount > 0 );
1690
      } while( status == 0 && successcount > 0 );
1691
1691
1692
      if( status >= 0 && (de.fsize % 512) != 0 ) {
1692
      if( status >= 0 && (de.fsize % 512) != 0 ) {
1693
        // fill remaining space
1693
        // fill remaining space
1694
        memset(tmp_buffer, 0, 512);
1694
        memset(tmp_buffer, 0, 512);
1695
        if( (file_dfs_errno=f_write(&file_write, tmp_buffer, 512 - (de.fsize % 512), &successcount_wr)) != FR_OK ) {
1695
        if( (file_dfs_errno=f_write(&file_write, tmp_buffer, 512 - (de.fsize % 512), &successcount_wr)) != FR_OK ) {
1696
#if DEBUG_VERBOSE_LEVEL >= 1
1696
#if DEBUG_VERBOSE_LEVEL >= 1
1697
          DEBUG_MSG("[FILE_CreateTar] Failed to write sector at position 0x%08x, status: %u\n", file_write.fptr, file_dfs_errno);
1697
          DEBUG_MSG("[FILE_CreateTar] Failed to write sector at position 0x%08x, status: %u\n", file_write.fptr, file_dfs_errno);
1698
#endif
1698
#endif
1699
          status = FILE_ERR_WRITE;
1699
          status = FILE_ERR_WRITE;
1700
        }
1700
        }
1701
      }
1701
      }
1702
1702
1703
      //f_close(&file_read); // never close read files to avoid "invalid object"
1703
      //f_close(&file_read); // never close read files to avoid "invalid object"
1704
1704
1705
      if( status < 0 )
1705
      if( status < 0 )
1706
        break;
1706
        break;
1707
    }
1707
    }
1708
      }
1708
      }
1709
    }
1709
    }
1710
  }
1710
  }
1711
1711
1712
  return status;
1712
  return status;
1713
}
1713
}
1714
1714
1715
1715
1716
/////////////////////////////////////////////////////////////////////////////
1716
/////////////////////////////////////////////////////////////////////////////
1717
//! This function creates a backup file of the entire disk (except .tar files)
1717
//! This function creates a backup file of the entire disk (except .tar files)
1718
//! Use this function to automatically determine the next backup file name
1718
//! Use this function to automatically determine the next backup file name
1719
//! Backup files are starting with "bak<number>.tar"
1719
//! Backup files are starting with "bak<number>.tar"
1720
/////////////////////////////////////////////////////////////////////////////
1720
/////////////////////////////////////////////////////////////////////////////
1721
s32 FILE_BackupDiskAutoName(u8 max_depth)
1721
s32 FILE_BackupDiskAutoName(u8 max_depth)
1722
{
1722
{
1723
  int i;
1723
  int i;
1724
  for(i=1;;++i) {
1724
  for(i=1;;++i) {
1725
    char filename[20];
1725
    char filename[20];
1726
    sprintf(filename, "/bak%d.tar", i);
1726
    sprintf(filename, "/bak%d.tar", i);
1727
    s32 status = FILE_FileExists(filename);
1727
    s32 status = FILE_FileExists(filename);
1728
    if( status < 0 ) {
1728
    if( status < 0 ) {
1729
#if DEBUG_VERBOSE_LEVEL >= 2
1729
#if DEBUG_VERBOSE_LEVEL >= 2
1730
      DEBUG_MSG("[FILE_BackupDiskAutoName] ERROR: during disk access, error code: %d!\n", status);
1730
      DEBUG_MSG("[FILE_BackupDiskAutoName] ERROR: during disk access, error code: %d!\n", status);
1731
#endif
1731
#endif
1732
      return status;
1732
      return status;
1733
    }
1733
    }
1734
1734
1735
    if( status == 0 ) {
1735
    if( status == 0 ) {
1736
      return FILE_CreateTar(filename, "", 1, max_depth);
1736
      return FILE_CreateTar(filename, "", 1, max_depth);
1737
    }
1737
    }
1738
  }
1738
  }
1739
1739
1740
  return 0; // no error
1740
  return 0; // no error
1741
}
1741
}
1742
1742
1743
/////////////////////////////////////////////////////////////////////////////
1743
/////////////////////////////////////////////////////////////////////////////
1744
//! This function prints some useful SD card informations on the MIOS terminal
1744
//! This function prints some useful SD card informations on the MIOS terminal
1745
/////////////////////////////////////////////////////////////////////////////
1745
/////////////////////////////////////////////////////////////////////////////
1746
s32 FILE_PrintSDCardInfos(void)
1746
s32 FILE_PrintSDCardInfos(void)
1747
{
1747
{
1748
  int status = 0;
1748
  int status = 0;
1749
1749
1750
  // read CID data
1750
  // read CID data
1751
  mios32_sdcard_cid_t cid;
1751
  mios32_sdcard_cid_t cid;
1752
  if( (status=MIOS32_SDCARD_CIDRead(&cid)) < 0 ) {
1752
  if( (status=MIOS32_SDCARD_CIDRead(&cid)) < 0 ) {
1753
    DEBUG_MSG("ERROR: Reading CID failed with status %d!\n", status);
1753
    DEBUG_MSG("ERROR: Reading CID failed with status %d!\n", status);
1754
    // continue regardless if we got an error or not...
1754
    // continue regardless if we got an error or not...
1755
  } else {
1755
  } else {
1756
    DEBUG_MSG("--------------------\n");
1756
    DEBUG_MSG("--------------------\n");
1757
    DEBUG_MSG("CID:\n");
1757
    DEBUG_MSG("CID:\n");
1758
    DEBUG_MSG("- ManufacturerID:\n", cid.ManufacturerID);
1758
    DEBUG_MSG("- ManufacturerID:\n", cid.ManufacturerID);
1759
    DEBUG_MSG("- OEM AppliID:\n", cid.OEM_AppliID);
1759
    DEBUG_MSG("- OEM AppliID:\n", cid.OEM_AppliID);
1760
    DEBUG_MSG("- ProdName: %s\n", cid.ProdName);
1760
    DEBUG_MSG("- ProdName: %s\n", cid.ProdName);
1761
    DEBUG_MSG("- ProdRev: %u\n", cid.ProdRev);
1761
    DEBUG_MSG("- ProdRev: %u\n", cid.ProdRev);
1762
    DEBUG_MSG("- ProdSN: 0x%08x\n", cid.ProdSN);
1762
    DEBUG_MSG("- ProdSN: 0x%08x\n", cid.ProdSN);
1763
    DEBUG_MSG("- Reserved1: %u\n", cid.Reserved1);
1763
    DEBUG_MSG("- Reserved1: %u\n", cid.Reserved1);
1764
    DEBUG_MSG("- ManufactDate: %u\n", cid.ManufactDate);
1764
    DEBUG_MSG("- ManufactDate: %u\n", cid.ManufactDate);
1765
    DEBUG_MSG("- msd_CRC: 0x%02x\n", cid.msd_CRC);
1765
    DEBUG_MSG("- msd_CRC: 0x%02x\n", cid.msd_CRC);
1766
    DEBUG_MSG("- Reserved2: %u\n", cid.Reserved2);
1766
    DEBUG_MSG("- Reserved2: %u\n", cid.Reserved2);
1767
    DEBUG_MSG("--------------------\n");
1767
    DEBUG_MSG("--------------------\n");
1768
  }
1768
  }
1769
1769
1770
1770
1771
  // read CSD data
1771
  // read CSD data
1772
  mios32_sdcard_csd_t csd;
1772
  mios32_sdcard_csd_t csd;
1773
  if( (status=MIOS32_SDCARD_CSDRead(&csd)) < 0 ) {
1773
  if( (status=MIOS32_SDCARD_CSDRead(&csd)) < 0 ) {
1774
    DEBUG_MSG("ERROR: Reading CSD failed with status %d!\n", status);
1774
    DEBUG_MSG("ERROR: Reading CSD failed with status %d!\n", status);
1775
    // continue regardless if we got an error or not...
1775
    // continue regardless if we got an error or not...
1776
  } else {
1776
  } else {
1777
    DEBUG_MSG("--------------------\n");
1777
    DEBUG_MSG("--------------------\n");
1778
    DEBUG_MSG("- CSDStruct: %u\n", csd.CSDStruct);
1778
    DEBUG_MSG("- CSDStruct: %u\n", csd.CSDStruct);
1779
    DEBUG_MSG("- SysSpecVersion: %u\n", csd.SysSpecVersion);
1779
    DEBUG_MSG("- SysSpecVersion: %u\n", csd.SysSpecVersion);
1780
    DEBUG_MSG("- Reserved1: %u\n", csd.Reserved1);
1780
    DEBUG_MSG("- Reserved1: %u\n", csd.Reserved1);
1781
    DEBUG_MSG("- TAAC: %u\n", csd.TAAC);
1781
    DEBUG_MSG("- TAAC: %u\n", csd.TAAC);
1782
    DEBUG_MSG("- NSAC: %u\n", csd.NSAC);
1782
    DEBUG_MSG("- NSAC: %u\n", csd.NSAC);
1783
    DEBUG_MSG("- MaxBusClkFrec: %u\n", csd.MaxBusClkFrec);
1783
    DEBUG_MSG("- MaxBusClkFrec: %u\n", csd.MaxBusClkFrec);
1784
    DEBUG_MSG("- CardComdClasses: %u\n", csd.CardComdClasses);
1784
    DEBUG_MSG("- CardComdClasses: %u\n", csd.CardComdClasses);
1785
    DEBUG_MSG("- RdBlockLen: %u\n", csd.RdBlockLen);
1785
    DEBUG_MSG("- RdBlockLen: %u\n", csd.RdBlockLen);
1786
    DEBUG_MSG("- PartBlockRead: %u\n", csd.PartBlockRead);
1786
    DEBUG_MSG("- PartBlockRead: %u\n", csd.PartBlockRead);
1787
    DEBUG_MSG("- WrBlockMisalign: %u\n", csd.WrBlockMisalign);
1787
    DEBUG_MSG("- WrBlockMisalign: %u\n", csd.WrBlockMisalign);
1788
    DEBUG_MSG("- RdBlockMisalign: %u\n", csd.RdBlockMisalign);
1788
    DEBUG_MSG("- RdBlockMisalign: %u\n", csd.RdBlockMisalign);
1789
    DEBUG_MSG("- DSRImpl: %u\n", csd.DSRImpl);
1789
    DEBUG_MSG("- DSRImpl: %u\n", csd.DSRImpl);
1790
    DEBUG_MSG("- Reserved2: %u\n", csd.Reserved2);
1790
    DEBUG_MSG("- Reserved2: %u\n", csd.Reserved2);
1791
    DEBUG_MSG("- DeviceSize: %u\n", csd.DeviceSize);
1791
    DEBUG_MSG("- DeviceSize: %u\n", csd.DeviceSize);
1792
    DEBUG_MSG("- MaxRdCurrentVDDMin: %u\n", csd.MaxRdCurrentVDDMin);
1792
    DEBUG_MSG("- MaxRdCurrentVDDMin: %u\n", csd.MaxRdCurrentVDDMin);
1793
    DEBUG_MSG("- MaxRdCurrentVDDMax: %u\n", csd.MaxRdCurrentVDDMax);
1793
    DEBUG_MSG("- MaxRdCurrentVDDMax: %u\n", csd.MaxRdCurrentVDDMax);
1794
    DEBUG_MSG("- MaxWrCurrentVDDMin: %u\n", csd.MaxWrCurrentVDDMin);
1794
    DEBUG_MSG("- MaxWrCurrentVDDMin: %u\n", csd.MaxWrCurrentVDDMin);
1795
    DEBUG_MSG("- MaxWrCurrentVDDMax: %u\n", csd.MaxWrCurrentVDDMax);
1795
    DEBUG_MSG("- MaxWrCurrentVDDMax: %u\n", csd.MaxWrCurrentVDDMax);
1796
    DEBUG_MSG("- DeviceSizeMul: %u\n", csd.DeviceSizeMul);
1796
    DEBUG_MSG("- DeviceSizeMul: %u\n", csd.DeviceSizeMul);
1797
    DEBUG_MSG("- EraseGrSize: %u\n", csd.EraseGrSize);
1797
    DEBUG_MSG("- EraseGrSize: %u\n", csd.EraseGrSize);
1798
    DEBUG_MSG("- EraseGrMul: %u\n", csd.EraseGrMul);
1798
    DEBUG_MSG("- EraseGrMul: %u\n", csd.EraseGrMul);
1799
    DEBUG_MSG("- WrProtectGrSize: %u\n", csd.WrProtectGrSize);
1799
    DEBUG_MSG("- WrProtectGrSize: %u\n", csd.WrProtectGrSize);
1800
    DEBUG_MSG("- WrProtectGrEnable: %u\n", csd.WrProtectGrEnable);
1800
    DEBUG_MSG("- WrProtectGrEnable: %u\n", csd.WrProtectGrEnable);
1801
    DEBUG_MSG("- ManDeflECC: %u\n", csd.ManDeflECC);
1801
    DEBUG_MSG("- ManDeflECC: %u\n", csd.ManDeflECC);
1802
    DEBUG_MSG("- WrSpeedFact: %u\n", csd.WrSpeedFact);
1802
    DEBUG_MSG("- WrSpeedFact: %u\n", csd.WrSpeedFact);
1803
    DEBUG_MSG("- MaxWrBlockLen: %u\n", csd.MaxWrBlockLen);
1803
    DEBUG_MSG("- MaxWrBlockLen: %u\n", csd.MaxWrBlockLen);
1804
    DEBUG_MSG("- WriteBlockPaPartial: %u\n", csd.WriteBlockPaPartial);
1804
    DEBUG_MSG("- WriteBlockPaPartial: %u\n", csd.WriteBlockPaPartial);
1805
    DEBUG_MSG("- Reserved3: %u\n", csd.Reserved3);
1805
    DEBUG_MSG("- Reserved3: %u\n", csd.Reserved3);
1806
    DEBUG_MSG("- ContentProtectAppli: %u\n", csd.ContentProtectAppli);
1806
    DEBUG_MSG("- ContentProtectAppli: %u\n", csd.ContentProtectAppli);
1807
    DEBUG_MSG("- FileFormatGrouop: %u\n", csd.FileFormatGrouop);
1807
    DEBUG_MSG("- FileFormatGrouop: %u\n", csd.FileFormatGrouop);
1808
    DEBUG_MSG("- CopyFlag: %u\n", csd.CopyFlag);
1808
    DEBUG_MSG("- CopyFlag: %u\n", csd.CopyFlag);
1809
    DEBUG_MSG("- PermWrProtect: %u\n", csd.PermWrProtect);
1809
    DEBUG_MSG("- PermWrProtect: %u\n", csd.PermWrProtect);
1810
    DEBUG_MSG("- TempWrProtect: %u\n", csd.TempWrProtect);
1810
    DEBUG_MSG("- TempWrProtect: %u\n", csd.TempWrProtect);
1811
    DEBUG_MSG("- FileFormat: %u\n", csd.FileFormat);
1811
    DEBUG_MSG("- FileFormat: %u\n", csd.FileFormat);
1812
    DEBUG_MSG("- ECC: %u\n", csd.ECC);
1812
    DEBUG_MSG("- ECC: %u\n", csd.ECC);
1813
    DEBUG_MSG("- msd_CRC: 0x%02x\n", csd.msd_CRC);
1813
    DEBUG_MSG("- msd_CRC: 0x%02x\n", csd.msd_CRC);
1814
    DEBUG_MSG("- Reserved4: %u\n", csd.Reserved4);
1814
    DEBUG_MSG("- Reserved4: %u\n", csd.Reserved4);
1815
    DEBUG_MSG("--------------------\n");
1815
    DEBUG_MSG("--------------------\n");
1816
  }
1816
  }
1817
1817
1818
  return 0; // no error
1818
  return 0; // no error
1819
}
1819
}
1820
1820
1821
1821
1822
/////////////////////////////////////////////////////////////////////////////
1822
/////////////////////////////////////////////////////////////////////////////
1823
//! Send a verbose error message to MIOS terminal
1823
//! Send a verbose error message to MIOS terminal
1824
/////////////////////////////////////////////////////////////////////////////
1824
/////////////////////////////////////////////////////////////////////////////
1825
s32 FILE_SendErrorMessage(s32 error_status)
1825
s32 FILE_SendErrorMessage(s32 error_status)
1826
{
1826
{
1827
#if DEBUG_VERBOSE_LEVEL >= 1
1827
#if DEBUG_VERBOSE_LEVEL >= 1
1828
  switch( error_status ) {
1828
  switch( error_status ) {
1829
  case FILE_ERR_SD_CARD: DEBUG_MSG("[SDCARD_ERROR:%d] failed to access SD card\n", error_status); break;
1829
  case FILE_ERR_SD_CARD: DEBUG_MSG("[SDCARD_ERROR:%d] failed to access SD card\n", error_status); break;
1830
  case FILE_ERR_NO_PARTITION: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_GetPtnStart failed to find partition\n", error_status); break;
1830
  case FILE_ERR_NO_PARTITION: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_GetPtnStart failed to find partition\n", error_status); break;
1831
  case FILE_ERR_NO_VOLUME: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_GetVolInfo failed to find volume information\n", error_status); break;
1831
  case FILE_ERR_NO_VOLUME: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_GetVolInfo failed to find volume information\n", error_status); break;
1832
  case FILE_ERR_UNKNOWN_FS: DEBUG_MSG("[SDCARD_ERROR:%d] unknown filesystem (only FAT12/16/32 supported)\n", error_status); break;
1832
  case FILE_ERR_UNKNOWN_FS: DEBUG_MSG("[SDCARD_ERROR:%d] unknown filesystem (only FAT12/16/32 supported)\n", error_status); break;
1833
  case FILE_ERR_OPEN_READ: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_OpenFile(..DFS_READ..) failed, e.g. file not found\n", error_status); break;
1833
  case FILE_ERR_OPEN_READ: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_OpenFile(..DFS_READ..) failed, e.g. file not found\n", error_status); break;
1834
  case FILE_ERR_OPEN_READ_WITHOUT_CLOSE: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_ReadOpen() has been called while previous file hasn't been closed\n", error_status); break;
1834
  case FILE_ERR_OPEN_READ_WITHOUT_CLOSE: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_ReadOpen() has been called while previous file hasn't been closed\n", error_status); break;
1835
  case FILE_ERR_READ: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_ReadFile failed\n", error_status); break;
1835
  case FILE_ERR_READ: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_ReadFile failed\n", error_status); break;
1836
  case FILE_ERR_READCOUNT: DEBUG_MSG("[SDCARD_ERROR:%d] less bytes read than expected\n", error_status); break;
1836
  case FILE_ERR_READCOUNT: DEBUG_MSG("[SDCARD_ERROR:%d] less bytes read than expected\n", error_status); break;
1837
  case FILE_ERR_READCLOSE: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_ReadClose aborted due to previous error\n", error_status); break;
1837
  case FILE_ERR_READCLOSE: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_ReadClose aborted due to previous error\n", error_status); break;
1838
  case FILE_ERR_WRITE_MALLOC: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_WriteOpen failed to allocate memory for write buffer\n", error_status); break;
1838
  case FILE_ERR_WRITE_MALLOC: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_WriteOpen failed to allocate memory for write buffer\n", error_status); break;
1839
  case FILE_ERR_OPEN_WRITE: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_OpenFile(..DFS_WRITE..) failed\n", error_status); break;
1839
  case FILE_ERR_OPEN_WRITE: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_OpenFile(..DFS_WRITE..) failed\n", error_status); break;
1840
  case FILE_ERR_OPEN_WRITE_WITHOUT_CLOSE: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_WriteOpen() has been called while previous file hasn't been closed\n", error_status); break;
1840
  case FILE_ERR_OPEN_WRITE_WITHOUT_CLOSE: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_WriteOpen() has been called while previous file hasn't been closed\n", error_status); break;
1841
  case FILE_ERR_WRITE: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_WriteFile failed\n", error_status); break;
1841
  case FILE_ERR_WRITE: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_WriteFile failed\n", error_status); break;
1842
  case FILE_ERR_WRITECOUNT: DEBUG_MSG("[SDCARD_ERROR:%d] less bytes written than expected\n", error_status); break;
1842
  case FILE_ERR_WRITECOUNT: DEBUG_MSG("[SDCARD_ERROR:%d] less bytes written than expected\n", error_status); break;
1843
  case FILE_ERR_WRITECLOSE: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_WriteClose aborted due to previous error\n", error_status); break;
1843
  case FILE_ERR_WRITECLOSE: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_WriteClose aborted due to previous error\n", error_status); break;
1844
  case FILE_ERR_SEEK: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_Seek() failed\n", error_status); break;
1844
  case FILE_ERR_SEEK: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_Seek() failed\n", error_status); break;
1845
  case FILE_ERR_OPEN_DIR: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_OpenDir(..DFS_READ..) failed, e.g. directory not found\n", error_status); break;
1845
  case FILE_ERR_OPEN_DIR: DEBUG_MSG("[SDCARD_ERROR:%d] DFS_OpenDir(..DFS_READ..) failed, e.g. directory not found\n", error_status); break;
1846
  case FILE_ERR_COPY: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_Copy() failed\n", error_status); break;
1846
  case FILE_ERR_COPY: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_Copy() failed\n", error_status); break;
1847
  case FILE_ERR_COPY_NO_FILE: DEBUG_MSG("[SDCARD_ERROR:%d] source file doesn't exist\n", error_status); break;
1847
  case FILE_ERR_COPY_NO_FILE: DEBUG_MSG("[SDCARD_ERROR:%d] source file doesn't exist\n", error_status); break;
1848
  case FILE_ERR_NO_DIR: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_GetDirs() or FILE_GetFiles() failed because of missing directory\n", error_status); break;
1848
  case FILE_ERR_NO_DIR: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_GetDirs() or FILE_GetFiles() failed because of missing directory\n", error_status); break;
1849
  case FILE_ERR_NO_FILE: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_GetFiles() failed because of missing directory\n", error_status); break;
1849
  case FILE_ERR_NO_FILE: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_GetFiles() failed because of missing directory\n", error_status); break;
1850
  case FILE_ERR_SYSEX_READ: DEBUG_MSG("[SDCARD_ERROR:%d] error while reading .syx file\n", error_status); break;
1850
  case FILE_ERR_SYSEX_READ: DEBUG_MSG("[SDCARD_ERROR:%d] error while reading .syx file\n", error_status); break;
1851
  case FILE_ERR_MKDIR: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_MakeDir() failed\n", error_status); break;
1851
  case FILE_ERR_MKDIR: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_MakeDir() failed\n", error_status); break;
1852
  case FILE_ERR_INVALID_SESSION_NAME: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_LoadSessionName()\n", error_status); break;
1852
  case FILE_ERR_INVALID_SESSION_NAME: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_LoadSessionName()\n", error_status); break;
1853
  case FILE_ERR_UPDATE_FREE: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_UpdateFreeBytes()\n", error_status); break;
1853
  case FILE_ERR_UPDATE_FREE: DEBUG_MSG("[SDCARD_ERROR:%d] FILE_UpdateFreeBytes()\n", error_status); break;
1854
1854
1855
  default:
1855
  default:
1856
    // remaining errors just print the number
1856
    // remaining errors just print the number
1857
    DEBUG_MSG("[SDCARD_ERROR:%d] see file.h for description\n", error_status);
1857
    DEBUG_MSG("[SDCARD_ERROR:%d] see file.h for description\n", error_status);
1858
  }
1858
  }
1859
#endif
1859
#endif
1860
1860
1861
  return 0; // no error
1861
  return 0; // no error
1862
}
1862
}
1863
1863
1864
1864
1865
/////////////////////////////////////////////////////////////////////////////
1865
/////////////////////////////////////////////////////////////////////////////
1866
//! Handler for MIOS Studio Filebrowser accesses.\n
1866
//! Handler for MIOS Studio Filebrowser accesses.\n
1867
//! See $MIOS32_PATH/apps/controllers/midio128/src/terminal.c for usage example.
1867
//! See $MIOS32_PATH/apps/controllers/midio128/src/terminal.c for usage example.
1868
/////////////////////////////////////////////////////////////////////////////
1868
/////////////////////////////////////////////////////////////////////////////
1869
s32 FILE_BrowserHandler(mios32_midi_port_t port, char *command)
1869
s32 FILE_BrowserHandler(mios32_midi_port_t port, char *command)
1870
{
1870
{
1871
  s32 status = 0;
1871
  s32 status = 0;
1872
  char *separators = " ";
1872
  char *separators = " ";
1873
  char *brkt;
1873
  char *brkt;
1874
  char *parameter;
1874
  char *parameter;
1875
  u8 command_taken = 0;
1875
  u8 command_taken = 0;
1876
  u8 send_footer = 1;
1876
  u8 send_footer = 1;
1877
1877
1878
  if( (parameter = strtok_r(command, separators, &brkt)) ) {
1878
  if( (parameter = strtok_r(command, separators, &brkt)) ) {
1879
    if( strcmp(parameter, "dir") == 0 ) {
1879
    if( strcmp(parameter, "dir") == 0 ) {
1880
      command_taken = 1;
1880
      command_taken = 1;
1881
      status |= MIOS32_MIDI_SendDebugStringHeader(port, 0x41, (u8)'D');
1881
      status |= MIOS32_MIDI_SendDebugStringHeader(port, 0x41, (u8)'D');
1882
1882
1883
      char *path = (char *)&command[4];
1883
      char *path = (char *)&command[4];
1884
      s32 status = 0;
1884
      s32 status = 0;
1885
      DIR di;
1885
      DIR di;
1886
      FILINFO de;
1886
      FILINFO de;
1887
1887
1888
      if( !volume_available ) {
1888
      if( !volume_available ) {
1889
    status |= MIOS32_MIDI_SendDebugStringBody(port, "!", 1); // SD Card not mounted
1889
    status |= MIOS32_MIDI_SendDebugStringBody(port, "!", 1); // SD Card not mounted
1890
      } else {
1890
      } else {
1891
    if( f_opendir(&di, path) != FR_OK ) {
1891
    if( f_opendir(&di, path) != FR_OK ) {
1892
      status |= MIOS32_MIDI_SendDebugStringBody(port, "-", 1); // failed to access directory
1892
      status |= MIOS32_MIDI_SendDebugStringBody(port, "-", 1); // failed to access directory
1893
    } else {
1893
    } else {
1894
      while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
1894
      while( status == 0 && f_readdir(&di, &de) == FR_OK && de.fname[0] != 0 ) {
1895
        if( de.fname[0] && de.fname[0] != '.' && !(de.fattrib & AM_HID) ) {
1895
        if( de.fname[0] && de.fname[0] != '.' && !(de.fattrib & AM_HID) ) {
1896
          char str[20];
1896
          char str[20];
1897
          str[0] = ',';
1897
          str[0] = ',';
1898
          str[1] = (de.fattrib & AM_DIR) ? 'D' : 'F';
1898
          str[1] = (de.fattrib & AM_DIR) ? 'D' : 'F';
1899
          strcpy((char *)&str[2], (char *)&de.fname[0]);
1899
          strcpy((char *)&str[2], (char *)&de.fname[0]);
1900
          status |= MIOS32_MIDI_SendDebugStringBody(port, str, strlen(str));
1900
          status |= MIOS32_MIDI_SendDebugStringBody(port, str, strlen(str));
1901
        }
1901
        }
1902
      }
1902
      }
1903
    }
1903
    }
1904
      }
1904
      }
1905
1905
1906
    } else if( strcmp(parameter, "mkdir") == 0 ) {
1906
    } else if( strcmp(parameter, "mkdir") == 0 ) {
1907
      command_taken = 1;
1907
      command_taken = 1;
1908
      status |= MIOS32_MIDI_SendDebugStringHeader(port, 0x41, (u8)'M');
1908
      status |= MIOS32_MIDI_SendDebugStringHeader(port, 0x41, (u8)'M');
1909
1909
1910
      char *path = (char *)&command[6];
1910
      char *path = (char *)&command[6];
1911
      s32 status = 0;
1911
      s32 status = 0;
1912
1912
1913
      if( !volume_available ) {
1913
      if( !volume_available ) {
1914
    status |= MIOS32_MIDI_SendDebugStringBody(port, "!", 1); // SD Card not mounted
1914
    status |= MIOS32_MIDI_SendDebugStringBody(port, "!", 1); // SD Card not mounted
1915
      } else {
1915
      } else {
1916
    if( FILE_MakeDir(path) < 0 ) {
1916
    if( FILE_MakeDir(path) < 0 ) {
1917
      status |= MIOS32_MIDI_SendDebugStringBody(port, "-", 1); // failed to create directory
1917
      status |= MIOS32_MIDI_SendDebugStringBody(port, "-", 1); // failed to create directory
1918
    } else {
1918
    } else {
1919
      status |= MIOS32_MIDI_SendDebugStringBody(port, "#", 1); // success
1919
      status |= MIOS32_MIDI_SendDebugStringBody(port, "#", 1); // success
1920
    }
1920
    }
1921
      }
1921
      }
1922
1922
1923
    } else if( strcmp(parameter, "del") == 0 ) {
1923
    } else if( strcmp(parameter, "del") == 0 ) {
1924
      command_taken = 1;
1924
      command_taken = 1;
1925
      status |= MIOS32_MIDI_SendDebugStringHeader(port, 0x41, (u8)'X');
1925
      status |= MIOS32_MIDI_SendDebugStringHeader(port, 0x41, (u8)'X');
1926
1926
1927
      char *path = (char *)&command[4];
1927
      char *path = (char *)&command[4];
1928
      s32 status = 0;
1928
      s32 status = 0;
1929
1929
1930
      if( !volume_available ) {
1930
      if( !volume_available ) {
1931
    status |= MIOS32_MIDI_SendDebugStringBody(port, "!", 1); // SD Card not mounted
1931
    status |= MIOS32_MIDI_SendDebugStringBody(port, "!", 1); // SD Card not mounted
1932
      } else {
1932
      } else {
1933
    if( FILE_Remove(path) < 0 ) {
1933
    if( FILE_Remove(path) < 0 ) {
1934
      status |= MIOS32_MIDI_SendDebugStringBody(port, "-", 1); // failed to remove file/directory
1934
      status |= MIOS32_MIDI_SendDebugStringBody(port, "-", 1); // failed to remove file/directory
1935
    } else {
1935
    } else {
1936
      status |= MIOS32_MIDI_SendDebugStringBody(port, "#", 1); // success
1936
      status |= MIOS32_MIDI_SendDebugStringBody(port, "#", 1); // success
1937
    }
1937
    }
1938
      }
1938
      }
1939
1939