| 
  • If you are citizen of an European Union member nation, you may not use this service unless you are at least 16 years old.

  • You already know Dokkio is an AI-powered assistant to organize & manage your digital files & messages. Very soon, Dokkio will support Outlook as well as One Drive. Check it out today!

View
 

Final Code

Page history last edited by camerons 13 years, 10 months ago


#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.