📄 zcontrol.c
字号:
/*
Copyright 2003 Nasif Akand (nasif@yifan.net)
http://go.to/zipamp
http://zipamp.virtualave.net
This file is part of ZipAmp MP3 software.
ZipAmp 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.
ZipAmp 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 code; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//This module performs different control operation for ZipAmp
//Nasif Akand
//If using CodeVision then following includes aren't needed.
#include "zcontrol.h"
//#include "zfat.h"
//#include "zata.h"
//#include "ztype.h"
//#include "i2c.h"
//#include "<delay.h>" //CodeVision AVR internal delay routines
//mask for cyclic buffer of clusterBuffer, check zata.h for clustBuf size
#define clustBufMask ClusterBufSize-1
void readFile(word wordToRead){ //
//Reads the current file word by word, no cluster buffering, used for generic file reading
if ((sectorPos==Sectors_Per_Cluster)) { //if whole cluster is already read then
currentCluster=findNextCluster(); //a new cluster must be read by looking into FAT
readPos=0;
sectorPos=0;
}
ATA_Read_Sectors_LBA(clust2LBA(currentCluster)+sectorPos,wordToRead); //read # of words;
filePos += (wordToRead<<1); //filepos = filepos+ (wordtoread*2)
}
void read() {
//This function is similar to above but reads 256 bytes at a time
//It is only used with cluster buffering for MP3 playback.
//The code below has been repeated many times. A function was
//was not written because of speed considerations.
if (sectorPos==Sectors_Per_Cluster) { //Check if a cluster has been already read.
if (readClusterBuffer()!=1) { //If cluster buffer is empty.
currentCluster=findNextCluster(); //find next cluster
}
sectorPos=0; //reset parameters
readPos=0;
headMoved=0;
}
//if head wasn't moved when we reached at sector end then move head.
//That will happen when readPos and headMoved both are 0.
if ((readPos|headMoved)==0) ATA_Move_Head(clust2LBA(currentCluster)+sectorPos);
ATA_Read(128); //Read 128 words
filePos += 256; //Increment file position.
}
byte writeClusterBuffer() {
//Fills up the cyclic buffer of clusterBuffer
//Writes clusterBuffer.cluster with next cluster address of the current file chain
//Returns 1 if buffering was successful, otherwise 0 if buffer is already full.
dword tempClust;
if (((clusterBufferWritePos+1)& clustBufMask) != clusterBufferReadPos) { //if buffer is not full
tempClust=currentCluster;
if (clusterBufferWritePos!=clusterBufferReadPos)
//If buffer is not empty then get the previous cluster from buffer to find Next cluster
currentCluster=clusterBuffer.cluster[(clusterBufferWritePos-1) & clustBufMask];
//findNextCluster function will looks at currentCluster
clusterBuffer.cluster[clusterBufferWritePos]=findNextCluster();
//increment buffer write pos and AND with mask
clusterBufferWritePos = (clusterBufferWritePos+1) & clustBufMask;
currentCluster=tempClust;
return 1;
}
else return 0; //Buffer is full, can't buffer anymore
}
byte readClusterBuffer() {
//Reads next cluster from cluster buffer if it is not empty
//Returns 1 if successfull, 0 if failed.
//Cluster address is returned in currentCluster.
if (clusterBufferWritePos != clusterBufferReadPos) { //if not empty buffer
currentCluster=clusterBuffer.cluster[clusterBufferReadPos];
clusterBufferReadPos = (clusterBufferReadPos+1) & clustBufMask;
return 1;
}
else return 0;
}
byte DecodeID3Frame(dword FrameStrVal,byte offset) {
//Decodes ID3v2 tag.
//This is very crude way to decode ID3 tags. It was done to fit the code in AVR 8515.
//This function only looks at first 256bytes of MP3 file for ID3v2 tags. If its not there
//then we are out of luck. Do not take this function as your guide to ID3 tag decoding.
//It was only written to decode TIT2 and TPE1 frames.
//FrameStrVal is value of ID3 frame name string in binary. e.g. TIT2 = 0x54495432
//offset is the storage offset in fileName string.
//Returns 0 if decoding failed, otherwise it returns the offset at fileName string.
byte i;
dword strn; //storage for binary ID3v2 frame name.
readPos=0; //need to read a sector, set readPos=0
//Read the first 256 bytes of MP3 file. This is where we will look for ID3v2 tag.
ATA_Read_Sectors_LBA(clust2LBA(currentCluster),128);
readPos=0;
while (readPos<220) {
//looks in first 256 bytes, we actually finish by 220 bytes so that we don't cross array
//boundary when we are doing following instructions in the loop.
if (sectorBuffer.data[readPos]=='T') //Check if its start of TIT2 or TPE1 frame
for(i=0; i<4; i++) strn=(strn<<8)+sectorBuffer.data[readPos+i]; //Load the bytes into strn for comparision
if (strn!=FrameStrVal) goto FAIL; //Check if its the frame that we are looking for
mp3Pos=sectorBuffer.data[readPos+7]; //mp3Pos is used to store Frame length
readPos += 11; //Increment readPos by frame record size (11 bytes) so we can start reading text data.
mp3Pos += offset; //Increment mp3Pos with offset so that we are ready to copy into fileName string.
while ((offset<41)&&(offset<mp3Pos)) { //If there is more space left in the string.
fileName[offset++]=sectorBuffer.data[readPos++];
}
offset--; //Decrement offset by 1
fileName[offset]=0; //Set last fileName char to NULL.
return offset; //finished reading frame, so retrn.
FAIL: //We reach here only if we didn't find the frame that we were looking for.
readPos++;
}
return 0; //We failed, so return 0.
}
void SongSelect() {
//This function finds an MP3 file based on current play mode.
//Saves player status. Fixes the LCD display.
byte offset,i=0;
if (playMode==1) { //If its Random mode.
dirReadOffset.fileNum=0;
currentFileNum=randomKey(); //get random file number
}
if (getDirEntry(1)!=0) { //get an MP3 file.
offset=DecodeID3Frame(TPE1,0); //Decode frame TPE1, and store in fileName offset 0
i=0;
//If we found TPE1 then put " - " character.
if (offset>0) while((offset<41)&&(i<3)) fileName[offset++]=dash[i++];
DecodeID3Frame(TIT2,offset); //Decode frame TIT2, and store in fileName offset position.
saveConfig(); //Save the ZipAmp status in hard drive.
firstCluster=currentCluster; //Remember the starting cluster of the file.
clusterBufferReadPos=0; clusterBufferWritePos=0; //Clear cluster buffer
while (writeClusterBuffer()!=0); //Now Fillup the cluster buffer.
UnBusy(); //Clear the busy led
filePos=0; //Reset all parameters
readPos=0;
sectorPos=0;
mp3Pos=0;
printFileName(); //Print file name on LCD
printInfo(); //Print other information
intFlag=0; //LCD fixed, so clear interrupt flag.
}
gotoxy(0,19); //Put the LCD cursor on position of play/stop character.
}
void STA013Setup() {
//Sets up STA013 after initial power up or reset.
byte success; byte i;
dword extension;
//Setup STA013
STA013Reset(); //Give reset pulse to STA013
i2cInit();
if (i2cReadAddress(1)!=0xAC) { //Check if STA013 is there
Halt(6); //STA013 decoder not found.
}
success=0;
currentFileNum=0;
do { //Find STA013.BIN
if (getDirEntry(0)==0) Halt(5); //root directory finished and STA013.BIN not found. Generate error.
extension=0;
for(i=0; i<3; i++) extension=(extension<<8)+fileExtension[i]; //Load extension chars into dword variable
//If extension is BIN and fileName starts with either 's' or 'S',
//then we assume filename is STA013.BIN. Whole filename comparision will take
//lot of code, therefore this assumption is made. User therefore must
//not save any other file that is BIN and starts with S.
if ((extension==0x0042494E)&& //if it is 0BIN
((fileName[0] & 0x53)==0x53)) // 'S' & 's' == 'S'
success=1; //we found STA013.BIN
}
while ((success==0));
success=0;
readPos=0; //reset to read start of STA013.BIN
sectorPos=0; //reset sector position to begin reading for start;
do { //Load STA013.BIN
readFile(1); //Read 1 word, 1st byte is I2C address, 2nd byte is data.
i2cInit();
success = i2cWriteAddress(sectorBuffer.data[0],sectorBuffer.data[1]);
}
while ((filePos<FileSize)&&(success==1));
// Load failed. Generate error.
if (success==0) Halt(7);
i2cInit();
i2cWriteAddress(0x7D,11); //Set tone attenuation level -16.5dB.
//This is required. Otherwise sound will crack when we do bass/treble boost.
i2cWriteAddress(0x72,1); //Run, (its not play)
}
void SetBassTreble() {
//Sets the STA013 bass treble registers depending on soundMode.
//Loads the pre-defined bass/treble values from BassTrebleTable array (look at ztype.h)
byte i;
for(i=0;i<6;i++)
//Bass treble I2C address starts at 0x77
i2cWriteAddress(i+0x77,BassTrebleTable[soundMode,i]);
}
void STAPlay() {
//Play/Stop MP3 playback on STA013.
i2cInit();
i2cWriteAddress(0x13,(play & 1));
}
word randomKey() {
//Generate random number between 0 to totalFiles-1
//Uses 16 bit timer/counter for random number.
//Random number is found by moding 16 bit counter TCNT1 with totalFiles.
word temp;
temp = TCNT1H;
temp = (temp<<8) + TCNT1L;
return (temp % totalFiles);
}
void printError(byte errorCode) {
//Print error based on errorCode on LCD from ErrStr array (look at ztype.h)
byte i=0;
while (ErrStr[errorCode,i]!=0) writechar(ErrStr[errorCode,i++]);
}
void Halt(byte errorCode) {
//Halt ZipAmp if error was encountered.
LCDclrscr();
printError(0); //Print first line of error
printError(errorCode);//Print the error line
while(1); //Infinite loop.
}
void printFileName() {
//Print file name on LCD
byte i=0;
LCDclrscr();
gotoxy(1,0);
while((fileName[i]!=0)&&(fileName[i]!='.')) {
if (i==20) gotoxy(2,0);
writechar(fileName[i++]);
}
gotoxy(3,0);
for (i=1; i<dirString[0]; i++) writechar(dirString[i]);
}
void printInfo() {
//Print other info on LCD.
byte i;
//Display fileNumber
gotoxy(0,0);
for(i=0;i<9;i++) writechar(' ');
gotoxy(0,0);
writeNumber(currentFileNum);
writechar('/');
writeNumber(totalFiles);
gotoxy(0,10); //Fix LCD display for sound mode
for(i=0;i<4;i++)
writechar(SoundModeDisplay[soundMode,i]);
//Diplay play mode characters
writechar(' ');
for (i=0; i<3; i++) writechar(PlayModeDisplayStrTable[playMode,i]);
writechar(' ');
//Display stop/play/pause characters
if (play==2) writechar(255); //player stopped
else writechar(5-play);
blink();
gotoxy(0,19);
}
//End of zcontrol.h
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -