Bluetooth MP3 Player with uLCD, Speaker, and SD card hardware components

Dependencies:   4DGL-uLCD-SE SDFileSystem mbed-rtos mbed

Fork of app-board-RTOS-Threads by jim hamblen

main.cpp

Committer:
pwu64
Date:
2017-03-14
Revision:
6:0c55c199443d
Parent:
5:4fb2d9e36571

File content as of revision 6:0c55c199443d:

#include "mbed.h"
#include "rtos.h"
#include "uLCD_4DGL.h"
#include "SDFileSystem.h"
#include "wave_player.h"
#include <string>
#include <vector>

/* Hardware Initialization */
Serial  blue(p13,p14);
BusOut myled(LED1,LED2,LED3,LED4);
uLCD_4DGL uLCD(p28, p27, p30);
AnalogOut Speaker(p18);
SDFileSystem sd(p5, p6, p7, p8, "sd");
wave_player waver(&Speaker);
FILE *wave_file;

/* Mutexes to make the code thread safe */
Mutex lcd_mutex;
Mutex stdio_mutex;
Mutex time_mutex;
Mutex inx_mutex;
Mutex currSong_mutex;
Mutex printed_mutex; //Basically will need to go around every if statement. May be usable as a generic mutex for everything/

/* Variables */
bool Menu=1; //1: menu mode 0: play mode
vector <string> songList; // vector of songs to index
string currSong="";
int startInx=0;     // starting index of songs to display on lcd
int inxIncrement=2; //4=Full page scroll 1=single song scrolling
int songTime;
int numSongs; // total # of songs on sd card
string dir = "/sd/myMusic/"; // directory of songs on SD card
int songsPerPage=4;
bool playing = false;
bool printed = false;

// Thread 1
// Reads in input from bluefruit module
// Make sure to be using the Adafruit bluetooth app -> controller -> control pad
void thread1(void const *args)
{
    while(1) {
        char bnum = 0; // number 1-8
        char bhit = 0; // number 0 or 1 (release or hit)
        if(blue.readable()) {
            stdio_mutex.lock();
            // Command come in as !B##
            if (blue.getc()=='!') {
                if (blue.getc()=='B') { //button data packet
                    bnum = blue.getc(); //button number
                    bhit = blue.getc(); //1=hit, 0=release
                    if (blue.getc()==char(~('!' + 'B' + bnum + bhit))) { //checksum OK?
                        myled = bnum - '0'; //current button number will appear on LEDs
                        switch (bnum) {
                            case '1':
                            case '2':
                            case '3':
                            case '4': //number button 1-4
                                if(Menu) {
                                    /* Pressing a number button selects the corresponding
                                    numbered song and displays the number on the LCD */
                                    currSong_mutex.lock();
                                    currSong = songList[startInx + bnum-'1'];
                                    currSong_mutex.unlock();
                                    lcd_mutex.lock();
                                    uLCD.locate(0,15);
                                    uLCD.printf("Song selected: %d", bnum - '0');
                                    lcd_mutex.unlock();
                                }
                                break;
                            case '5': //button 5 up arrow
                                if (bhit=='1') {
                                    if(Menu) {
                                        /* Page up */
                                        inx_mutex.lock();
                                        startInx -= inxIncrement;
                                        startInx = startInx<0?0:startInx;
                                        inx_mutex.unlock();
                                        printed_mutex.lock();
                                        printed = false;
                                        printed_mutex.unlock();
                                    }
                                    break;
                                case '6': //button 6 down arrow
                                    if (bhit=='1') {
                                        if(Menu) {
                                            /* Page down */
                                            inx_mutex.lock();
                                            startInx += inxIncrement;
                                            startInx = startInx>songList.size()-songsPerPage?songList.size()-songsPerPage:startInx;
                                            inx_mutex.unlock();
                                            printed_mutex.lock();
                                            printed = false;
                                            printed_mutex.unlock();
                                        }
                                    }
                                    break;
                                case '7': //button 7 left arrow
                                    // stops the music from playing
                                    // does nothing if nothing is playing
                                    if (bhit=='1') {
                                        if(!Menu) {
                                            playing = false;
                                            Menu = 1;
                                            printed_mutex.lock();
                                            printed =false;
                                            printed_mutex.unlock();
                                        }
                                    }
                                    break;
                                case '8': //button 8 right arrow
                                    // change to play menu and play music
                                    if (bhit=='1') {
                                        if(Menu) {
                                            lcd_mutex.lock();
                                            uLCD.cls();
                                            // Draw a playing icon
                                            uLCD.circle(60,40,40,GREEN);
                                            uLCD.triangle(45,70,45,10,95,40,GREEN);
                                            uLCD.locate(0,12);
                                            currSong_mutex.lock();
                                            // Display current song playing
                                            uLCD.printf("%s playing...",currSong.substr(0,currSong.find(".wav")));
                                            currSong_mutex.unlock();
                                            lcd_mutex.unlock();
                                            playing =true;
                                            Menu = 0;
                                        }
                                    }
                                    break;
                                default:
                                    break;
                                }
                        }
                    }
                }
                stdio_mutex.unlock();
            }
        }
        Thread::wait(250); // wait .25s
    }
}

