#include <avr/power.h>
#include <avr/sleep.h>
/* import the full fatfs library for access to functions & defines. */
#include <diskio.h>
#include <fatfs.h>
#include <ff.h>
#include <ffconf.h>
#include <integer.h>
#include <EEPROM.h>
#define NO_GRAPHICS
#define NO_BITMAP
#include <nokia_3310_lcd.h>
#define cs_pin 14 // chip select pin on the arduino
#define bytes_to_read (14*6) // this is the max # of chars the
// lcd can display
#define LCD_PWR 12
#define LCD_DC 4
#define LCD_SCE 21
#define LCD_RESET 5
#include <avr/power.h>
#include <mp3.h>
#include <mp3conf.h>
#define mp3_cs 0 // 'command chip select' to cs pin
#define mmc_cs 14 // 'chip select' to microsd cs pin
#define dcs 18 // 'data chip select' to bsync pin
#define rst 20 // 'reset' to decoder's reset pin
#define dreq 19 // 'data request line' to dreq pin
#define read_buffer 512 // size of the microsd read buffer
#define MUTE 148
#define POWER 149
#define SLEEP 182
#define LAST 187
#define ASPECT 1085
#define VOL_PLUS 146
#define VOL_MINUS 147
#define CH_PLUS 144
#define CH_MINUS 145
#define MENU 224
#define EXIT 227
#define UP 244
#define DOWN 245
#define LEFT 180
#define RIGHT 179
#define OK 229
#define REWIND 217
#define FAST_FORWARD 216
#define PLAY 218
#define PAUSE 622
#define STOP 631
#define ONE 128
#define TWO 129
#define THREE 130
#define FOUR 131
#define FIVE 132
#define SIX 133
#define SEVEN 134
#define EIGHT 135
#define NINE 136
#define ZERO 137
#define RETURN 139
#define MINUS 157
//END REMOTE KEY DEFINES
/*typedef struct
{
char* name;
char* artist;
int length; //seconds
} songT;*/
Nokia_3310_lcd lcd(LCD_PWR,
LCD_DC,
LCD_SCE,
LCD_RESET);
#define ir_pin 6
#define start_bit 2000
#define bin_1 1000
#define bin_0 400
volatile int menuPage=0;
volatile int selected=0;
volatile long lastFall=0;
volatile int data[12];
volatile int dataReceived=false;
boolean songPlaying=true;
boolean muted=false;
int numSongs=0;
int currSong=0;
long bytesIntoMp3=0;
long anchor=0;
const int menuLines=6;
int mp3_vol = 250; // output volume range is 0 to 254
int numPages=1;
#define DEBUG true
void spi_init(){
pinMode(0, INPUT_PULLUP); // SS pin, should be pulled high.
pinMode(3, INPUT_PULLUP); // MISO
pinMode(2, OUTPUT); //MOSI
pinMode(1, OUTPUT); //SCLK
SPCR = _BV(SPE) | _BV(MSTR)| _BV(SPR0);
}
void setup() {
pinMode(11,OUTPUT);
digitalWrite(11,HIGH);
clock_prescale_set(clock_div_2); // fosc 8mhz as teensy is at 3.3V
initLCD();
delay(200);
Mp3.begin(mp3_cs,dcs,rst,dreq); // decoder cs, dcs, rst, dreq pin
Mp3.volume(mp3_vol); // default volume level is silent
delay(200);
FatFs.begin(mmc_cs); // register microsd card's cs pin
//Serial.begin(115200); // initialize the ////Serial terminal
clock_prescale_set(clock_div_1); // fosc 16mhz only for full waves
initSongList();
// while only rated to 8mhz, the processor seems to work at 16MHz,
// which is required to playback full-resolution 44.1kHz wav files
delay(200);
setupIR();
startMP3(0);
clock_prescale_set(clock_div_1);
delay(500);
digitalWrite(11,LOW);
delay(500);
digitalWrite(11,HIGH);
//Serial.print("nS");
//Serial.println(numSongs);
//Serial.print("nP");
//Serial.println(numPages);
refreshLCD();
for(int i=0;i<numSongs;i++)
{
//Serial.println(songNames(i));
}
}
void loop() {
if(dataReceived)
handleKeyPress();
if(songPlaying)
{
if(!mp3_play())
{
//song is over, start next one
// startMP3(millis()%numSongs);
}
}
//showSongList();
}
/*
* send (pointers to) all files in the root directory to dir_play(),
* even though they may not be mp3 or wav files (as they're screened
* for proper extensions there).
*/
FILINFO fnfo; // information on file size & type, updated by readdir
//starts the mp3 in filespace with tht
void startMP3(int index)
{
currSong=index;
anchor=0;
selected=currSong%menuLines;
//Serial.println("deb");
//Serial.println(selected+menuPage*menuLines);
if(FatFs.open(songNames(selected+menuPage*menuLines), FA_READ) == FR_OK)
{
bytesIntoMp3=0;
//Serial.print(index);
//Serial.println(songNames(index));
}
else
{
////Serial.print("NF");
////Serial.print(songNames[index]);
}
/*do {
FatFs.readdir(&fnfo);
dir_play(&fnfo);
}
while (fnfo.fname[0]!='M');*/
}
void setupIR()
{
for(int i=0;i<12;i++)
data[i]=0;
pinMode(ir_pin, INPUT);
attachInterrupt(1, int1routine, CHANGE);
}
void initLCD()
{
CLKPR = 0x80;
CLKPR = 0x1;
spi_init();
lcd.init();
lcd.clear();
}
int getIRKey() {
for(int i=0;i<11;i++) { //Parse them
if(data[i] > bin_1) { //is it a 1?
data[i] = 1;
} else {
if(data[i] > bin_0) { //is it a 0?
data[i] = 0;
} else {
data[i] = 2; //Flag the data as invalid; I don't know what it is!
}
}
}
for(int i=0;i<11;i++) { //Pre-check data for errors
if(data[i] > 1) {
return -1; //Return -1 on invalid data
}
}
int result = 0;
int seed = 1;
for(int i=0;i<11;i++) { //Convert bits to integer
if(data[i] == 1) {
result += seed;
}
seed = seed * 2;
}
return result; //Return key number
}
long totalTime=100;
boolean mp3_play (void)
{
unsigned char bytes[read_buffer]; // buffer to send to the decoder
unsigned int bytes_read; // number of bytes read from fat
long mpTimer=millis();
int count=0;
do {
long m=millis();
if(m>totalTime+mpTimer)//method ran totalTime sec
{
return true;
}
FatFs.read(bytes, read_buffer, &bytes_read);
Mp3.play(bytes, read_buffer);
bytesIntoMp3+= bytes_read;
}
while (bytes_read == read_buffer);
return false;
}
/*
* play back an mp3 or wav file (only!) in the root directory. first
* check that it's a file (and not a directory); next, check that it
* has a proper extension; finally, play only if it opens cleanly.
*/
void dir_play (FILINFO * fnfo) {
if ((fnfo->fattrib & AM_DIR) != AM_DIR) {
char * fn = fnfo->fname; // pointer to the filename
char s = strlen(fnfo->fname); // length of the filename
if ((fn[s-3] == 'M' && fn[s-2] == 'P' && fn[s-1] == '3') ||
(fn[s-3] == 'W' && fn[s-2] == 'A' && fn[s-1] == 'V')) {
if (FatFs.open(fnfo->fname, FA_READ) == FR_OK) {
////Serial.print("P ");
////Serial.println(fnfo->fname);
}
}
}
}
void initSongList ()
{
FILINFO file_info; // information on file size and type
unsigned int files_found = 0; // count of files found in directory
char* suffix = ".MP3";
int i=0;
int currAddr=0;
FatFs.opendir();
do {
FatFs.readdir(&file_info);
if ((file_info.fattrib & AM_DIR) != AM_DIR)
{
if((strstr(file_info.fname,suffix)!=NULL)) {
writeString(file_info.fname,currAddr);
currAddr+=strlen(file_info.fname);
currAddr++;
i++;
}
}
}
while (file_info.fname[0] != 0);
//FatFs.closedir();
numSongs=i;
numPages=numSongs/6;
FatFs.close();
}
long songListTimer=0;
int songListRefreshRate=2000; //millis between refreshes
void showSongList() {
long m = millis();
if(m<songListTimer+songListRefreshRate) //not enough time passed
return;
else
songListTimer=m;
lcd.clear();
lcd.writeString( 0, 0, "Demo! 123", MODE_NORMAL);
//delay(1000);
lcd.writeStringBig(0, 3, "1", MODE_NORMAL);
//delay(500);
lcd.writeStringBig( 12, 2, "2", MODE_NORMAL );
//delay(500);
lcd.writeStringBig( 24, 1, "3", MODE_NORMAL );
delay(2000);
lcd.clear();
for(int i=0;i<menuLines;i++)
{
if(i+menuLines*menuPage<numSongs)
{
if(i!=selected)
{
lcd.writeString( 0, i, songNames(i+menuLines*menuPage), MODE_NORMAL);
//Serial.println(songNames(i+menuLines*menuPage));
}
else
{
lcd.writeString( 0, i, songNames(i+menuLines*menuPage), MODE_INVERSE);
//Serial.print(">");
//Serial.println(songNames(i+menuLines*menuPage));
}
}
}
}
long d=0;
int dataPos=0;
void int1routine()
{
if(digitalRead(ir_pin)==LOW) //falling
lastFall=micros();
else //rising
{
d=micros()-lastFall;
if(d>2200) //mark received
{
dataPos=0;
dataReceived=false;
}
else if(dataPos<12) //found some data!
{
data[dataPos++]=d;
if(dataPos==12)
dataReceived=true;
}
}
}
void sleepNow() // here we put the arduino to sleep
{
// The 5 different modes are:
// SLEEP_MODE_IDLE -the least power savings
// SLEEP_MODE_ADC
// SLEEP_MODE_PWR_SAVE
// SLEEP_MODE_STANDBY
// SLEEP_MODE_PWR_DOWN -the most power savings
digitalWrite(11,LOW);
delay(100);
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable(); // enables the sleep bit in the mcucr register
// so sleep is possible. just a safety pin
detachInterrupt(1);
//ONLY USE LOW HERE except in IDLE mode
attachInterrupt(1,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
// wakeUpNow when pin 2 gets LOW
sleep_mode(); // here the device is actually put to sleep!!
// THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
sleep_disable(); // first thing after waking from sleep:
// disable sleep...
detachInterrupt(1); // disables interrupt 0 on pin 2 so the
// wakeUpNow code will not be executed
// during normal running time.
delay(500); //takes a bit to wake up from sleeping
attachInterrupt(1, int1routine, CHANGE);
}
void wakeUpNow() // here the interrupt is handled after wakeup
{
digitalWrite(11,HIGH);
// execute code here after wake-up before returning to the loop() function
// timers and code using timers (////Serial.print and more...) will not work here.
}
long pauseButtonTimer=0;
//if false, exit the method early
boolean buttonTimer(long time)
{
long m = millis();
if(m<pauseButtonTimer+time)
return false;
else
pauseButtonTimer=m;
return true;
}
boolean buttonTimer()
{
return buttonTimer(500);
}
void pauseButton()
{
if(!buttonTimer()) return;
// ////Serial.println("pause button");
songPlaying=false;
}
void unpauseButton()
{
if(!buttonTimer()) return;
//////Serial.println("unpause button");
songPlaying=true;
if(!mp3_play())
{
//song is over, start next one
startMP3(millis()%numSongs);
}
}
void stopButton()
{
if(!buttonTimer()) return;
////Serial.println("stop");
songPlaying=false;
FatFs.lseek(0);
}
void rwButton()
{
if(!buttonTimer(100)) return;
bytesIntoMp3-=30000;
bytesIntoMp3-=30000;
if(bytesIntoMp3<0)
bytesIntoMp3=0;
FatFs.lseek(bytesIntoMp3);
}
void changePage(boolean up)
{
if(!buttonTimer()) return;
if(up)
{
menuPage--;
if(menuPage<0)
menuPage=numPages-1;
if(selected+menuLines*menuPage>=numSongs)
selected=menuLines*menuPage+selected-numSongs;
}
else
{
menuPage++;
if(menuPage>=numPages)
menuPage=0;
if(selected+menuLines*menuPage>=numSongs)
selected=menuLines*menuPage+selected-numSongs;
}
refreshLCD();
}
boolean upButton()
{
if(!buttonTimer(1000))
return false;
else
{
selected--;
if(selected<0) //next page
{
selected=5;
menuPage--;
if(menuPage<0)
menuPage=numPages-1;
if(selected+menuLines*menuPage>numSongs)
selected=menuLines*menuPage-numSongs;
}
}
refreshLCD();
return true;
}
boolean downButton()
{
if(!buttonTimer(1000))
return false;
else
{
selected++;
if(selected>5) //next page
{
selected=0;
menuPage++;
if(menuPage>=numPages)
menuPage=0;
}
}
refreshLCD();
return true;
}
void muteButton()
{
if(!buttonTimer()) return;
if(muted)
{
Mp3.volume(mp3_vol);
}
else
{
Mp3.volume(0);
}
muted=!muted;
}
void okButton()
{
if(!buttonTimer()) return;
startMP3(selected+menuLines*menuPage);
}
void ffButton()
{
if(!buttonTimer(100)) return;
bytesIntoMp3+=25*read_buffer;
FatFs.lseek(bytesIntoMp3);
}
boolean wasRW=false;
void handleKeyPress()
{
if(!dataReceived) return;
int key= getIRKey();
dataReceived=false;
////Serial.println(key);
switch(key)
{
case -2: break; //Nothing received
case CH_PLUS:
if(upButton())
{
startMP3(selected+menuLines*menuPage);
//Serial.println("up");
}
break;
case CH_MINUS:
if(downButton())
{
startMP3(selected+menuLines*menuPage);
//Serial.println("down");
}
break;
case MUTE:
muteButton();
break;
case POWER:
sleepNow();
break;
case SLEEP:
sleepNow();
break;
case PLAY:
unpauseButton();
break;
case PAUSE:
pauseButton();
break;
case STOP:
stopButton();
break;
case REWIND:
rwButton();
break;
case ASPECT:
aspectButton2();
break;
case LAST:
lastButton2();
break;
case OK:
okButton();
break;
case FAST_FORWARD:
ffButton();
break;
case VOL_PLUS:
changeVol(5);
case VOL_MINUS:
changeVol(-5);
case UP:
upButton();
break;
case DOWN:
downButton();
break;
case LEFT:
changePage(true);
case RIGHT:
changePage(false);
default: break;
}
if(key>=ONE && key<138) //Input number
{
//Serial.println("numSongs");
//Serial.println(numSongs);
if(key-ONE <numSongs) //songs are zero indexed
{
startMP3(key-ONE);
}
}
}
int writeString(char* c, int addr)
{
int i=0;
for(i=0;i<=strlen(c);i++)
{
EEPROM.write(addr+i,(byte)c[i]);
}
return i;
}
int writeLong(long a, int addr)
{
int i=0;
for(i=0;i<sizeof(long);i++)
{
byte b= ((byte*) &a)[i];
EEPROM.write(addr+i,b);
}
return i;
}
long readLong(int addr)
{
byte arr[sizeof(long)];
for(int i=0;i<sizeof(long);i++)
{
arr[i]=EEPROM.read(i+addr);
}
long f= *( (long*) arr);
long b = f;
return b;
}
char* readNthString(int n)
{
int currAddr=0;
for(int i=0;i<n;i++)
{
currAddr+=strlen(readString(currAddr));
currAddr++; //go past /0
}
char* str = readString(currAddr);
return str;
}
char* readString(int addr)
{
char* str="";
char ch='A';
int i=0;
while(ch!='\0'&&i<50)
{
ch=(char)(EEPROM.read(addr+i));
str[i]=ch;
i++;
}
str[i]='\0';
if(i>=50)
{
return "";
}
return str;
}
void changeVol(int amt)
{
if(!buttonTimer(200)) return;
mp3_vol+=amt;
if(mp3_vol>250)
mp3_vol=250;
else if(mp3_vol<1)
mp3_vol=1;
Mp3.volume(mp3_vol);
// //Serial.print("v");
////Serial.println(mp3_vol);
}
long strToLong(char* str)
{
long mult =1;
long result=0;
for(int i=strlen(str)-1;i>=0;i--)
{
result+=(str[i]-'0')*mult;
mult*=10;
}
return result;
}
void lastButton2()
{
if(!buttonTimer()) return;
FatFs.lseek(anchor);
}
void aspectButton2()
{
if(!buttonTimer()) return;
anchor = bytesIntoMp3;
}
//restore to the anchor for this song if it exists
void lastButton()
{
if(!buttonTimer()) return;
int i=0;
char prevCh =(char) EEPROM.read(i++); //go past @ at beginning
char ch=(char) EEPROM.read(i);
int br=0;
if(prevCh!='@')
{
return;
}
while(!(ch=='@'&&prevCh=='@'))
{
if(br>30)
{
return;
}
char* str = readString(i);
i+=strlen(str)+1; //go past the /0
if(strcmp(songNames(currSong),str)==0) //found it!
{
long bytesIn=readLong(i);
FatFs.lseek(bytesIn);
return;
}
i+=sizeof(long); //go past long (we didnt find it)
prevCh = EEPROM.read(i++); //go past the @
ch=(char) EEPROM.read(i);
br++;
}
}
char* songNames(int i)
{
return readNthString(i);
}
//write to EEProm in next available spot
//make note of where we are in the song
void aspectButton()
{
if(!buttonTimer()) return;
long lo=bytesIntoMp3;
int i=0;
char prevCh =EEPROM.read(i++);
char ch=EEPROM.read(i++);
int numBytes=0;
while(!(ch=='@'&&prevCh=='@'))
{
prevCh=ch;
ch=(char) EEPROM.read(i++);
}
////Serial.println(i);
i--;
//we are at the second @, we can write over this now
i+=writeString(songNames(currSong),i);
i+=writeLong(lo,i);
writeString("@@",i);
//EEPROM.write(addr, val);
}
void refreshLCD()
{
lcd.clear();
for(int i=0;i<menuLines;i++)
{
if(i+menuLines*menuPage<numSongs)
{
if(i!=selected)
{
lcd.writeString( 0, i, songNames(i+menuLines*menuPage), MODE_NORMAL);
//Serial.println(songNames(i+menuLines*menuPage));
}
else
{
lcd.writeString( 0, i, songNames(i+menuLines*menuPage), MODE_INVERSE);
//Serial.print(">");
//Serial.println(songNames(i+menuLines*menuPage));
}
}
}
}
Comments (0)
You don't have permission to comment on this page.