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

  • Social distancing? Try a better way to work remotely on your online files. Dokkio, a new product from PBworks, can help your team find, organize, and collaborate on your Drive, Gmail, Dropbox, Box, and Slack files. Sign up for free.

View
 

Final Project Doc

Page history last edited by Martin Sanner 6 years, 9 months ago

Final Project Documentation by Martin Sanner

Moddable MP3-Player

 

Partslist:

     -1 * Arduino Micro

     -1 * Arduino Uno

     -4 * small Pushbuttons

     -wiring :)

     -the LCD from Lab 3

     - an SD-Card-reader soldered for Breadborduse

     -an SD-Card-reader for PC-connection

     -2 micro-SD-cards

     -the SparkFun mp3 Shield: https://www.sparkfun.com/products/10628

     Addons:

     -an additional musical output

 

If one is thinking about digital design in combination with widely used electronical Devices, most people have a clear design in their heads.

Since most of these devices, namely Apples iPhone Series, as well as Google Android mobile Series, have a fixed Interface but such a widespread Usability, there's clearly a bottleneck in the design.

 

My intention was to invent a "user-proof", in other words, easy to use device in form of an mp3-Player, that can fix this issue.

Most of the technologies were already in use by the end of Lab #6, so i could draw on that knowledge, and expand to fit my needs.

 

But up to that point, the transformation of the initial idea to the finished product was long, and struck by change, since i did not have a design in mind, but rather a full fledged technology.

 

My initial Design was the following:

although it proved unreliable due to the sheer size of the MP3.

 

At the Point of designing the Physical Interface, most of the Software was already designed.

To create a viable Userinterface, i wrote a small Filemanagerclass, which can :

     A: handle most textdriven inputfiles

     B:dynamically allocate those files, and handle garbagecollection

     C:create Files in a userselected Datatype, which can be easily accustomed

     D:create new Files, read Files into a buffer, append new strings to the File and, on demand, delete the Files.

This class(interface and implementation) is to be found here:

 

          Filemanager.h:

          //
//  Filemanager.h
//  UTIL
//
//  Created by Martin Sanner on 05.08.13.
//  All rights reserved.

#ifndef __UTIL__Filemanager__
#define __UTIL__Filemanager__

#include <iostream>
#include <fstream>
#include "string.h"
#include <vector>


using namespace std;

class Filemanager{
public:
    void getFile();
    void getFile(string filename);
    void getFile(string Filename, bool write);
    
    Filemanager();
    ~Filemanager();
    Filemanager(string filename);
    Filemanager(string filename, int start);
    void readBuffer();
    void readFile();
    void readFile(string filename);
    void releaseFile(bool completeRelease);
    void writeFile();
    void writeFile(vector<string> input);
    void writeBuffer();
    void writeBuffer(vector<string> input);
    void clearBuffer();
    string getFiletype();
    void cutBuffer(int currentID);
    void setFilename(string name);
    vector<string> getBuffer();
    void setFileType(string type);
    void setFileType();
    void cutBuffer();
    string getFilename();
    
private:
    
    ofstream output;
    string FileType;
    string filename;
    ifstream input;
    vector<string> buffer;
    int Current;    //pointer to the current char
};
#endif /* defined(__UTIL__Filemanager__) */

 

     Filemanager.cpp

          //
//  Filemanager.cpp
//  UTIL
//
//  Created by Martin Sanner on 05.08.13.
//  Copyright (c) 2013 Hellixionmeta. All rights reserved.
//

#include "Filemanager.h"

void Filemanager::getFile(){
    string name;
    cout << "What is your desired Filename?";
    cin >> name;
    setFilename(name);
    getFile(filename);
}

void Filemanager::getFile(string Filename,bool write){
    setFilename(Filename);
    if(write){
        ofstream stream;
        stream.open(Filename);
        if(stream.is_open()){
        for(int bufpoint = 0;bufpoint <= buffer.size();bufpoint++){
            stream << buffer[bufpoint];
            stream << endl;
            }
            stream.close();
        }
    }
    else{
        readFile(Filename);
    }
};
void Filemanager::getFile(string Filename){
    setFilename(Filename);
   readFile(Filename);
};
void Filemanager::readBuffer(){
    for(int i = 0;i<=buffer.size();i++){
        cout << buffer[i]<<endl;
    }
};

Filemanager::Filemanager(){
    Current=0;
    output.open(filename);
    setFilename("");
    getFile(filename);
    FileType=getFiletype();
    clearBuffer();
    input.open(filename);
};
Filemanager::~Filemanager(){
    Current=0;
    FileType="";
    
    clearBuffer();
    input.close();
    
    
};
Filemanager::Filemanager(string Filename){
    filename=Filename;
    getFile(filename);
    setFileType();
    Current=0;
    clearBuffer();
    output.open(filename);
    input.open(filename);
};
Filemanager::Filemanager(string Filename,int id){
    filename=Filename;
    getFile(filename);
    Current=id;
    if(buffer.size()>Current){
          cutBuffer(Current);
    }
    
};
void Filemanager::readFile(){
    readFile(filename);
}
void Filemanager::readFile(string Filename){
   
    input=ifstream(Filename);
    
    string line;
    if(input.is_open())
    {
        while(!input.eof())
        {
            getline(input,line);
            buffer.push_back(line);
        };
    }else{
        cout << "Unable to open file:" << filename << endl;
    }
    
};
string Filemanager::getFiletype(){
    return FileType;
};
void Filemanager::setFileType(){
    if(getFilename().size()>4){
    FileType=getFilename().substr(filename.size()-3);
    }
};
string Filemanager::getFilename(){
    return filename;
}
void Filemanager::writeBuffer(vector<string> input){
    buffer = input;
}
void Filemanager::setFileType(string type){
    FileType=type;
    string temp=getFilename();
    temp=temp.substr(0,temp.size()-3);
    temp.append(FileType);
    setFilename(temp);
};
void Filemanager::setFilename(string name){
    filename=name;
}
void Filemanager::cutBuffer(int currentID){
        buffer.erase(buffer.begin(), buffer.begin()+buffer.size()/2);
};

void Filemanager::cutBuffer(){
    buffer.erase(buffer.begin(),buffer.begin()+buffer.size()/2);
}

void Filemanager::clearBuffer(){
    if(buffer.size()>0){
        for(long int i=buffer.size();i>=0;i--){
            buffer[i].erase();
        }
    }
};
void Filemanager::releaseFile(bool completeRelease){
    if(input.is_open()){
    input.close();
    }
    if(output.is_open()){
    output.close();
    }
    clearBuffer();
    if(completeRelease)
    {
        setFileType("");
        setFilename("");
    }
};
void Filemanager::writeBuffer(){
    bool isrunning=true;
    bool isHel;          //"*.hel is a custom Filetype, which is to be further expanded in future iterations. For Convenience, handle it as a textfile
    string answer;
    cout << "Please start writing to the Buffer now."<<endl << "If you want to end the writingprocess, please put in an emptyline:"<<endl;
    cout << "Do you want to use the .hel - datatype?[y/n]: "<<endl;
    cin >> answer;
    if(answer=="yes"){
        isHel=true;
    }else{
        isHel=false;
    }
    if(isHel){
        setFileType("hel");
    }
    string text;
    while(isrunning){
        cin >> text;
        if(text==""){
            isrunning=false;
        }
        buffer.push_back(text);
    }
};
void Filemanager::writeFile(){
    if(buffer.size() == 0){
    writeBuffer();
    }
    writeFile(buffer);
}
void Filemanager::writeFile(vector<string> input){
    if(buffer.size() == 0){
        writeBuffer();
    }
    if(filename==""){
        getFile();
    }
    getFile(filename);

    ofstream out;
    out.open(filename, ios::out | ios::binary);
    if(out.is_open()){
        if(FileType=="hel"){
            for(int i=0;i<=buffer.size();i+=2){
                out << buffer[i] << "" << buffer[i++] << endl;
            }
        }else{
            for(int i=0;i<=buffer.size();i++){
                out << buffer[i] << endl;
            }
        }
        out.close();
    }
}
vector<string> Filemanager::getBuffer(){
    return buffer;
};

 

          main.cpp:

               //
//  main.cpp
//  HELSetup
//
//  Created by Martin Sanner on 07.08.13.
//  Copyright (c) 2013 Hellixionmeta. All rights reserved.
//

#include <iostream>
#include "string"
#include "Filemanager.h"


using namespace std;

void help();

int main(int argc, const char * argv[])
{
    string file = "interface.txt";
    cout << "File: "<< file<<endl;
    help();
    Filemanager manager;
    bool isRunning = true;
    vector<string> temp;
    cout << "Start writing now."<<endl;
A:
    while(isRunning){
        string tempstring;
        cin >> tempstring;
        if(tempstring == "HELP"){
            help();
        }
        else if(tempstring == "STOP"){
            isRunning = false;
        }
        else{
            temp.push_back(tempstring);
        }
    }
    
    manager.writeBuffer(temp);
    manager.readBuffer();
    //The buffer gets doubled after reading from it. cutBuffer cuts the buffer in two equallysized halfs
    manager.cutBuffer();
    manager.getFile(file,true);
    manager.writeFile();
    cout << "Written to File."<<endl;
    //Check wether the User wants to finish
    cout <<  "are you sure you want to finish?[NO to repeat]"<<endl;
    string answer;
    cin >> answer;
    if(answer =="NO"){
        isRunning = true;
        cout << "You may start writing again."<<endl;
        goto A;          //Although this is considered bad style, it is IMO easier to use goto in that Situation with such a small program.
    }
    
    return 0;
};

void help()
{
    cout << "Please start putting in a set of Strings to be written to the file."<<endl
         << "To start a newline, please press enter. To stop writing, write 'STOP'."<<endl
         << "Write 'HELP' to view this command again."<<endl
         << "Please press enter now."<<endl;
};

 

To use the Class, simply take the .h File and the .cpp File, and drag them into a custom project.

Although this code was created and compiled using the xCode interface, it should work on any OS with a fully working C++ Compiler, since no System API is used whatsoever.

 

As instructed by the Program, Interfaces can be created by putting in Strings using the readBuffer() method in the class, which then were to be dynamically loaded by the arduino micro, and displayed on an lcd, while an arduino Uno plays the mp3-Files.

 

This process works as follows:

         MicroOS.ino:

          ///
/*This is the Arduino Micro program, which handles textoutput to the LCD, and reads the custom interface.txt file
 *
 *
 *
 *
 */
///
#include <SD.h>
#include <SdFat.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(12,11,5,4,3,2);

String[4] ReadFile(File file);
String* Interface;

//The Micro only needs 2 Buttons(next and last);
int ButtonNextID = 7;
int ButtonLastID = 6;

//acronyms
#define BNID ButtonNextID
#define BLID ButtonLastID

int currentID = 0;

void LCDRefresh(LiquidCrystal lcd);

void initPins();

bool isHigh(int Bid);
void modID(int currentID);

void setup(){
 
  lcd.begin(16,2);
  initPins();
   pinMode(10,OUTPUT);
  if(SD.begin(14)){
  File interface = SD.open("interface.txt",FILE_READ);
  Interface = ReadFile(interface);
       for(int i = 0; i <= 4;i++){
      String interface[i] = Interface[i];
      }
    }
  };



void loop(){
  LCDPrint(interface[currentID],lcd);
  modID(currentID);
  LCDRefresh(lcd);
};


void LCDPrint(String string, LiquidCrystal LCD){
  LCD.setCursor(0,1);
  LCD.display();
  LCD.println(string);
};

String[4] ReadFile (File file){
String[4] result;
int i = 0;
while(file.available()){
    result[i] = file.read
    i++;
  }
reeturn result;
};

isHigh(int Bid){
 return digitalRead(Bid) == HIGH;
}
void initPins(){
pinMode(10,OUTPUT);
pinMode(BLID,INPUT);
pinMode(BNID,INPUT);
}

void modID(int currentID){
  int lastStateBNID = digitalRead(BNID);
  int lastStateBLID = digitalRead(BLID);
  if(isHigh(BNID) && digitalRead(BNID) != lastStateBNID){
   currentID++;
  }
  if(isHigh(BLID) && digitalRead(BLID) != lastStateBLID){
  currentID--;
  }
 
     delay(250);
  lastStateBNID = digitalRead(BNID);
  lastStateBLID = digitalRead(BLID);
}

void LCDRefresh(LiquidCrystal lcd){
  lcd.noDisplay();
  delay(250);
}

 

    OS.ino:

          #include <SPI.h>
#include <SdFat.h>

#include <SFEMP3Shield.h>

#include <SD.h>


SdFat sd;
SFEMP3Shield MP3player;

int startButtonID = 5;
int StopbuttonID = 4;
int nextButtonID = 3;
int lastButtonID = 2;
const int NumTracks = 4;

void stopMusic();
void PlaylastTrack();
void PlayNextTrack();
void PlayPlaylist();

void setup() {

  Serial.begin(9600);
 
  //Buttoninterupts
  attachInterrupt(StopbuttonID,stopMusic,CHANGE);
  attachInterrupt(startButtonID,PlayPlaylist,CHANGE);
  attachInterrupt(nextButtonID,PlayNextTrack,CHANGE);
  attachInterrupt(lastButtonID,PlaylastTrack,CHANGE);  
  //start the shield
  sd.begin(SD_SEL, SPI_HALF_SPEED);
  MP3player.begin();
  Serial.println("starting");
  uint16_t currentVol = MP3player.getVolume();
  MP3player.setVolume(currentVol*2);
 
}

//do something else now
void loop() {
}
void StopMusic(){
  SFEMP3Shield Mp3Player;
    Mp3Player.stopTrack();
}

void PlayFirstTrack(){
  StopMusic();
  SFEMP3Shield Mp3p;
  Mp3p.playTrack(0);
}

void PlayLastTrack(){
 
  StopMusic();
  SFEMP3Shield Mp3P;
  Mp3P.playTrack(NumTracks);
}

void PlayPlaylist(){
  SFEMP3Shield Mp3P;
   for(int i = 0;i<=NumTracks;i++){
  Mp3P.playTrack(i);
  if(i == NumTracks){
      i = 1;
    }
  }
}

 

microOS.ino is the File to be uploaded to the Micro. If you have successfully finished Lab#6, there should be nothing of that needs further explanation in that File.

In case of the OS.ino, it is a quite different picture, since i found the following Library rather useful:

http://www.billporter.info/2012/01/28/sparkfun-mp3-shield-arduino-library/

This Library defines Methods and Classes for the MP3 Player in Conjunction either with the Arduino Mega or Uno.

These functions handle most of the code needed to play certain Files, and also allow for different Datatypes, like AAC and WAV.

 

Due to some adaptations in the Code, multiple redesigns were necessary to complete the Project, but in the end, it mostly worked out well, besides the fact, that the Arduino Micro does not have enough ram to dynamically allocate Memory and use the LCD, while the UNO has no problems whatsoever if the program is segregated enough.

 

Due to these Designchanges in the later history of the project, i wasn't able to complete any kind of Casing.

The Code on the other hand got a simplification from my initial Softwaredesign, with some ideas simplified.

 

When building the MP3 though, there was some struggle with the wiring, since most of the Micro-Pins were already used and, along with the MP3shield not comming with a viable option to add more wires to it, but besides that, it worked out OK(besides the RAM-problem :), so keep that in mind if you want to rebuild the MP3).

 

Since most of my design is targeted at the developers and creators POV, which was my initial idea, i think i reached that point very well, and is conform with my own POV.

 

As already mentioned, my timing wasn't as fortunate as it could have been, so my final Product is the following:

 

If you were able to follow my design and ideas so far, you should be good to go to reimplement my whole product in nearly no time, since i assume, that you might already have the knowledge needed from prior labs.

 

 

 

Martin Sanner

 

Comments (1)

David S said

at 3:29 pm on Aug 19, 2013

Nice job powering through things at the end of term! We like the way that you spell out your aspirations and plans for the project, and wish that you had started the document with a brief, punchy design point of view statement. Keep in mind that for interfaces in general, too much flexibility can cause "bottlenecks" as well. That is, users are not developers, and they often don't have clear enough points of view regarding their own needs to design an interface that addresses them.

We like that you included photos of your initial design sketches and state diagrams, and wish that these photos were high enough in resolution and size that we could make out the details in them.

We like very much that you present portions of your page as a guide to other students. Perhaps you could also highlight the differences (maybe pros and cons) between the mp3 shield library methods and classes that you reference and the mp3 library that we use in class?

It's clear that you put a lot of effort into creating your file manager class. Regarding the shortage of SRAM for dynamic memory allocation, the Micro (ATmega32U4) has 2.5Kb, while the Uno (ATmega328) has 2.0Kb, so perhaps the challenge you faced with the Micro lies somewhere else?

We feel bad that you didn't have time to copy your circuit to perfboard, or enclose it within a case, as these are rich experiences in and of themselves, and are great skills to develop.

We also wish that you were able to upload a video of your project, even if it's not quite complete yet. The video is an opportunity for us to hear your voice, see your project within its proper context, and acknowledge the wonderful aspects of the project that you want to highlight.

Overall, nicely done, and we hope that you're able to post an update when you've completed things.

David, Jessica, Kevin, Matt and Vivien

You don't have permission to comment on this page.