// Thread 2
// Play the currSong selected from the bluetooth controller
// playing is a bool defined in the waveplayer as an extern variable that adds
// play/stop functionality
void thread2(void const *args)
{
    while(true) {
        if(!Menu && playing && !(currSong == "")) {
            time_mutex.lock();
            // restart songTime
            songTime=0;
            time_mutex.unlock();
            string fileBuffer;
            currSong_mutex.lock();
            // concatenate the directory with the song selected
            fileBuffer = "/sd/myMusic/" + currSong;
            currSong_mutex.unlock();
            // convert to const char* for the wave_file to open
            const char* songToPlay = fileBuffer.c_str();
            wave_file = fopen(songToPlay, "r");
            waver.play(wave_file);
            fclose(wave_file);
            playing =false;
            Menu=1;
            printed_mutex.lock();
            printed = false;
            printed_mutex.unlock();
        }
        Thread::wait(500); // wait 0.5s
    }
}

int main()
{
    uLCD.cls();
    // Read all files on SD card into a string vector called songList
    // Make sure to lock appropriate mutexes
    DIR *dp;
    struct dirent *dirp;
    dp = opendir("/sd/myMusic");
    numSongs = 0;
    if (dp != NULL) {
        lcd_mutex.lock();
        stdio_mutex.lock();
        while ((dirp = readdir(dp)) != NULL) {
            songList.push_back(string(dirp->d_name));
            //uLCD.printf("\r%s\r\n", string(dirp->d_name));
            numSongs++;
        }
        lcd_mutex.unlock();
        stdio_mutex.unlock();
    } else {
        uLCD.printf("Could not open directory!\n");
    }
    closedir(dp);

    // Print songsPerPage # onto the LCD screen
    for (int i = 0; i < songsPerPage; i++) {
        lcd_mutex.lock();
        uLCD.printf("\r%d. %s\r\n\r\n", (i+1), songList[startInx+i].substr(0,songList[startInx + i].find(".wav")));
        lcd_mutex.unlock();
    }
    printed = true;
    // Set bluetooth baudrate
    blue.baud(9600);

    // Start threading
    Thread t1(thread1); // bluetooth
    Thread t2(thread2); //song

    songTime=0;

    // Main thread - counts up songTime and displays the time the song has been
    // playing on LCD screen
    while(true) {       // main is the next thread
        if(!Menu) {
            lcd_mutex.lock();
            stdio_mutex.lock();
            uLCD.locate(0,15);
            time_mutex.lock();
            uLCD.printf("%d:%02d",songTime/60,songTime%60);
            songTime++;
            time_mutex.unlock();
            lcd_mutex.unlock();
            stdio_mutex.unlock();
        } else {
            printed_mutex.lock();
            if(!printed) {
                lcd_mutex.lock();
                uLCD.cls();
                for (int i = 0; i < songsPerPage; i++) {
                    // Creates a substring out of the wave file names which takes out the .wav in the title
                    uLCD.printf("\r%d. %s\r\n\r\n", (i+1), songList[startInx+i].substr(0,songList[startInx + i].find(".wav")));
                }
                lcd_mutex.unlock();
                printed =true;
            }
            printed_mutex.unlock();
        }
        Thread::wait(1000); // Waits 1 second before updating songTime
    }
}