📄 mp3init.c
字号:
void DisplayReady (void)
/* Simply writes "Ready" on the 3rd line of the LCD display, blanks out 4th line */
{
UART1_TxCharWaitC(0x5c);
UART1_TxCharWaitC(0x42);
UART1_TxCharWaitC(32);
UART1_TxCharWaitC(34); /* put cursor on start of 3rd row (row #2) */ /* put cursor on start of 2nd row */
uart1_putwaitPROGstr(PSTR("Ready ")); /* and display "ready" */
}
void DisplayWait (void)
/* Simply writes "One moment please..." on the 4th line of the LCD display */
/* Used at power-up. */
{
UART1_TxCharWaitC(0x5c);
UART1_TxCharWaitC(0x42);
UART1_TxCharWaitC(32);
UART1_TxCharWaitC(35); /* put cursor on start of 4th line (row #3) */ /* put cursor on start of 2nd row */
uart1_putwaitPROGstr(PSTR("One moment please...")); /* and display the string */
}
void DisplayName (void)
// Simply writes MP3 player's name on top line of LCD display
{
UART1_TxCharWaitC(0x5c);
UART1_TxCharWaitC(0x42);
UART1_TxCharWaitC(32);
UART1_TxCharWaitC(32);
uart1_putwaitPROGstr(PSTR(" Frank's MP3 Player")); /* write string to LCD display */
}
void LED_ON (void)
// turns the AVR LED on
{
*AVR_DDRB = *AVR_DDRB | 0x10; /* make the LED bit an output */
*AVR_PORTB = *AVR_PORTB & 0xEF; /* and set the bit low */
}
void LED_OFF (void)
// turns the AVR LED off (set PortB bit 4 high)
{
*AVR_PORTB = *AVR_PORTB | 0x10; /* turn front-panel LED off */
*AVR_DDRB = *AVR_DDRB | 0x10; /* make the LED bit an output */
}
void LCD_LIGHT_ON (void)
// turns the LCD Backlighting on; Port F bit 5 high to switch it on
{
*AVR_PORTF = *AVR_PORTF | 0x20; /* set the LCD backlight bit high */
*AVR_DDRF = *AVR_DDRF | 0x20; /* make the LCD backlight bit an output */
}
void LCD_LIGHT_OFF (void)
// turns the LCD Backlighting off; Port F bit 5 low to switch it off
{
*AVR_PORTF = *AVR_PORTF & 0xDF; /* set the LCD backlight bit low */
*AVR_DDRF = *AVR_DDRF | 0x20; /* ensure the LCD backlight bit an output */
}
void CntMP3files (void)
/* This routine may be called at startup to ensure we know the number of MP3 files in the */
/* current directory. At some point this will be extended to support playlists & subdirectories */
/* (maybe!) but not right now. We need to know the number of MP3 files for random mode, and */
/* the FastFind table, to work. */
/* Better to count them once at power-up than interrupt playing if the user selects random */
/* mode and we have to count them then. */
/* FYI, the eeprom count value is zeroed if the user plugs the USB cable in. */
{
u16 i;
PositionLCDcursor (2, 1); // place cursor at start of second row of display
uart1_putwaitPROGstr(PSTR("Counting MP3 Files ")); /* tell user what's going on */
i = CountMP3files(); /* count the files */
EEPROM_Write(StoreNumFilesL, (u08)(i&0x00ff)); /* write low count byte into eeprom */
EEPROM_Write(StoreNumFilesH, (u08)(i>>8)); /* write high count bye into eeprom */
PositionLCDcursor (2, 1); // place cursor at start of second row of display
PrintASCIIword (i, 1); // display ascii number of files on lcd
uart1_putwaitPROGstr(PSTR(" MP3 files found.")); // followed by some helpful text
}
u16 CountMP3files (void)
// Warning: SLOW. Does not return until completed.
// This routine counts the number of MP3 files in the current directory,
// without using FindFileC. Hopefully it'll be faster! It uses StreamFileC
// to stream the entire directory into the MP3dataQ, then reads out the files,
// counting the MP3 files as it goes, until the directory ends. Some notes:
// - If the FAT has an error in it, the directory cluster chain can end before
// the directory is properly finished. This is detected by noticing that
// StreamFileC has idled prematurely.
// - Directory entires are 32 bytes. So don't try reading anything until you
// know you have at least 32 bytes in the data queue.
// - We don't know how long the directory is. So give StreamFileC a huge file size
// number, so that it'll stream until it can't stream no more!
{
u16 filecount;
u08 i, firstchar, extm, extp, ext3, attr;
// Ensure StreamFileC stopped
STREAMFILE_CMD = StreamFile_Cmd_Stop; // command StreamFileC to STOP
StreamFileC();
while (STREAMFILE_ST!=StreamFile_St_Idle) StreamFileC(); // wait until StreamFileC idle
// Ensure MP3dataQ empty
Q_clear_C((u08*)&MP3DATAQ[0]);
// Command StreamFileC to stream current directory into the MP3dataQ
STREAMFILE_FILESZ = 0xFFFFFFF; // huge "file size"
STREAMFILE_CLUS = CURRENT_DIRCL; // cluster number for start of current directory
STREAMFILE_QPOINTER = &MP3DATAQ[0]; // point StreamFile to the MP3 Data queue
STREAMFILE_CMD = StreamFile_Cmd_Stream; // command StreamFileC to start streaming
StreamFileC();
StreamFileC();
filecount = 0;
// Don't really loop forever - we'll break out of this while loop with return statements!
while (1) {
// Wait until 32 bytes in queue. If StreamFileC goes idle, return.
while ( Q_HowMuchDataC((u08*)&MP3DATAQ[0]) < 32 ) {
StreamFileC();
if ( (STREAMFILE_ST==StreamFile_St_Idle) && (Q_HowMuchDataC((u08*)&MP3DATAQ[0])<32) )
return filecount;
}
// We now have 32 bytes in the queue; a directory entry's worth. Read them out of
// the queue, keeping a few of them for later review, discarding the rest. The first 12 bytes in
// the queue are the short filename (8.3) and the file attributes. If the first byte is zero,
// return, also telling StreamFileC to stop, because there are no more files in this directory.
firstchar = Q_read_C((u08*)&MP3DATAQ[0]); // get first character of filename
if (firstchar == 0x00 ) {
STREAMFILE_CMD = StreamFile_Cmd_Stop; // tell StreamFileC to stop, then
while (STREAMFILE_ST!=StreamFile_St_Idle) StreamFileC(); // wait until it's idle
return filecount;
}
for (i=7;i;i--)
Q_read_C((u08*)&MP3DATAQ[0]); // ignore next 7 characters of the filename
extm = Q_read_C((u08*)&MP3DATAQ[0]);
extp = Q_read_C((u08*)&MP3DATAQ[0]);
ext3 = Q_read_C((u08*)&MP3DATAQ[0]); // hopefully these 3 are "MP3"
attr = Q_read_C((u08*)&MP3DATAQ[0]); // get file attributes
for (i=20;i;i--)
Q_read_C((u08*)&MP3DATAQ[0]); // throwaway remainder of the 32 bytes
// Increment filecount if we've found an MP3 file
if ( firstchar!=0xE5 && extm=='M' && extp=='P' && ext3=='3' && !(attr&0x1E) )
filecount++;
// give StreamFileC another chance to run, then loop back for the next directory entry
StreamFileC();
}
}
void BuildFastFindTable (void)
// This routine builds the FastFind table, used by FindNthMP3 to greatly accelerate
// the location of the "Nth" MP3 file. Here's how it works:
// - There are NumFFEntries entries in the table. Each entry is 6 bytes: a 2-byte file
// number and a 4-byte cluster number.
// - The file number is the number of the first MP3 file in that cluster.
// - The first file number in the table is always 1.
// This routine makes an "estimate" of the number of MP3 files per entry by dividing the total
// number of files in the directory by NumFFEntries. This is then used to set "target"
// file numbers. We count though the files on the disk, and when the "target" filenumber
// is reached we record in the table the file number of the first MP3 file in the current cluster.
{
u08 entries, i, firstchar, extm, extp, ext3, attr;
u16 filecount, filestep, filetarget, firstfile, eepromaddr, clusterbytecount;
u32 cluster;
// display message to user on 3rd line of lcd display
PositionLCDcursor (3, 1); // place cursor at start of third row of display
uart1_putwaitPROGstr(PSTR("Building FastFind table ")); /* and display the string */
// general initializations
eepromaddr = (u16)FFTableStart; // eeprom address of start of table
cluster = (u32)CURRENT_DIRCL; // cluster number for start of current directory
clusterbytecount = 0; // we've read nothing from the current cluster yet
filetarget = 1; // initial file number target
filecount = 0; // no files counted yet
firstfile = 0; // this init just to keep compiler happy
// get number of MP3 files in directory (use filestep variable just 'cause it's free :-)
filestep = (((u16)EEPROM_ReadC(StoreNumFilesH))<<8) + (u16)EEPROM_ReadC(StoreNumFilesL);
// if too few MP3 files, don't properly build the table; just fill it with "dummy" data & return
if (filestep <= 2*NumFFEntries) {
for (i=0; i<NumFFEntries; i++) {
EEPROM_Write(eepromaddr++, 1);
EEPROM_Write(eepromaddr++, 0); // filenumber = 0x0001
EEPROM_Write(eepromaddr++, (u08)cluster);
EEPROM_Write(eepromaddr++, (u08)(cluster>>8));
EEPROM_Write(eepromaddr++, (u08)(cluster>>16));
EEPROM_Write(eepromaddr++, (u08)(cluster>>24)); // cluster number is always first cluster
}
return;
}
// Calculate estimated step between filenumbers: number of files / number of table entries
filestep = (filestep - 1) / NumFFEntries;
FeedSTcodec_Command = FSC_Cmd_Stop; // ensure ST codec not trying to read MP3 data Q
// Ensure StreamFileC stopped
STREAMFILE_CMD = StreamFile_Cmd_Stop; // command StreamFileC to STOP
StreamFileC();
while (STREAMFILE_ST!=StreamFile_St_Idle) StreamFileC(); // wait until StreamFileC idle
// Ensure MP3dataQ empty
Q_clear_C((u08*)&MP3DATAQ[0]);
// Command StreamFileC to stream current directory into the MP3dataQ
STREAMFILE_FILESZ = 0xFFFFFFF; // huge "file size"
STREAMFILE_CLUS = cluster; // cluster number for start of current directory
STREAMFILE_QPOINTER = &MP3DATAQ[0]; // point StreamFile to the MP3 Data queue
STREAMFILE_CMD = StreamFile_Cmd_SmWithCl; // command StreamFileC to start streaming, provide cluster numbers
StreamFileC();
StreamFileC();
StreamFileC();
// loop until we've written into the table NumFFEntries times
entries = NumFFEntries;
while (entries) {
// if clusterbytecount is zero, we need to read the 4-byte cluster number out of the data Q,
// and reset the clusterbyte counter. FYI, a multiply by 512 is a left-shift of 9 bits.
if (clusterbytecount == 0) {
// wait until 4 bytes in data Q. If StreamFileC goes idle, return
while ( Q_HowMuchDataC((u08*)&MP3DATAQ[0]) < 4 ) {
StreamFileC();
if ( (STREAMFILE_ST==StreamFile_St_Idle) && (Q_HowMuchDataC((u08*)&MP3DATAQ[0])<4) )
return;
}
// extract cluster number low-byte first, reset clusterbytecount, save current filecount, and continue along...
cluster = ((u32)Q_read_C((u08*)&MP3DATAQ[0])) + (((u32)Q_read_C((u08*)&MP3DATAQ[0]))<<8) + \
+ (((u32)Q_read_C((u08*)&MP3DATAQ[0]))<<16) + (((u32)Q_read_C((u08*)&MP3DATAQ[0]))<<24);
clusterbytecount = ((u16)SEC_PER_CLUS)<<9; // number of bytes per cluster
firstfile = filecount + 1; // filenumber for first file in this upcoming cluster
}
// Wait until 32 bytes (a directory entry) in queue. If StreamFileC goes idle, return.
while ( Q_HowMuchDataC((u08*)&MP3DATAQ[0]) < 32 ) {
StreamFileC();
if ( (STREAMFILE_ST==StreamFile_St_Idle) && (Q_HowMuchDataC((u08*)&MP3DATAQ[0])<32) )
return;
}
// We now have 32 bytes in the queue; a directory entry's worth. Read them out of
// the queue, keeping a few of them for later review, discarding the rest. The first 12 bytes in
// the queue are the short filename (8.3) and the file attributes. If the first byte is zero,
// return, also telling StreamFileC to stop, because there are no more files in this directory.
firstchar = Q_read_C((u08*)&MP3DATAQ[0]); // get first character of filename
if (firstchar == 0x00 ) {
STREAMFILE_CMD = StreamFile_Cmd_Stop; // tell StreamFileC to stop, then
while (STREAMFILE_ST!=StreamFile_St_Idle) StreamFileC(); // wait until it's idle
return;
}
for (i=7;i;i--)
Q_read_C((u08*)&MP3DATAQ[0]); // ignore next 7 characters of the filename
extm = Q_read_C((u08*)&MP3DATAQ[0]);
extp = Q_read_C((u08*)&MP3DATAQ[0]);
ext3 = Q_read_C((u08*)&MP3DATAQ[0]); // hopefully these 3 are "MP3"
attr = Q_read_C((u08*)&MP3DATAQ[0]); // get file attributes
for (i=20;i;i--)
Q_read_C((u08*)&MP3DATAQ[0]); // throwaway remainder of the 32 bytes
// Increment filecount if we've found an MP3 file
if ( firstchar!=0xE5 && extm=='M' && extp=='P' && ext3=='3' && !(attr&0x1E) )
filecount++;
// decrement cluster byte counter by the 32 bytes we just read out; give StreamFileC another chance to run
clusterbytecount -= 32;
StreamFileC();
// check to see if we've reached our target filecount number, ie, if time to put entry into table
if (filecount == filetarget) {
// Fill in table entry. Low bytes first.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -