//check the volume of your MP3, if too high it can cause the DFplayer to bug  
#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
#include "avr/sleep.h"
#include "avr/power.h"

SoftwareSerial mySoftwareSerial(10, 11);
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);

//Mux control pins
int s0 = 6;
int s1 = 7;
int s2 = 8;
int s3 = 9;

//Mux in "SIG" pin
int SIG_pin = 1;



int pushValue = 100; //tresshold to active button
int stopValue = 50; //tresshold to desactive button
int longPressTime = 3000; //Time to press to activate hidden song
int deepSleep=0;
long deepSleepCounter;
long idleTime=400000;

boolean isPlaying = false;
boolean songLongPressActive = false;
boolean songActive = false;
int songValue[9]={0,0,0,0,0,0,0,0,0};
boolean songpress[9]={false,false,false,false,false,false,false,false,false};
long songTimer[9]={0,0,0,0,0,0,0,0,0};
unsigned long currentMillis;

void setup () {

  pinMode(s0, OUTPUT); 
  pinMode(s1, OUTPUT); 
  pinMode(s2, OUTPUT); 
  pinMode(s3, OUTPUT); 

  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  int i = 0;
  /*while ( i < 9)
  {
    pinMode(i, INPUT); //initialize analog input
        i++;
  }*/


  mySoftwareSerial.begin(9600); //serial with music player
  Serial.begin(9600); //debug serial

  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while (true);
  }
  Serial.println(F("DFPlayer Mini online."));

  myDFPlayer.setTimeOut(1500); //Set serial communictaion time out 500ms

  //----Set volume----
  myDFPlayer.volume(30);  //Set volume value (0~30).
  //myDFPlayer.volumeUp(); //Volume Up
  //myDFPlayer.volumeDown(); //Volume Down

  //----Set different EQ----
  //myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
  //  myDFPlayer.EQ(DFPLAYER_EQ_POP);
  //  myDFPlayer.EQ(DFPLAYER_EQ_ROCK);
  //  myDFPlayer.EQ(DFPLAYER_EQ_JAZZ);
  //  myDFPlayer.EQ(DFPLAYER_EQ_CLASSIC);
  //  myDFPlayer.EQ(DFPLAYER_EQ_BASS);

  //----Set device we use SD as default----

  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);


  //----Read imformation----
  Serial.println(myDFPlayer.readState()); //read mp3 state
  Serial.println(myDFPlayer.readVolume()); //read current volume
  Serial.println(myDFPlayer.readEQ()); //read EQ setting
  Serial.println(myDFPlayer.readFileCounts()); //read all file counts in SD card
  Serial.println(myDFPlayer.readCurrentFileNumber()); //read current play file number
  Serial.println(myDFPlayer.readFileCountsInFolder(3)); //read file counts in folder SD:/03

}
void loop () {
  /*for(int i = 1; i < 4; i ++){
    Serial.print("Value at channel ");
    Serial.print(i);
    Serial.print("is : ");
    Serial.println(readMux(i));
        delay(1000);
  }*/

 if ((( currentMillis - deepSleepCounter) > idleTime)& !isPlaying) 
      {
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
Serial.println("going to sleep");
sleep_enable();
sleep_mode();
}
else
{
 // Serial.println(idleTime - currentMillis + deepSleepCounter );
  }
  
  if (myDFPlayer.available()) {
    printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states.
  }

  
  for(int i=0 ; i<=8 ; i++) //check every analog pin, if a pin is not use do not test it or wire it to the ground
  {currentMillis = millis();
      checkPush (i);
      delay(50);
      }
      
}

void checkPush(int pinNumber)
{ songValue[pinNumber] = readMux(pinNumber); //check value
/*Serial.print("songValue ");
Serial.print(pinNumber);
Serial.print("= ");
Serial.println(songValue[pinNumber]);*/



  if (songValue[pinNumber] > pushValue && currentMillis > 2000 ) //is button pressed? timer to avoid wrong high value at first reading
  {

    if (songpress[pinNumber] == false) //if first press
    {
      songpress[pinNumber] = true;
      songTimer[pinNumber] = millis(); //store counter for longpressed calculation
      Serial.println("songpressed= " + pinNumber);
      deepSleepCounter=millis();

    }


  }

  if ( songValue[pinNumber] < stopValue && songpress[pinNumber]  ) { //is button unpressed?
    if (isPlaying )
    {
       songTimer[pinNumber] = 0;   //reset counter for longpress
      myDFPlayer.pause();
      songpress[pinNumber] = false;
      isPlaying = false;

      Serial.println("pause");
      delay(1000); 
    } else
    {
      if (( currentMillis - songTimer[pinNumber]) > longPressTime)  //is button longpressed?
      {
        songTimer[pinNumber] = 1;
        songpress[pinNumber] = false;
        isPlaying = true;
        myDFPlayer.playFolder(pinNumber+1, 2);  //play song beginning by 002 in folder=pinNumber
        Serial.print("play song2 folder: ");
        Serial.println(pinNumber);
        Serial.println("longpress= "+ pinNumber);
        
        delay(500);
      }
      else //else shortpush
      {
        Serial.println("shortpress= "+ pinNumber);
        songpress[pinNumber] = false;
        songTimer[pinNumber] = 0;
        isPlaying = true;
       
        }
        myDFPlayer.playFolder(pinNumber+1, 1);   //play song beginning by 001 in folder=pinNumber
         Serial.print("play song1 folder: ");
        Serial.println(pinNumber);
        delay(500);

      }

    }

  }

 

  



void printDetail(uint8_t type, int value) {
  switch (type) {
    case TimeOut:
      Serial.println(F("Time Out!"));
      break;
    case WrongStack:
      Serial.println(F("Stack Wrong!"));
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Card Inserted!"));
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card Removed!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      break;
    case DFPlayerUSBInserted:
      Serial.println("USB Inserted!");
      break;
    case DFPlayerUSBRemoved:
      Serial.println("USB Removed!");
      break;
    case DFPlayerPlayFinished:
      Serial.print(F("Number:"));
      Serial.print(value);
      Serial.println(F(" Play Finished!"));
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("Card not found"));
          break;
        case Sleeping:
          Serial.println(F("Sleeping"));
          break;
        case SerialWrongStack:
          Serial.println(F("Get Wrong Stack"));
          break;
        case CheckSumNotMatch:
          Serial.println(F("Check Sum Not Match"));
          break;
        case FileIndexOut:
          Serial.println(F("File Index Out of Bound"));
          break;
        case FileMismatch:
          Serial.println(F("Cannot Find File"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }

}
int readMux(int channel){
  int controlPin[] = {s0, s1, s2, s3};

  int muxChannel[16][4]={
    {0,0,0,0}, //channel 0
    {1,0,0,0}, //channel 1
    {0,1,0,0}, //channel 2
    {1,1,0,0}, //channel 3
    {0,0,1,0}, //channel 4
    {1,0,1,0}, //channel 5
    {0,1,1,0}, //channel 6
    {1,1,1,0}, //channel 7
    {0,0,0,1}, //channel 8
    /*{1,0,0,1}, //channel 9
    {0,1,0,1}, //channel 10
    {1,1,0,1}, //channel 11
    {0,0,1,1}, //channel 12
    {1,0,1,1}, //channel 13
    {0,1,1,1}, //channel 14
    {1,1,1,1}  //channel 15*/
  };

  //loop through the 4 sig
  for(int i = 0; i < 4; i ++){
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }

  //read the value at the SIG pin
  int val = analogRead(SIG_pin);

  //return the value
 // float voltage = (val * 5.0) / 1024.0;
  return val;
}
