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

Revision:
5:4fb2d9e36571
Parent:
4:79863d2ea5a0
--- a/main.cpp	Sun Sep 22 17:57:46 2013 +0000
+++ b/main.cpp	Tue Mar 14 16:05:38 2017 +0000
@@ -1,164 +1,247 @@
-// example to test the mbed Lab Board lcd lib with the mbed rtos
-// Pot1 changes the contrast
-// Pot2 changes the speed of the sin wave
-
 #include "mbed.h"
 #include "rtos.h"
-#include "Small_6.h"
-#include "Small_7.h"
-#include "Arial_9.h"
-#include "stdio.h"
-#include "C12832_lcd.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;
 
-C12832_LCD LCD;
-AnalogIn Pot1(p19);
-AnalogIn Pot2(p20);
-PwmOut Speaker(p26);
-PwmOut RGBLED_r(p23);
-PwmOut RGBLED_g(p24);
-PwmOut RGBLED_b(p25);
-DigitalIn joyfire(p14);
-BusIn joy(p15,p12,p13,p16);
-BusOut leds(LED1,LED2,LED3,LED4);
+/* 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/
 
-// mutex to make the lcd lib thread safe
-Mutex lcd_mutex;
+/* 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
-// print counter into first line and wait for 1 s
+// Reads in input from bluefruit module
+// Make sure to be using the Adafruit bluetooth app -> controller -> control pad
 void thread1(void const *args)
 {
-    int i;
-    while(true) {       // thread loop
-        lcd_mutex.lock();
-        LCD.locate(0,0);
-        LCD.set_font((unsigned char*) Small_6);
-        LCD.printf("Thread1 count: %d",i);
-        lcd_mutex.unlock();
-        i++;
-        Thread::wait(1000);
+    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
-// print counter into third line and wait for 0,5s
+// 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)
 {
-    int k;
-    while(true) {       // thread loop
-        lcd_mutex.lock();
-        LCD.locate(0,20);
-        LCD.set_font((unsigned char*) Arial_9);
-        LCD.printf("Thread 2 count : %d",k);
-        lcd_mutex.unlock();
-        k++;
+    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
     }
 }
 
-// Thread 3
-// print a sin function in a small window
-// the value of pot 1 changes the speed of the sine wave
-void thread3(void const *args)
+int main()
 {
-    int i,k,v;
-    double s,a;
-    k = 1;
-    lcd_mutex.lock();
-    LCD.rect(89,0,127,17,1);
-    lcd_mutex.unlock();
-    while(true) {       // thread loop
-        v = Pot1.read_u16();  // get value of pot 1
+    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();
-        for (i=90; i<127; i++) {
-            s = 8 * sin((long double)(i+k) /5);   // pixel to print
-            a = 8 * sin((long double)(i+k-1) /5); // old pixel to erase
-            LCD.pixel(i,9 + (int)a ,0);           // erase pixel
-            LCD.pixel(i,9 + (int)s ,1);           // print pixel
+        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.copy_to_lcd();  // LCD.pixel does not update the lcd
         lcd_mutex.unlock();
-        k++;
-        Thread::wait(v/100);   // value of pot1 / 100
+        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;
 
-// Thread 4
-// input pot 2 and change the contrast of LCD
-void thread4(void const *args)
-{
-    int k;
-    while(true) {         // thread loop
-        k = Pot2.read_u16();  // get the value of poti 2
-        k = k >> 10;          // need only 6 bits for contrast
-        lcd_mutex.lock();
-        LCD.set_contrast(k);
-        lcd_mutex.unlock();
-        Thread::wait(500);    // wait 0.5s
-    }
-}
-// Thread 5
-// RGB LED
-void thread5(void const *args)
-{
-    while(true) {         // thread loop
-        RGBLED_r = 0.5 + (rand() % 11)/20.0;
-        RGBLED_g = 0.5 + (rand() % 11)/20.0;
-        RGBLED_b = 0.5 + (rand() % 11)/20.0;
-        Thread::wait(1667);    // wait 1.5s
+    // 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
     }
 }
-// Thread 6
-// Speaker
-void thread6(void const *args)
-{
-    while(true) {         // thread loop
-        Speaker.period(1.0/800.0);
-        Speaker = 0.01;
-        Thread::wait(1000);    // wait 1.0s
-        Speaker.period(1.0/969.0);
-        Speaker = 0.01;
-        Thread::wait(1000);    // wait 1.0s
-    }
-}
-
-// Thread 7
-// Joystick controls onboard mbed LEDs
-void thread7(void const *args)
-{
-    while(true) {         // thread loop
-        if (joyfire) {
-            leds = 0xf;
-        } else {
-            leds = joy;
-        }
-        Thread::wait(200);    // wait 0.25s
-    }
-}
-
-
-
-int main()
-{
-    int j;
-    LCD.cls();
-
-    Thread t1(thread1); //start thread1
-    Thread t2(thread2); //start thread2
-    Thread t3(thread3); //start thread3
-    Thread t4(thread4); //start thread4
-    Thread t5(thread5); //start thread5
-    Thread t6(thread6); //start thread6
-    Thread t7(thread7); //start thread7
-
-    while(true) {       // main is the next thread
-        lcd_mutex.lock();
-        LCD.locate(0,9);
-        LCD.set_font((unsigned char*) Small_7);
-        j = LCD.get_contrast();    // read the actual contrast
-        LCD.printf("contrast : %d",j);
-        lcd_mutex.unlock();
-        Thread::wait(500);   // wait 0.5s
-    }
-}