Subversion Repositories svn.mios32

Rev

Rev 2617 | Details | Compare with Previous | Last modification | View Log | RSS feed

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