2025-02-27 17:59:18 +08:00

517 lines
14 KiB
C
Executable File

#include "diskio.h" /* Declarations of low level disk I/O functions */
#if CONFIG_SDCARD && CONFIG_USB_MSD
#include "ff.h"
#define MAX_DIR_SUPPORT 1024
#define MAX_SONG_DIR 64 // 128
#define MAX_DIR_LEVEL 6
FILE_INFO FileInfo;
char *MP3_Ext = ".MP3";
char *WAV_Ext = ".WAV";
FAT_DIR_INFO file_queue[MAX_SONG_DIR];
uint16 mp3queuecount = 0; //有MP3文件的文件夹数目
uint16 mp3filecount = 0;// MP3歌曲总的数目
FATFS Fatfs_buf;
FIL fsFD;
DIR_QUEUE *point_front;//队头指针
DIR_QUEUE *point_rear;//队尾指针
static uint16 rear_cnt = 0;
DIR_QUEUE g_dirbuf[MAX_DIR_SUPPORT];
extern void mem_set (void *dst, int val, uint32 cnt);
extern FRESULT chk_mounted_con (FATFS *rfs, uint8 chk_wp);
int strcmpi (const void *dst, const void *src, int cnt)
{
const char *d = (const char *)dst, *s = (const char *)src;
int r = 0;
while (cnt-- && (r = *d++ - *s++) == 0);
return r;
}
char *strrchr_con(char *str, char ch)
{
char *p = (char *)str;
while (*str) str++;
while ((str-- != p) && (*str != ch));
if (*str == ch)
return( (char *)str );
return NULL;
}
static void Convert2UpperCase(char *str, uint32 len)
{
uint32 i;
for(i = 0; i < len; i++)
((str[i] <= 'z') && (str[i] >= 'a')) ? (str[i] -= 0x20) : str[i];
}
FRESULT f_open_con (
FIL *fp, /* Pointer to the blank file object */
PFILINFOADD finfo,
uint8 mode /* Access mode and file open mode flags */
)
{
fp->flag = mode; /* File access mode */
fp->org_clust = finfo->fcluster;/* File start cluster */
fp->fsize = finfo->fsize; /* File size */
fp->fptr = 0;
fp->csect = 255; /* File pointer */
fp->dsect = 0;
fp->fs = &Fatfs_buf;
fp->id = Fatfs_buf.id; /* Owner file system object of the file */
fp->ExNoChainFlag = finfo->ExNoChainFlag;
return FR_OK;
}
////
FRESULT fl_listatdir(DIR *dj_con, PFILINFOADD fi_con, uint16 idx)
{
int i;
uint8 c, *dir;
char *p;
FRESULT ret = FR_NO_FILE;
/*for exfat use*/
static uint8 DirEntryAttr = 0;
static uint8 no_fat_chain_Flag = 0;
static uint8 ExtNameStartFlag = 0;
static uint8 exfat_name_length = 0;
static uint8 extname_idx = 0;
static char ext_name[3];
static uint32 exfat_first_cluster = 0;
static uint32 exfat_file_size = 0;
static uint16 exfat_entry_phase = 0;
uint32 tmp = 0;
dj_con->dir = dj_con->fs->win + (idx % (SS(dj_con->fs) / 32)) * 32;
dir = dj_con->dir;
if(dj_con->fs->fs_type == FS_ExFAT)
{
switch (dir[0])
{
case FILE_DIR_ENTRY:
if(exfat_entry_phase == 0)
{
DirEntryAttr = dir[ExFat_Dir_Attr] & 0x3f; //get file attribute
exfat_entry_phase++;
}
ret = FR_NO_FILE;
break;
case STREAM_EXT_DIR_ENT:
if(exfat_entry_phase == 1)
{
exfat_first_cluster = LD_DWORD(dir + ExFat_FirstCluster);
exfat_file_size = LD_DWORD(dir + ExFat_DataLength); //Byte unit
exfat_name_length = dir[ExFat_NameLength];
no_fat_chain_Flag = dir[ExFat_NoChainFlag];
extname_idx = 0;
ExtNameStartFlag = 0;
exfat_entry_phase++;
}
ret = FR_NO_FILE;
break;
case FILE_NAME_DIR_ENTRY:
if(exfat_entry_phase == 2 )
{
if(exfat_name_length < 19)
{
tmp = (exfat_name_length > 15) ? 15 : exfat_name_length;
for(i = 0; i < tmp; i++)
{
if(ExtNameStartFlag)
{
ext_name[extname_idx] = (char)dir[(i + 1) << 1];
extname_idx++;
}
else
{
if((dir[(i + 1) << 1] == '.') && (dir[((i + 1) << 1) + 1] == 0))
ExtNameStartFlag = 1;
}
}
exfat_name_length -= tmp;
}
else
exfat_name_length -= 15;
if(exfat_name_length == 0)
{
/*all file name directory entries have been handled*/
mem_set(fi_con->fname, ' ', 13);
Convert2UpperCase(ext_name, 3);
mem_cpy(&fi_con->fname[9], ext_name, 3);
fi_con->fname[0] = '*';
fi_con->fname[8] = '.';//for our usage , ignore the name
fi_con->fname[12] = '\0';
fi_con->fattrib = DirEntryAttr; /* Attribute */
fi_con->fsize = exfat_file_size; /* Size */
fi_con->fcluster = exfat_first_cluster;/*file start cluster*/
fi_con->ExNoChainFlag = no_fat_chain_Flag;
exfat_entry_phase = 0;
ret = FR_OK;
}
else
ret = FR_NO_FILE;
}
break;
case 0:
ret = FR_EXIST;
break;
default:
exfat_entry_phase = 0;
ret = FR_NO_FILE;
break;
}
}
else
{
p = fi_con->fname;
if ((dir[0] == 0xE5) || (dir[0] == 0x05) || (dir[0] == 0x20) || (dir[0] == '.')
|| (dir[DIR_Attr] == 0x0f))
return FR_NO_FILE;
if (dir[0] == 0x00)
return FR_EXIST;
for (i = 0; i < 8; i++)
{
/* Copy name body */
c = dir[i];
*p++ = c;
}
fi_con->fname[8] = ' ';
fi_con->fname[9] = ' ';
fi_con->fname[10] = ' ';
fi_con->fname[11] = ' ';
if (dir[8] != ' ')
{
/* Copy name extension */
*p++ = '.';
for (i = 8; i < 11; i++)
{
c = dir[i];
if (c == ' ')
break;
*p++ = c;
}
}
fi_con->fname[12] = '\0';
fi_con->fattrib = dir[DIR_Attr]; /* Attribute */
fi_con->fsize = LD_DWORD(dir + DIR_FileSize); /* Size */
fi_con->fdate = LD_WORD(dir + DIR_WrtDate); /* Date */
fi_con->ftime = LD_WORD(dir + DIR_WrtTime); /* Time */
fi_con->fcluster = ((uint32)LD_WORD(dir + DIR_FstClusHI) << 16) | LD_WORD(dir + DIR_FstClusLO);
ret = FR_OK;
}
return ret;
}
static FRESULT get_curdir_info(DIR_QUEUE *p_front)
{
uint16 idx = 0;
uint16 cur_musicfile = 0;
uint16 ic, dc;
FRESULT ret;
DIR dj;
FILINFOADD fl_curnode;
char *Ext = NULL;
char *Ext1 = NULL;
dj.fs = &Fatfs_buf;
dj.ExNoChainFlag = p_front->ExNoChainFlag;
dc = SS(dj.fs) / 32;//entry count per sector
ic = SS(dj.fs) / 32 * dj.fs->csize;//entry count per cluster
if(p_front->broot_dir)
dj.sclust = 0;//for Fat16
else
dj.sclust = p_front ->cluster_number;
os_printf("get_curdir_info\r\n");
while(1)
{
if((idx % ic) == 0) //new cluster
{
ret = dir_seek(&dj, idx);
if (ret != FR_OK)
break;
}
if((idx % dc) == 0) //new sector
{
if((idx % ic) != 0) //not cluster boundary
dj.sect++;
ret = move_window(dj.fs, dj.sect);
if (ret != FR_OK)
break;
}
ret = fl_listatdir(&dj, &fl_curnode, idx);
idx++;
if(ret == FR_OK)
{
if((fl_curnode.fattrib & 0x10) != 0)
{
point_rear->cluster_number = fl_curnode.fcluster;
point_rear->dirlevel = p_front->dirlevel + 1;
point_rear->broot_dir = 0;
point_rear->ExNoChainFlag = fl_curnode.ExNoChainFlag;
rear_cnt++;
if(rear_cnt > MAX_DIR_SUPPORT - 1)
break;
point_rear++;
}
if((fl_curnode.fattrib & 0x20) != 0) /*对只读、隐藏、系统等文件的属性支持*/
{
Ext = fl_curnode.fname;
os_printf("get_curdir_info: fl_curnode.fname = \"%s\"\r\n", Ext);
Ext1 = strrchr_con(Ext, '.');
if (!strcmpi(Ext1, MP3_Ext, 4))
cur_musicfile++;
else
{
if(!strcmpi(Ext1, WAV_Ext, 4))
cur_musicfile++;
}
}
}
if(ret == FR_NO_FILE)
continue;
if(ret == FR_EXIST)
break;
}//while(1)
if (cur_musicfile)
{
file_queue[mp3queuecount].first_cluster = p_front->cluster_number;
file_queue[mp3queuecount].music_total = cur_musicfile;
file_queue[mp3queuecount].broot_dir = p_front->broot_dir;
file_queue[mp3queuecount].ExNoChainFlag = p_front->ExNoChainFlag;
mp3queuecount++;
mp3filecount += cur_musicfile;
}
return FR_OK;
}
/*input:
i -- directory index
number -- music file idx in directory i */
static FIL *GetFile_From_NumInDir(uint16 i, uint16 number)
{
uint16 idx = 0;
uint16 ic, dc, brootdir, music_count;
FRESULT ret;
FILINFOADD fl_curnode;
char *Ext = NULL;
char *Ext1 = NULL;
DIR dj_con;
FIL *fio = &fsFD;
dj_con.fs = &Fatfs_buf;
brootdir = file_queue[i].broot_dir;
if(brootdir)
dj_con.sclust = 0;
else
dj_con.sclust = file_queue[i].first_cluster;
dc = SS(dj_con.fs) / 32;
ic = SS(dj_con.fs) / 32 * dj_con.fs->csize;
music_count = 0;
number += 1;
while(1)
{
if((idx % ic) == 0)
{
ret = dir_seek(&dj_con, idx);
if (ret != FR_OK)
return NULL;
}
if((idx % dc) == 0)
{
if((idx % ic) != 0)
dj_con.sect++;
ret = move_window(dj_con.fs, dj_con.sect);
if (ret != FR_OK)
return NULL;
}
ret = fl_listatdir(&dj_con, &fl_curnode, idx);
idx++;
if(ret == FR_OK)
{
if((fl_curnode.fattrib & 0x20) != 0) /*对只读、隐藏、系统等文件的属性支持*/
{
Ext = fl_curnode.fname;
Ext1 = strrchr_con(Ext, '.');
if (!strcmpi(Ext1, MP3_Ext, 4))
music_count++;
else
{
if (!strcmpi(Ext1, WAV_Ext, 4))
music_count++;
}
}
}
if (music_count == number)
break;
if(ret == FR_NO_FILE)
continue;
if(ret == FR_EXIST)
return NULL;
}
FileInfo.fcluster = fl_curnode.fcluster;
mem_cpy(FileInfo.fname, fl_curnode.fname, 12);
mem_cpy(FileInfo.extname, FileInfo.fname + 9, 3);
f_open_con(fio, &fl_curnode, FA_READ);
return fio;
}
/*input:number -- 0~mp3filecount-1 */
//Playlist_GetSongFileInfo
FIL *Get_File_From_Number(uint16 number)
{
uint16 i;
FIL *fhFile;
for(i = 0; i < MAX_SONG_DIR; i++)
{
if(number >= file_queue[i].music_total)
{
number = number - file_queue[i].music_total;
continue;
}
else
break;
}
if(i == MAX_SONG_DIR)
return NULL;
fhFile = GetFile_From_NumInDir(i, number);
return fhFile;
}
/*scan whole disk, get total music file number and store the DIRs info
which have music files
*/
static uint32 initfatsystem(uint8 type)
{
int count = 0, ret;
DIR_QUEUE *dir_buf;
rear_cnt = 0;
if((ret = chk_mounted_con(&Fatfs_buf, type)) != FR_OK)
{
FATFS_LOGI("Fat Init Err:%d!!!\r\n", ret);
return 1;
}
#if 1
//if(driver_sdcard_get_init_status())
{
//dir_buf=(DIR_QUEUE*)jmalloc(MAX_DIR_SUPPORT*sizeof(DIR_QUEUE),0);//最大支持的文件夹
//if(!dir_buf)
// return -1;
dir_buf = &g_dirbuf[0];
mem_set(file_queue, 0, MAX_SONG_DIR * sizeof(FAT_DIR_INFO));
mp3filecount = 0;
mp3queuecount = 0;
point_front = point_rear = dir_buf;
point_front ->cluster_number = Fatfs_buf.dirbase;
point_front ->dirlevel = 0;
point_front ->ExNoChainFlag = 0;
if (Fatfs_buf.fs_type == FS_FAT16)
point_front ->broot_dir = 1;
else
point_front ->broot_dir = 0;
point_rear++;
rear_cnt++;
while(1)
{
if ((mp3queuecount < MAX_SONG_DIR)
&& (point_front ->dirlevel < MAX_DIR_LEVEL)
&& (point_front != point_rear)
&& (count < MAX_DIR_SUPPORT))
{
if(rear_cnt > MAX_DIR_SUPPORT - 1)
break;
get_curdir_info(point_front);
count++;
point_front++;
}
else
break;
}
FATFS_LOGI("count=%d mp3queuecount=%d mp3filecount=%d,rear_cnt =%d\r\n", count, mp3queuecount, mp3filecount, rear_cnt);
//driver_sdcard_set_init_status(0);
//jfree(dir_buf);
// dir_buf = NULL;
}
#endif
return 0;
}
/*Sd card & filesystem initialization*/
//uint32 SD_Fs_Init(void)
uint32 Media_Fs_Init(uint8 type)
{
uint32 ret = 1;
FileInfo.fat_ok_flag = 0;
if(f_mount(1, &Fatfs_buf) == FR_OK)
{
if(initfatsystem(type) == FR_OK)
{
FileInfo.fat_ok_flag = 1;
ret = 0;
}
}
return ret;
}
uint8 get_fat_ok_flag(void)
{
return FileInfo.fat_ok_flag;
}
uint16 get_musicfile_count(void)
{
return mp3filecount;
}
FILE_INFO *get_file_info(void)
{
return (&FileInfo);
}
uint8 get_disk_type(void)
{
return Fatfs_buf.drive;
}
#endif