//文件操作与WAV音频播放实验程序解析
//头文件
#include <string.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/pin_map.h"
#include "driverlib/ssi.h"
#include "grlib/grlib.h"
#include "utils/cmdline.h"
#include "utils/uartstdio.h"
#include "fatfs/src/ff.h"
#include "fatfs/src/diskio.h"
#include "drivers/cfal96x64x16.h"
#include "drivers/buttons.h"
//*****************************************************************************
// Defines the size of the buffers that hold the path, or temporary data from
// the SD card. There are two buffers allocated of this size. The buffer size
// must be large enough to hold the longest expected full path name, including
// the file name, and a trailing null character.
//*****************************************************************************
#define PATH_BUF_SIZE 80
//*****************************************************************************
// Defines the size of the buffer that holds the command line.
//*****************************************************************************
#define CMD_BUF_SIZE 64
//*****************************************************************************
// This buffer holds the full path to the current working directory. Initially
// it is root ("/").
//*****************************************************************************
static char g_cCwdBuf[PATH_BUF_SIZE] = "/";
//*****************************************************************************
// A temporary data buffer used when manipulating file paths, or reading data
// from the SD card.
//*****************************************************************************
static char g_cTmpBuf[PATH_BUF_SIZE];
//*****************************************************************************
// A flag to indicate the select button was pressed.
//*****************************************************************************
static volatile unsigned char bSelectPressed = 0;
static volatile unsigned char bUpPressed = 0;
static volatile unsigned char bDownPressed = 0;
static volatile unsigned char bLeftPressed = 0;
static volatile unsigned char bRightPressed = 0;
//*****************************************************************************
// The buffer that holds the command line.
//*****************************************************************************
static char g_cCmdBuf[CMD_BUF_SIZE];
//*****************************************************************************
// The following are data structures used by FatFs.
//*****************************************************************************
static FATFS g_sFatFs;
static DIR g_sDirObject;
static FILINFO g_sFileInfo;
static FIL g_sFileObject;
tRectangle sRect;
char tmp[100];
char cover[20]=" ";
//*****************************************************************************
// A structure that holds a mapping between an FRESULT numerical code, and a
// string representation. FRESULT codes are returned from the FatFs FAT file
// system driver.
//*****************************************************************************
typedef struct
{
FRESULT fresult;
char *pcResultStr;
}
tFresultString;
//wav文件头数据类型
typedef struct _tagMsWavPcmHeader44{
char ChunkID[4]; // "RIFF"; The "RIFF" the mainchunk;
unsigned long ChunkSize; // FileSize - 8; The size following this data
char Format[4]; // "WAVE"; The "WAVE" format consists of two subchunks: "fmt " and "data"
char SubChunk1ID[4]; // "fmt "
unsigned long SubChunk1Size; // 16 for PCM. This is the size of the rest of the subchunk which follows this data.
unsigned short AudioFormat; // 1 for PCM. Linear quantization
unsigned short NumChannels; // 1->Mono, 2->stereo, etc..
unsigned long SampleRate; // 8000, 11025, 16000, 44100, 48000, etc..
unsigned long ByteRate; // = SampleRate * NumChannels * BitsPerSample/8
unsigned short BlockAlign; // = NumChannels * BitsPerSample / 8
unsigned short BitsPerSample; // 8->8bits, 16->16bits, etc..
char SubChunk2ID[4]; // "data"
unsigned long SubChun2Size; // = NumSamples * NumChannels * BitsPerSample / 8. The size of data
} wav_pcm_header44;
//*****************************************************************************
// A macro to make it easy to add result codes to the table.
//*****************************************************************************
#define FRESULT_ENTRY(f) { (f), (#f) }
//*****************************************************************************
// A table that holds a mapping between the numerical FRESULT code and it's
// name as a string. This is used for looking up error codes for printing to
// the console.
//*****************************************************************************
tFresultString g_sFresultStrings[] =
{
FRESULT_ENTRY(FR_OK),
FRESULT_ENTRY(FR_NOT_READY),
FRESULT_ENTRY(FR_NO_FILE),
FRESULT_ENTRY(FR_NO_PATH),
FRESULT_ENTRY(FR_INVALID_NAME),
FRESULT_ENTRY(FR_INVALID_DRIVE),
FRESULT_ENTRY(FR_DENIED),
FRESULT_ENTRY(FR_EXIST),
FRESULT_ENTRY(FR_RW_ERROR),
FRESULT_ENTRY(FR_WRITE_PROTECTED),
FRESULT_ENTRY(FR_NOT_ENABLED),
FRESULT_ENTRY(FR_NO_FILESYSTEM),
FRESULT_ENTRY(FR_INVALID_OBJECT),
FRESULT_ENTRY(FR_MKFS_ABORTED)
};
//*****************************************************************************
// A macro that holds the number of result codes.
//*****************************************************************************
#define NUM_FRESULT_CODES (sizeof(g_sFresultStrings) / sizeof(tFresultString))
//*****************************************************************************
// Graphics context used to show text on the CSTN display.
//*****************************************************************************
tContext g_sContext;
//*****************************************************************************
// This function returns a string representation of an error code that was
// returned from a function call to FatFs. It can be used for printing human
// readable error messages.
//*****************************************************************************
const char *
StringFromFresult(FRESULT fresult)
{
unsigned int uIdx;
//
// Enter a loop to search the error code table for a matching error code.
//
for(uIdx = 0; uIdx < NUM_FRESULT_CODES; uIdx++)
{
//
// If a match is found, then return the string name of the error code.
//
if(g_sFresultStrings[uIdx].fresult == fresult)
{
return(g_sFresultStrings[uIdx].pcResultStr);
}
}
//
// At this point no matching code was found, so return a string indicating
// an unknown error.
//
return("UNKNOWN ERROR CODE");
}
//*****************************************************************************
// This is the handler for this SysTick interrupt. FatFs requires a timer tick
// every 10 ms for internal timing purposes.
//*****************************************************************************
void
SysTickHandler(void)
{
//
// Call the FatFs tick timer.
//
unsigned char ucData, ucDelta;
disk_timerproc();
// Get buttons status using button debouncer driver
ucData = ButtonsPoll(&ucDelta, 0);
// See if the select button was just pressed.
if(BUTTON_PRESSED(SELECT_BUTTON, ucData, ucDelta))
{
bSelectPressed = 1;
}
if(BUTTON_RELEASED(SELECT_BUTTON, ucData, ucDelta))
{
bSelectPressed = 0;
}
if(BUTTON_PRESSED(UP_BUTTON, ucData, ucDelta))
{
bUpPressed = 1;
}
if(BUTTON_RELEASED(UP_BUTTON, ucData, ucDelta))
{
bUpPressed = 0;
}
if(BUTTON_PRESSED(DOWN_BUTTON, ucData, ucDelta))
{
bDownPressed = 1;
}
if(BUTTON_RELEASED(DOWN_BUTTON, ucData, ucDelta))
{
bDownPressed = 0;
}
if(BUTTON_PRESSED(LEFT_BUTTON, ucData, ucDelta))
{
bLeftPressed = 1;
}
if(BUTTON_RELEASED(LEFT_BUTTON, ucData, ucDelta))
{
bLeftPressed = 0;
}
if(BUTTON_PRESSED(RIGHT_BUTTON, ucData, ucDelta))
{
bRightPressed = 1;
}
if(BUTTON_RELEASED(RIGHT_BUTTON, ucData, ucDelta))
{
bRightPressed = 0;
}
}
//*****************************************************************************
// This function implements the "ls" command. It opens the current directory
// and enumerates through the contents, and prints a line for each item it
// finds. It shows details such as file attributes, time and date, and the
// file size, along with the name. It shows a summary of file sizes at the end
// along with free space.
//*****************************************************************************
int
Cmd_ls(int argc, char *argv[])
{
unsigned long ulTotalSize;
unsigned long ulFileCount;
unsigned long ulDirCount;
FRESULT fresult;
FATFS *pFatFs;
// Open the current directory for access.
fresult = f_opendir(&g_sDirObject, g_cCwdBuf);
// Check for error and return if there is a problem.
if(fresult != FR_OK)
{
return(fresult);
}
ulTotalSize = 0;
ulFileCount = 0;
ulDirCount = 0;
// Give an extra blank line before the listing.
UARTprintf("\n");
// Enter loop to enumerate through all directory entries.
for(;;)
{
// Read an entry from the directory.
fresult = f_readdir(&g_sDirObject, &g_sFileInfo);
// Check for error and return if there is a problem.
if(fresult != FR_OK)
{
return(fresult);
}
// If the file name is blank, then this is the end of the listing.
if(!g_sFileInfo.fname[0])
{
break;
}
// If the attribue is directory, then increment the directory count.
if(g_sFileInfo.fattrib & AM_DIR)
{
ulDirCount++;
}
// Otherwise, it is a file. Increment the file count, and add in the
// file size to the total.
else
{
ulFileCount++;
ulTotalSize += g_sFileInfo.fsize;
}
// Print the entry information on a single line with formatting to show
// the attributes, date, time, size, and name.
UARTprintf("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9u %s\n",
(g_sFileInfo.fattrib & AM_DIR) ? 'D' : '-',
(g_sFileInfo.fattrib & AM_RDO) ? 'R' : '-',
(g_sFileInfo.fattrib & AM_HID) ? 'H' : '-',
(g_sFileInfo.fattrib & AM_SYS) ? 'S' : '-',
(g_sFileInfo.fattrib & AM_ARC) ? 'A' : '-',
(g_sFileInfo.fdate >> 9) + 1980,
(g_sFileInfo.fdate >> 5) & 15,
g_sFileInfo.fdate & 31,
(g_sFileInfo.ftime >> 11),
(g_sFileInfo.ftime >> 5) & 63,
g_sFileInfo.fsize,
g_sFileInfo.fname);
}
// Print summary lines showing the file, dir, and size totals.
UARTprintf("\n%4u File(s),%10u bytes total\n%4u Dir(s)",
ulFileCount, ulTotalSize, ulDirCount);
// Get the free space.
fresult = f_getfree("/", &ulTotalSize, &pFatFs);
// Check for error and return if there is a problem.
if(fresult != FR_OK)
{
return(fresult);
}
// Display the amount of free space that was calculated.
UARTprintf(", %10uK bytes free\n", ulTotalSize * pFatFs->sects_clust / 2);
// Made it to here, return with no errors.
return(0);
}
//*****************************************************************************
// This function implements the "cd" command. It takes an argument that
// specifies the directory to make the current working directory. Path
// separators must use a forward slash "/". The argument to cd can be one of
// the following:
// * root ("/")
// * a fully specified path ("/my/path/to/mydir")
// * a single directory name that is in the current directory ("mydir")
// * parent directory ("..")
// It does not understand relative paths, so dont try something like this:
// ("../my/new/path")
// Once the new directory is specified, it attempts to open the directory to
// make sure it exists. If the new path is opened successfully, then the
// current working directory (cwd) is changed to the new path.
//*****************************************************************************
int
Cmd_cd(int argc, char *argv[])
{
unsigned int uIdx;
FRESULT fresult;
// Copy the current working path into a temporary buffer so it can be
// manipulated.
strcpy(g_cTmpBuf, g_cCwdBuf);
// If the first character is /, then this is a fully specified path, and it
// should just be used as-is.
if(argv[1][0] == '/')
{
// Make sure the new path is not bigger than the cwd buffer.
if(strlen(argv[1]) + 1 > sizeof(g_cCwdBuf))
{
UARTprintf("Resulting path name is too long\n");
return(0);
}
// If the new path name (in argv[1]) is not too long, then copy it
// into the temporary buffer so it can be checked.
else
{
strncpy(g_cTmpBuf, argv[1], sizeof(g_cTmpBuf));
}
}
// If the argument is .. then attempt to remove the lowest level on the
// CWD.
else if(!strcmp(argv[1], ".."))
{
// Get the index to the last character in the current path.
uIdx = strlen(g_cTmpBuf) - 1;
// Back up from the end of the path name until a separator (/) is
// found, or until we bump up to the start of the path.
while((g_cTmpBuf[uIdx] != '/') && (uIdx > 1))
{
//
// Back up one character.
//
uIdx--;
}
// Now we are either at the lowest level separator in the current path,
// or at the beginning of the string (root). So set the new end of
// string here, effectively removing that last part of the path.
g_cTmpBuf[uIdx] = 0;
}
// Otherwise this is just a normal path name from the current directory,
// and it needs to be appended to the current path.
else
{
// Test to make sure that when the new additional path is added on to
// the current path, there is room in the buffer for the full new path.
// It needs to include a new separator, and a trailing null character.
if(strlen(g_cTmpBuf) + strlen(argv[1]) + 1 + 1 > sizeof(g_cCwdBuf))
{
UARTprintf("Resulting path name is too long\n");
return(0);
}
// The new path is okay, so add the separator and then append the new
// directory to the path.
else
{
// If not already at the root level, then append a /
if(strcmp(g_cTmpBuf, "/"))
{
strcat(g_cTmpBuf, "/");
}
// Append the new directory to the path.
strcat(g_cTmpBuf, argv[1]);
}
}
// At this point, a candidate new directory path is in chTmpBuf. Try to
// open it to make sure it is valid.
fresult = f_opendir(&g_sDirObject, g_cTmpBuf);
// If it can't be opened, then it is a bad path. Inform the user and
// return.
if(fresult != FR_OK)
{
UARTprintf("cd: %s\n", g_cTmpBuf);
return(fresult);
}
// Otherwise, it is a valid new path, so copy it into the CWD.
else
{
strncpy(g_cCwdBuf, g_cTmpBuf, sizeof(g_cCwdBuf));
}
// Return success.
return(0);
}
//*****************************************************************************
// This function implements the "pwd" command. It simply prints the current
// working directory.
//*****************************************************************************
int
Cmd_pwd(int argc, char *argv[])
{
// Print the CWD to the console.
UARTprintf("%s\n", g_cCwdBuf);
// Return success.
return(0);
}
//*****************************************************************************
// This function implements the "cat" command. It reads the contents of a file
// and prints it to the console. This should only be used on text files. If
// it is used on a binary file, then a bunch of garbage is likely to printed on
// the console.
//*****************************************************************************
int
Cmd_cat(int argc, char *argv[])
{
FRESULT fresult;
unsigned short usBytesRead;
// First, check to make sure that the current path (CWD), plus the file
// name, plus a separator and trailing null, will all fit in the temporary
// buffer that will be used to hold the file name. The file name must be
// fully specified, with path, to FatFs.
if(strlen(g_cCwdBuf) + strlen(argv[1]) + 1 + 1 > sizeof(g_cTmpBuf))
{
UARTprintf("Resulting path name is too long\n");
return(0);
}
// Copy the current path to the temporary buffer so it can be manipulated.
strcpy(g_cTmpBuf, g_cCwdBuf);
// If not already at the root level, then append a separator.
if(strcmp("/", g_cCwdBuf))
{
strcat(g_cTmpBuf, "/");
}
// Now finally, append the file name to result in a fully specified file.
strcat(g_cTmpBuf, argv[1]);
// Open the file for reading.
fresult = f_open(&g_sFileObject, g_cTmpBuf, FA_READ);
// If there was some problem opening the file, then return an error.
if(fresult != FR_OK)
{
return(fresult);
}
// Enter a loop to repeatedly read data from the file and display it, until
// the end of the file is reached.
do
{
// Read a block of data from the file. Read as much as can fit in the
// temporary buffer, including a space for the trailing null.
fresult = f_read(&g_sFileObject, g_cTmpBuf, sizeof(g_cTmpBuf) - 1,
&usBytesRead);
// If there was an error reading, then print a newline and return the
// error to the user.
if(fresult != FR_OK)
{
UARTprintf("\n");
return(fresult);
}
// Null terminate the last block that was read to make it a null
// terminated string that can be used with printf.
g_cTmpBuf[usBytesRead] = 0;
// Print the last chunk of the file that was received.
UARTprintf("%s", g_cTmpBuf);
}
while(usBytesRead == sizeof(g_cTmpBuf) - 1);
// Return success.
return(0);
}
//*****************************************************************************
// This function implements the "help" command. It prints a simple list of the
// available commands with a brief description.
//*****************************************************************************
int
Cmd_help(int argc, char *argv[])
{
tCmdLineEntry *pEntry;
// Print some header text.
UARTprintf("\nAvailable commands\n");
UARTprintf("------------------\n");
// Point at the beginning of the command table.
pEntry = &g_sCmdTable[0];
// Enter a loop to read each entry from the command table. The end of the
// table has been reached when the command name is NULL.
while(pEntry->pcCmd)
{
// Print the command name and the brief description.
UARTprintf("%s%s\n", pEntry->pcCmd, pEntry->pcHelp);
// Advance to the next entry in the table.
pEntry++;
}
// Return success.
return(0);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//在SD卡上建立新文件
int
Cmd_new(int argc, char *argv[])
{
FRESULT fresult;
if(strlen(g_cCwdBuf) + strlen(argv[1]) + 1 + 1 > sizeof(g_cTmpBuf))
{
UARTprintf("Resulting path name is too long\n");
return(0);
}
strcpy(g_cTmpBuf, g_cCwdBuf);
if(strcmp("/", g_cCwdBuf))
{
strcat(g_cTmpBuf, "/");
}
strcat(g_cTmpBuf, argv[1]);
fresult = f_open(&g_sFileObject, g_cTmpBuf, FA_CREATE_NEW);
if(fresult != FR_OK)
{
return(fresult);
}
UARTprintf("File %s has been built\n",argv[1]);
return(0);
}
//////////////////////////////////////////////////////////////////////////////
//删除SD卡上的选定文件
int
Cmd_delete(int argc, char *argv[])
{
FRESULT fresult;
if(strlen(g_cCwdBuf) + strlen(argv[1]) + 1 + 1 > sizeof(g_cTmpBuf))
{
UARTprintf("Resulting path name is too long\n");
return(0);
}
strcpy(g_cTmpBuf, g_cCwdBuf);
if(strcmp("/", g_cCwdBuf))
{
strcat(g_cTmpBuf, "/");
}
strcat(g_cTmpBuf, argv[1]);
fresult = f_unlink(g_cTmpBuf); //删除文件
if(fresult != FR_OK)
{
return(fresult);
}
UARTprintf("File %s has been deleted\n",argv[1]);
return(0);
}
//////////////////////////////////////////////////////////////////////////////////
//向SD卡上的文本文件末尾追加更新内容(uart输入)
int
Cmd_edit(int argc, char *argv[])
{
FRESULT fresult;
unsigned short usBytesedit;
int strl;
f_mount(0, NULL); //更新扇区,避免原内存数据干扰更新信息的写入
fresult = f_mount(0, &g_sFatFs);
if(fresult != FR_OK)
{
UARTprintf("f_mount error: %s\n", StringFromFresult(fresult));
return(1);
}
if(strlen(g_cCwdBuf) + strlen(argv[1]) + 1 + 1 > sizeof(g_cTmpBuf))
{
UARTprintf("Resulting path name is too long\n");
return(0);
}
strcpy(g_cTmpBuf, g_cCwdBuf);
if(strcmp("/", g_cCwdBuf))
{
strcat(g_cTmpBuf, "/");
}
strcat(g_cTmpBuf, argv[1]);
UARTprintf("%d\n",g_sFileObject.fsize);
fresult = f_open(&g_sFileObject, g_cTmpBuf, FA_WRITE);
if(fresult != FR_OK)
{
return(fresult);
}
UARTprintf(">");
strl=UARTgets(tmp, sizeof(tmp));
fresult = f_lseek(&g_sFileObject, g_sFileObject.fsize); //移动读写指针到文件末尾
if(fresult != FR_OK)
{
return(fresult);
}
fresult = f_write(&g_sFileObject, tmp, strl,
&usBytesedit); //写入数据
if(fresult != FR_OK)
{
UARTprintf("\n");
return(fresult);
}
UARTprintf("Succeed!");
f_close(&g_sFileObject);
return(0);
}
///////////////////////////////////////////////////////////////////////////////////
//在评估板上的显示器上显示对应文件名的文本文件的内容
//g_cTmpBuf[]为存储文件名的字符串
int showtxt(char* g_cTmpBuf)
{
FRESULT fresult;
unsigned short usBytesRead,i=0,j=0,modified=0; //i为已读出的文本行数(10字符一行),j=0表示为首次更新
char txt1[11],txt2[11],txt3[11],txt4[11],tmp[11];
txt1[0]=0;txt2[0]=0;txt3[0]=0;txt4[0]=0; //更新用临时变量
fresult = f_open(&g_sFileObject, g_cTmpBuf, FA_READ);
if(fresult != FR_OK)
{
return(0);
}
do
{
if (bSelectPressed==1) break;//按下Select键程序退出
if (bDownPressed==1||(i<4&&j==0))//首次更新或者按下down键,显示内容下移
{
f_lseek(&g_sFileObject, (DWORD)(i*10)); //移动到读取位置
fresult = f_read(&g_sFileObject, tmp, 10,
&usBytesRead);
if(fresult != FR_OK) return(0);
tmp[usBytesRead]=0;
if(usBytesRead!=0) //未到文件末尾
{
strcpy(txt1,txt2);
strcpy(txt2,txt3);
strcpy(txt3,txt4);
strcpy(txt4,tmp);
i++;
modified=1;
}
if (i==4||usBytesRead==0) j=1;
if (i>4) SysCtlDelay(SysCtlClockGet() / 12);//暂停等待按键状态更新
}
if (bUpPressed==1&&i>4)
{
f_lseek(&g_sFileObject, (DWORD)((i-5)*10));
fresult = f_read(&g_sFileObject, tmp, 10,
&usBytesRead);
if(fresult != FR_OK) return(0);
tmp[usBytesRead]=0;
strcpy(txt4,txt3);
strcpy(txt3,txt2);
strcpy(txt2,txt1);
strcpy(txt1,tmp);
i--;
modified=1;
SysCtlDelay(SysCtlClockGet() / 12);
}
if (i>3&&modified==1) //若显示状态需要更新,更新屏幕输出
{
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 20, true);
GrStringDrawCentered(&g_sContext, txt1, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 20, true);
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 30, true);
GrStringDrawCentered(&g_sContext, txt2, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 30, true);
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 40, true);
GrStringDrawCentered(&g_sContext, txt3, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 40, true);
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 50, true);
GrStringDrawCentered(&g_sContext, txt4, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 50, true);
modified=0;
}
}
while(1);
UARTprintf("\nDone!\n");
return (0);
}
////////////////////////////////////////////////////////////////////////////////
//文本显示操作函数
int
Cmd_show(int argc, char *argv[])
{
if(strlen(g_cCwdBuf) + strlen(argv[1]) + 1 + 1 > sizeof(g_cTmpBuf))
{
UARTprintf("Resulting path name is too long\n");
return(0);
}
strcpy(g_cTmpBuf, g_cCwdBuf);
if(strcmp("/", g_cCwdBuf))
{
strcat(g_cTmpBuf, "/");
}
strcat(g_cTmpBuf, argv[1]);
UARTprintf("%s",g_cTmpBuf); //得到有效文件名
showtxt(g_cTmpBuf);
GrContextFontSet(&g_sContext, g_pFontFixed6x8); //回复屏幕输出
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 20, true);
GrStringDrawCentered(&g_sContext, "Connect a", -1,
GrContextDpyWidthGet(&g_sContext) / 2, 20, false);
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 30, true);
GrStringDrawCentered(&g_sContext, "terminal", -1,
GrContextDpyWidthGet(&g_sContext) / 2, 30, false);
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 40, true);
GrStringDrawCentered(&g_sContext, "to UART0.", -1,
GrContextDpyWidthGet(&g_sContext) / 2, 40, false);
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 50, true);
GrStringDrawCentered(&g_sContext, "115000,N,8,1", -1,
GrContextDpyWidthGet(&g_sContext) / 2, 50, false);
return(0);
}
/////////////////////////////////////////////////////////////////////////////////////////
//刷新屏幕显示的文件列表
//i为屏幕上最后一行对应的文件在列表中位置,j为选定文件在列表中位置
int
lsupdate(int i,int j,char sf[])
{
int ulfileCount=0;
tRectangle sRect1;
if (j==0) return (i); //列表到顶,不更新
if (j>i) i++; //列表下移更新
if (j<=i-4) i--; //列表上移更新
f_opendir(&g_sDirObject, g_cCwdBuf); //打开路径供读取
GrContextFontSet(&g_sContext, g_pFontFixed6x8); //掩盖旧信息
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 20, true);
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 30, true);
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 40, true);
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 50, true);
while(1)
{
f_readdir(&g_sDirObject, &g_sFileInfo);
if(!g_sFileInfo.fname[0])
{
i=ulfileCount;
return (i);
}
if(!(g_sFileInfo.fattrib & AM_DIR))
{
ulfileCount++;
if (ulfileCount==j) //记录选定文件的信息,并在屏幕上进行高亮显示
{
strcpy(sf,g_sFileInfo.fname);
sRect1.sXMin = 0;
sRect1.sYMin = (3-i+j)*10+17;
sRect1.sXMax = GrContextDpyWidthGet(&g_sContext) - 1;
sRect1.sYMax = (3-i+j)*10+23;
GrContextForegroundSet(&g_sContext, ClrDarkGreen);
GrRectFill(&g_sContext, &sRect1);
GrContextForegroundSet(&g_sContext, ClrWhite);
}
//更新屏幕列表信息,共四行
if (ulfileCount==i-3)
{
if (i!=3)
{
GrContextFontSet(&g_sContext, g_pFontFixed6x8);
GrStringDrawCentered(&g_sContext, g_sFileInfo.fname, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 20, false);
}
}
if (ulfileCount==i-2)
{
GrContextFontSet(&g_sContext, g_pFontFixed6x8);
GrStringDrawCentered(&g_sContext, g_sFileInfo.fname, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 30, false);
}
if (ulfileCount==i-1)
{
GrContextFontSet(&g_sContext, g_pFontFixed6x8);
GrStringDrawCentered(&g_sContext, g_sFileInfo.fname, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 40, false);
}
if (ulfileCount==i)
{
GrContextFontSet(&g_sContext, g_pFontFixed6x8);
GrStringDrawCentered(&g_sContext, g_sFileInfo.fname, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 50, false);
break;
}
}
}
return (i);
}
///////////////////////////////////////////////////////////////////////////////////////////////
//在评估板上显示屏显示SD卡上的文件列表
int
Cmd_showls(int argc, char *argv[])
{
int i=4,j=1,modified=0;
//i为屏幕上最后一行对应的文件在列表中位置,j为选定文件在列表中位置,modified为刷新标志
int ti,tj;
char sf[PATH_BUF_SIZE];
ti=i;tj=j;
sf[0]=0;
i=lsupdate(i,j,sf);
while(1)
{
if (bUpPressed==1&&j!=0)//按下up,选定位置减一
{
j--;
modified=1;
SysCtlDelay(SysCtlClockGet() / 12);
}
if (bDownPressed==1)//按下down,选定位置加一
{
j++;
modified=1;
SysCtlDelay(SysCtlClockGet() / 12);
}
if (modified==1)//跟新屏幕内容
{
ti=i;tj=j;
i=lsupdate(i,j,sf);
if (j>i) j=i;
modified=0;
}
if (bSelectPressed==1&&j==0)//列表到且按下Select,程序退出,恢复显示内容
{
GrContextFontSet(&g_sContext, g_pFontFixed6x8);
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 20, true);
GrStringDrawCentered(&g_sContext, "Connect a", -1,
GrContextDpyWidthGet(&g_sContext) / 2, 20, false);
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 30, true);
GrStringDrawCentered(&g_sContext, "terminal", -1,
GrContextDpyWidthGet(&g_sContext) / 2, 30, false);
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 40, true);
GrStringDrawCentered(&g_sContext, "to UART0.", -1,
GrContextDpyWidthGet(&g_sContext) / 2, 40, false);
GrStringDrawCentered(&g_sContext, cover, -1,
GrContextDpyWidthGet(&g_sContext) / 2, 50, true);
GrStringDrawCentered(&g_sContext, "115000,N,8,1", -1,
GrContextDpyWidthGet(&g_sContext) / 2, 50, false);
return(0);
}
if (bSelectPressed==1&&j!=0)//在浏览界面点击Select,打开选定文件,显示文本内容
{
strcpy(g_cTmpBuf, g_cCwdBuf);
bSelectPressed=0;
if(strcmp("/", g_cCwdBuf))
{
strcat(g_cTmpBuf, "/");
}
strcat(g_cTmpBuf, sf);
SysCtlDelay(SysCtlClockGet() / 4);
showtxt(g_cTmpBuf);
SysCtlDelay(SysCtlClockGet() / 4);
lsupdate(ti,tj,sf);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
//播放wav格式文件
int
Cmd_playwav(int argc, char *argv[])
{
FRESULT fresult;
unsigned short usBytesRead,i=0,refresh=1;
volatile unsigned short left,right;
wav_pcm_header44 hwav;//文件头信息
char data[64];//数据缓存数组
unsigned long delaytime;
if(strlen(g_cCwdBuf) + strlen(argv[1]) + 1 + 1 > sizeof(g_cTmpBuf))
{
UARTprintf("Resulting path name is too long\n");
return(0);
}
strcpy(g_cTmpBuf, g_cCwdBuf);
if(strcmp("/", g_cCwdBuf))
{
strcat(g_cTmpBuf, "/");
}
strcat(g_cTmpBuf, argv[1]);
fresult = f_open(&g_sFileObject, g_cTmpBuf, FA_READ);
fresult = f_read(&g_sFileObject, &hwav, sizeof(hwav),&usBytesRead);
//读入文件信息
if(fresult != FR_OK)
{
UARTprintf("\n");
return(fresult);
}
if (!strcmp(hwav.Format,"WAVE")) return (0);//若文件不为wav文件,退出
delaytime=ROM_SysCtlClockGet()/hwav.SampleRate;
delaytime/=3;
ROM_SSIDisable(SSI1_BASE); //使能SSI模块
ROM_SysCtlDelay(100);
ROM_SSIConfigSetExpClk(SSI1_BASE, ROM_SysCtlClockGet(),
SSI_FRF_MOTO_MODE_1, SSI_MODE_MASTER,
hwav.SampleRate*hwav.BitsPerSample, 16);
ROM_SSIEnable(SSI1_BASE);
ROM_SysCtlDelay(100);
while(1)
{
if (refresh==1)//每读64字节,更新一次缓存
{
fresult = f_read(&g_sFileObject, data,64,&usBytesRead);
UARTprintf("%d\n",usBytesRead);
if (usBytesRead==0) break;
refresh=0;
}
if(fresult != FR_OK)
{
UARTprintf("\n");
return(fresult);
}
//根据不同的通道数与比特率进行数据读取,读取信息存储为16bits的left,right
if (hwav.BitsPerSample==8)
{
left=(unsigned short)data[i++];
if (hwav.NumChannels==1)
{
right=left;
}
else
{
right=(unsigned short)data[i++];
}
}
else
{
left=(unsigned short)data[i+1];
left=left<<8;
left+=(unsigned short)data[i];
i+=2;
if (hwav.NumChannels==1)
{
right=left;
}
else
{
right=(unsigned short)data[i+1];
right=right<<8;
right+=(unsigned short)data[i];
i+=2;
}
left=left>>4;
right=right>>4; //DAC为12位,舍去四位,
}
left+=0x4000; //加入控制字
right+=0x8000;
ROM_SSIDataPut(SSI1_BASE, left);
while(ROM_SSIBusy(SSI1_BASE))
{
}
ROM_SSIDataPut(SSI1_BASE, right);
while(ROM_SSIBusy(SSI1_BASE))
{
}
SysCtlDelay(delaytime-100);
if (i==64)
{
i=0;
refresh=1;
// UARTprintf("%d\n",left);
}
if (usBytesRead<64&&i>=usBytesRead) break;//读到文件尾,退出
}
return(0);
}
//*****************************************************************************
// This is the table that holds the command names, implementing functions, and
// brief description.
//*****************************************************************************
tCmdLineEntry g_sCmdTable[] =
{
{ "help", Cmd_help, " : Display list of commands" },
{ "h", Cmd_help, " : alias for help" },
{ "?", Cmd_help, " : alias for help" },
{ "ls", Cmd_ls, " : Display list of files" },
{ "chdir", Cmd_cd, ": Change directory" },
{ "cd", Cmd_cd, " : alias for chdir" },
{ "pwd", Cmd_pwd, " : Show current working directory" },
{ "cat", Cmd_cat, " : Show contents of a text file" },
{ "new", Cmd_new, " : Create a new file" },
{ "delete", Cmd_delete, " : Delete a existed file " },
{ "edit", Cmd_edit, " : Edit a existed file " },
{ "show", Cmd_show, " : show the file content on the screen" },
{ "showls", Cmd_showls, " : show the list of files on the screen" },
{ "playwav", Cmd_playwav, " : play the wav music file" },
{ 0, 0, 0 }
};
//*****************************************************************************
// The error routine that is called if the driver library encounters an error.
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, unsigned long ulLine)
{
}
#endif
//*****************************************************************************
// The program main function. It performs initialization, then runs a command
// processing loop to read commands from the console.
//*****************************************************************************
int
main(void)
{
int nStatus;
FRESULT fresult;
// The FPU should be enabled because some compilers will use floating-
// point registers, even for non-floating-point code. If the FPU is not
// enabled this will cause a fault. This also ensures that floating-
// point operations could be added to this application and would work
// correctly and use the hardware floating-point unit. Finally, lazy
// stacking is enabled for interrupt handlers. This allows floating-
// point instructions to be used within interrupt handlers, but at the
// expense of extra stack usage.
FPUEnable();
FPULazyStackingEnable();
// Set the system clock to run at 50MHz from the PLL.
ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_16MHZ);
// Enable the peripherals used by this example.
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG);
// Configure SysTick for a 100Hz interrupt. The FatFs driver wants a 10 ms
// tick.
ROM_SysTickPeriodSet(ROM_SysCtlClockGet() / 100);
ROM_SysTickEnable();
ROM_SysTickIntEnable();
//configure the ssi port
ROM_GPIOPinConfigure(GPIO_PD0_SSI1CLK);
ROM_GPIOPinConfigure(GPIO_PD1_SSI1FSS);
ROM_GPIOPinConfigure(GPIO_PD3_SSI1TX);
ROM_GPIOPinTypeSSI(GPIO_PORTD_BASE, (GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3));
ROM_GPIOPinTypeGPIOOutput(GPIO_PORTG_BASE,GPIO_PIN_3);
//how to adjust the ssi mode for the high-quality radio
ROM_GPIOPinWrite(GPIO_PORTG_BASE,GPIO_PIN_3, GPIO_PIN_3);
// Enable Interrupts
ROM_IntMasterEnable();
// Set GPIO A0 and A1 as UART.
ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
// Initialize the UART as a console for text I/O.
UARTStdioInit(0);
ButtonsInit();
// Initialize the display driver.
CFAL96x64x16Init();
// Initialize the graphics context.
GrContextInit(&g_sContext, &g_sCFAL96x64x16);
// Fill the top part of the screen with blue to create the banner.
sRect.sXMin = 0;
sRect.sYMin = 0;
sRect.sXMax = GrContextDpyWidthGet(&g_sContext) - 1;
sRect.sYMax = 9;
GrContextForegroundSet(&g_sContext, ClrDarkBlue);
GrRectFill(&g_sContext, &sRect);
// Change foreground for white text.
GrContextForegroundSet(&g_sContext, ClrWhite);
// Put the application name in the middle of the banner.
GrContextFontSet(&g_sContext, g_pFontFixed6x8);
GrStringDrawCentered(&g_sContext, "sd_card", -1,
GrContextDpyWidthGet(&g_sContext) / 2, 4, 0);
// Show some instructions on the display
GrContextFontSet(&g_sContext, g_pFontFixed6x8);
GrStringDrawCentered(&g_sContext, "Connect a", -1,
GrContextDpyWidthGet(&g_sContext) / 2, 20, false);
GrStringDrawCentered(&g_sContext, "terminal", -1,
GrContextDpyWidthGet(&g_sContext) / 2, 30, false);
GrStringDrawCentered(&g_sContext, "to UART0.", -1,
GrContextDpyWidthGet(&g_sContext) / 2, 40, false);
GrStringDrawCentered(&g_sContext, "115000,N,8,1", -1,
GrContextDpyWidthGet(&g_sContext) / 2, 50, false);
// Print hello message to user.
UARTprintf("\n\nSD Card Example Program\n");
UARTprintf("Type \'help\' for help.\n");
// Mount the file system, using logical disk 0.
fresult = f_mount(0, &g_sFatFs);
if(fresult != FR_OK)
{
UARTprintf("f_mount error: %s\n", StringFromFresult(fresult));
return(1);
}
// Enter an infinite loop for reading and processing commands from the user.
while(1)
{
//
// Print a prompt to the console. Show the CWD.
//
UARTprintf("\n%s> ", g_cCwdBuf);
// Get a line of text from the user.
UARTgets(g_cCmdBuf, sizeof(g_cCmdBuf));
// Pass the line from the user to the command processor. It will be
// parsed and valid commands executed.
nStatus = CmdLineProcess(g_cCmdBuf);
// Handle the case of bad command.
if(nStatus == CMDLINE_BAD_CMD)
{
UARTprintf("Bad command!\n");
}
// Handle the case of too many arguments.
else if(nStatus == CMDLINE_TOO_MANY_ARGS)
{
UARTprintf("Too many arguments for command processor!\n");
}
// Otherwise the command was executed. Print the error code if one was returned.
else if(nStatus != 0)
{
UARTprintf("Command returned error code %s\n",
StringFromFresult((FRESULT)nStatus));
}
}
}