📄 player.c
字号:
//++
//player.c - system startup, POST, and initialization
//
// Copyright (C) 2005 by Spare Time Gizmos. All rights reserved.
//
// This file is part of the Spare Time Gizmos' MP3 Player firmware.
//
// This firmware is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA
//
//DESCRIPTION:
//
//TODO:
//
// REVISION HISTORY:
// dd-mmm-yy who description
// 15-May-05 RLA New file.
// 12-Oct-05 RLA SDCC doesn't support printf precision for strings
// The SDCC __DATE__ macro returns too many characters
// On non-FAT volumes, don't display the volume label
// Change calling sequences for FAT and CFCARD routines
// 15-Oct-05 RLA Add VOLUME conditional
// 19-Oct-05 RLA Call ResetMP3Decoder() to abort playing (when the knob
// is turned). This avoids noise in the output.
//--
// Include files...
#include <stdio.h> // needed so DBGOUT(()) can find printf!
#include <string.h> // needed for memcpy(), memset(), et al...
#include "reg66x.h" // declarations for Philips 89C66x processors
#include "standard.h" // standard types - BYTE, WORD, BOOL, etc
#include "player.h" // project wide (hardware configuration) declarations
#include "post.h" // power on self test diagnostics
#include "debug.h" // debuging (serial port output) routines
#include "timer.h" // time keeping functions
#include "buffer.h" // disk buffer management functions
#include "display.h" // LCD/VFD display interface
#include "i2c.h" // I2C driver functions
#include "sta013.h" // STA013 MP3 decoder functions
#include "cfcard.h" // compact flash card interface functions
#include "fat.h" // FAT12/16 functions
#include "switches.h" // user interface (rotary encoder) functions
#include "id3.h" // ID3 tag definitions and functions
// This is the copyright notice, version, and date for the software in plain
// ASCII. Even though this only gets printed out in the debug version, it's
// always included to identify the ROM's contents...
PUBLIC char const code g_szFirmware[] =
"MP3 Player Firmware " __DATE__ " " __TIME__;
PUBLIC char const code g_szCopyright[] =
"Copyright (C) 2005 by Spare Time Gizmos. All rights reserved.";
//++
// This routine will show the copyright "screen" on the display. It will
// pause for five seconds before returning...
//--
PRIVATE void ShowCopyright (void)
{
ClearDisplay();
DisplayTextAt(0, 0, COPYRIGHT_SYMBOL " SPARE TIME GIZMOS");
DisplayTextAt(1, 0, "MP3 Player v%03u %04X", (WORD) VERSION, g_wROMChecksum);
DisplayTextAt(2, 0, " %1bdK RAM %2bdK ROM",
(BYTE) ((RAMSize()+256) >> 10), (BYTE) (ROMSIZE >> 10));
DisplayTextAt(3, 4, "%s", __DATE__);
DelayMS(5000);
//while (PUSH_BUTTON) ;
}
//++
// This routine will clear the display and show the first three (of the four)
// lines that appear while we're playing an MP3. These lines show the file name
// and (if the file has an ID3 tag) the artist and song name. The remaining
// fourth line comes from ShowPlaybackStatus()...
//--
PRIVATE void ShowPlaybackNames (PXDIRENT pxDirEnt)
{
ClearDisplay();
// If this file has an LFN (long file name) then show that on the first
// line; otherwise the traditional 8.3 name will have to do. Note that
// we never show the .MP3 extension in any case - when all files are MP3,
// why bother?
if (strlen(g_szLongFileName) > 0) {
DisplayTextAt(0,0,"%.20s", g_szLongFileName);
} else {
DisplayTextAt(0,0,"%8.8s.%3.3s", pxDirEnt->szFileName, pxDirEnt->szFileType);
}
// Now open the file and attempt to read the ID3 tag. If we get lucky and
// find one, then use that to show the title and artist.
if (ReadID3Tag(pxDirEnt)) {
DisplayTextAt(1,0,"%.20s",g_szArtistName);
DisplayTextAt(2,0,"%.20s",g_szTrackName);
}
}
//++
// And this routine will display the fourth line used while we're playing.
// This line shows the current running time (in mmm:ss), the MP3 bit rate
// (kbps) and the sampling frequency (kHz)...
//--
PRIVATE void ShowPlaybackStatus (BOOL fPaused)
{
BYTE bSeconds; WORD wMinutes;
GetElapsedTime(wMinutes);
bSeconds = (BYTE) (wMinutes % 60); wMinutes /= 60;
if (fPaused)
DisplayTextAt(3,0,"%3u:%02bu PAUSED ", wMinutes, (BYTE) bSeconds);
else
DisplayTextAt(3,0,"%3u:%02bu %3ukbps %2bukHz",
wMinutes, (BYTE) bSeconds, GetMP3BitRate(), (BYTE) GetMP3SampleFrequency());
}
//++
// Unfortunately, we don't support hot swapping of CF cards (the CF standard
// makes that pretty much impossible for any application that uses TrueIDE mode)
// so contrary to what its name might lead you to believe, this routine does NOT
// wait for a card to be inserted. If one isn't already in there at power up,
// this routine just displays an error message and returns FALSE, and that will
// make the main program loop forever until the user reboots us.
//
// If a CompactFlash card is inserted now, then this routine will initialize
// the IDE interface and attempt to find a FAT16 filesystem on it. If we're
// successful it will display a brief status screen (for about 2 seconds) and
// then return TRUE; if the card can't be read or if it doesn't contain a FAT16
// file system, then an error message is displayed and FALSE results.
//--
PRIVATE BOOL IsCardReady (void)
{
ClearDisplay();
// If there's no CF card in the socket now, then tell him to turn off the
// power, insert one, and try again...
if (!IsCardInserted()) {
DBGOUT(("??IsCardReady: No card inserted ...\n"));
// 01234567890123456789
DisplayStringAt(0,0,"???? NO CF CARD ????");
//DisplayStringAt(1,0," ");
DisplayStringAt(2,0," insert card and ");
DisplayStringAt(3,0," cycle power ");
return FALSE;
}
// Initialize the IDE interface. If we can't, then either the card is bad
// or he has tried to hot swap it (which prevents the card from going into
// TrueIDE mode). Either way he has to restart...
if (!InitializeCard()) {
DBGOUT(("??IsCardReady: Failed to initialize TrueIDE interface ...\n"));
// 01234567890123456789
DisplayStringAt(0,0,"????? BAD CARD ?????");
//DisplayStringAt(1,0," ");
DisplayStringAt(2,0,"unable to initialize");
DisplayStringAt(3,0," TrueIDE interface ");
return FALSE;
}
// Identify the card's manufacturer, type and size. Mostly this is just for
// show, but it does serve to verify that the card really is a Flash Memory
// device (after all, it might be a modem or a network card or anything!)...
if (!IdentifyCard()) {
DBGOUT(("??IsCardReady: Unrecognized card \"%s\"\n", g_szCardName));
// 01234567890123456789
DisplayStringAt(0,0,"????? BAD CARD ?????");
//DisplayStringAt(1,0," ");
DisplayStringAt(2,0," unable to identify ");
DisplayStringAt(3,0," card type ");
return FALSE;
}
DisplayTextAt(0, 0, "%.20s", g_szCardName);
DisplayTextAt(1, 0, "Type %04X Size %uMb", g_wCardAttributes, g_wCardSize);
// Finally, try to find a file system that we can deal with...
if (!InitializeFAT()) {
DBGOUT(("??IsCardReady: Not a FAT16 file system \"%s\"\n", g_szSystemType));
// 01234567890123456789
DisplayStringAt(2,0,"??? not a FAT16 ???");
DisplayStringAt(3,0,"??? file system ???");
//DisplayTextAt(1, 10, "%s", g_szSystemType);
return FALSE;
}
// It's a good card and a good file system. Find the volume label and
// count the number of MP3 files in the root directory. If there are no
// MP3 files, then there's nothing we can do with this card!
GetVolumeData();
DisplayTextAt(2,0,"%11.11s", g_szVolumeLabel);
if (g_wTotalMP3Files == 0) {
// 01234567890123456789
DisplayStringAt(3,0,"??? no mp3 files ???");
return FALSE;
}
DisplayTextAt(3,0,"%u MP3 Files", g_wTotalMP3Files);
// Delay a few moments so the user can read the screen and then return...
DelayMS(5000);
return TRUE;
}
//++
// This routine will play one MP3 file given its directory entry. Ordinarily
// it will play the entire file, beginning to end, and won't return until the
// end of file is reached. A basic pause/resume function, using the push button,
// is implemented locally. If, however, the rotary encoder is turned this
// routine will abort playback of the current file and return immediately. It
// doesn't change the value of g_nEncoderCount in the process of doing this -
// it's up to the caller to notice that this value is non-zero and skip forward
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -