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

Committer:
pwu64
Date:
Tue Mar 14 16:36:23 2017 +0000
Revision:
6:0c55c199443d
Parent:
5:4fb2d9e36571
2nd Commit to try and publish mp3 player

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dreschpe 0:f6a57b843f79 1 #include "mbed.h"
dreschpe 0:f6a57b843f79 2 #include "rtos.h"
pwu64 5:4fb2d9e36571 3 #include "uLCD_4DGL.h"
pwu64 5:4fb2d9e36571 4 #include "SDFileSystem.h"
pwu64 5:4fb2d9e36571 5 #include "wave_player.h"
pwu64 5:4fb2d9e36571 6 #include <string>
pwu64 5:4fb2d9e36571 7 #include <vector>
dreschpe 0:f6a57b843f79 8
pwu64 5:4fb2d9e36571 9 /* Hardware Initialization */
pwu64 5:4fb2d9e36571 10 Serial blue(p13,p14);
pwu64 5:4fb2d9e36571 11 BusOut myled(LED1,LED2,LED3,LED4);
pwu64 5:4fb2d9e36571 12 uLCD_4DGL uLCD(p28, p27, p30);
pwu64 5:4fb2d9e36571 13 AnalogOut Speaker(p18);
pwu64 5:4fb2d9e36571 14 SDFileSystem sd(p5, p6, p7, p8, "sd");
pwu64 5:4fb2d9e36571 15 wave_player waver(&Speaker);
pwu64 5:4fb2d9e36571 16 FILE *wave_file;
4180_1 4:79863d2ea5a0 17
pwu64 5:4fb2d9e36571 18 /* Mutexes to make the code thread safe */
pwu64 5:4fb2d9e36571 19 Mutex lcd_mutex;
pwu64 5:4fb2d9e36571 20 Mutex stdio_mutex;
pwu64 5:4fb2d9e36571 21 Mutex time_mutex;
pwu64 5:4fb2d9e36571 22 Mutex inx_mutex;
pwu64 5:4fb2d9e36571 23 Mutex currSong_mutex;
pwu64 5:4fb2d9e36571 24 Mutex printed_mutex; //Basically will need to go around every if statement. May be usable as a generic mutex for everything/
dreschpe 2:a69c8c5f5b03 25
pwu64 5:4fb2d9e36571 26 /* Variables */
pwu64 5:4fb2d9e36571 27 bool Menu=1; //1: menu mode 0: play mode
pwu64 5:4fb2d9e36571 28 vector <string> songList; // vector of songs to index
pwu64 5:4fb2d9e36571 29 string currSong="";
pwu64 5:4fb2d9e36571 30 int startInx=0; // starting index of songs to display on lcd
pwu64 5:4fb2d9e36571 31 int inxIncrement=2; //4=Full page scroll 1=single song scrolling
pwu64 5:4fb2d9e36571 32 int songTime;
pwu64 5:4fb2d9e36571 33 int numSongs; // total # of songs on sd card
pwu64 5:4fb2d9e36571 34 string dir = "/sd/myMusic/"; // directory of songs on SD card
pwu64 5:4fb2d9e36571 35 int songsPerPage=4;
pwu64 5:4fb2d9e36571 36 bool playing = false;
pwu64 5:4fb2d9e36571 37 bool printed = false;
dreschpe 0:f6a57b843f79 38
dreschpe 2:a69c8c5f5b03 39 // Thread 1
pwu64 5:4fb2d9e36571 40 // Reads in input from bluefruit module
pwu64 5:4fb2d9e36571 41 // Make sure to be using the Adafruit bluetooth app -> controller -> control pad
dreschpe 0:f6a57b843f79 42 void thread1(void const *args)
dreschpe 0:f6a57b843f79 43 {
pwu64 5:4fb2d9e36571 44 while(1) {
pwu64 5:4fb2d9e36571 45 char bnum = 0; // number 1-8
pwu64 5:4fb2d9e36571 46 char bhit = 0; // number 0 or 1 (release or hit)
pwu64 5:4fb2d9e36571 47 if(blue.readable()) {
pwu64 5:4fb2d9e36571 48 stdio_mutex.lock();
pwu64 5:4fb2d9e36571 49 // Command come in as !B##
pwu64 5:4fb2d9e36571 50 if (blue.getc()=='!') {
pwu64 5:4fb2d9e36571 51 if (blue.getc()=='B') { //button data packet
pwu64 5:4fb2d9e36571 52 bnum = blue.getc(); //button number
pwu64 5:4fb2d9e36571 53 bhit = blue.getc(); //1=hit, 0=release
pwu64 5:4fb2d9e36571 54 if (blue.getc()==char(~('!' + 'B' + bnum + bhit))) { //checksum OK?
pwu64 5:4fb2d9e36571 55 myled = bnum - '0'; //current button number will appear on LEDs
pwu64 5:4fb2d9e36571 56 switch (bnum) {
pwu64 5:4fb2d9e36571 57 case '1':
pwu64 5:4fb2d9e36571 58 case '2':
pwu64 5:4fb2d9e36571 59 case '3':
pwu64 5:4fb2d9e36571 60 case '4': //number button 1-4
pwu64 5:4fb2d9e36571 61 if(Menu) {
pwu64 5:4fb2d9e36571 62 /* Pressing a number button selects the corresponding
pwu64 5:4fb2d9e36571 63 numbered song and displays the number on the LCD */
pwu64 5:4fb2d9e36571 64 currSong_mutex.lock();
pwu64 5:4fb2d9e36571 65 currSong = songList[startInx + bnum-'1'];
pwu64 5:4fb2d9e36571 66 currSong_mutex.unlock();
pwu64 5:4fb2d9e36571 67 lcd_mutex.lock();
pwu64 5:4fb2d9e36571 68 uLCD.locate(0,15);
pwu64 5:4fb2d9e36571 69 uLCD.printf("Song selected: %d", bnum - '0');
pwu64 5:4fb2d9e36571 70 lcd_mutex.unlock();
pwu64 5:4fb2d9e36571 71 }
pwu64 5:4fb2d9e36571 72 break;
pwu64 5:4fb2d9e36571 73 case '5': //button 5 up arrow
pwu64 5:4fb2d9e36571 74 if (bhit=='1') {
pwu64 5:4fb2d9e36571 75 if(Menu) {
pwu64 5:4fb2d9e36571 76 /* Page up */
pwu64 5:4fb2d9e36571 77 inx_mutex.lock();
pwu64 5:4fb2d9e36571 78 startInx -= inxIncrement;
pwu64 5:4fb2d9e36571 79 startInx = startInx<0?0:startInx;
pwu64 5:4fb2d9e36571 80 inx_mutex.unlock();
pwu64 5:4fb2d9e36571 81 printed_mutex.lock();
pwu64 5:4fb2d9e36571 82 printed = false;
pwu64 5:4fb2d9e36571 83 printed_mutex.unlock();
pwu64 5:4fb2d9e36571 84 }
pwu64 5:4fb2d9e36571 85 break;
pwu64 5:4fb2d9e36571 86 case '6': //button 6 down arrow
pwu64 5:4fb2d9e36571 87 if (bhit=='1') {
pwu64 5:4fb2d9e36571 88 if(Menu) {
pwu64 5:4fb2d9e36571 89 /* Page down */
pwu64 5:4fb2d9e36571 90 inx_mutex.lock();
pwu64 5:4fb2d9e36571 91 startInx += inxIncrement;
pwu64 5:4fb2d9e36571 92 startInx = startInx>songList.size()-songsPerPage?songList.size()-songsPerPage:startInx;
pwu64 5:4fb2d9e36571 93 inx_mutex.unlock();
pwu64 5:4fb2d9e36571 94 printed_mutex.lock();
pwu64 5:4fb2d9e36571 95 printed = false;
pwu64 5:4fb2d9e36571 96 printed_mutex.unlock();
pwu64 5:4fb2d9e36571 97 }
pwu64 5:4fb2d9e36571 98 }
pwu64 5:4fb2d9e36571 99 break;
pwu64 5:4fb2d9e36571 100 case '7': //button 7 left arrow
pwu64 5:4fb2d9e36571 101 // stops the music from playing
pwu64 5:4fb2d9e36571 102 // does nothing if nothing is playing
pwu64 5:4fb2d9e36571 103 if (bhit=='1') {
pwu64 5:4fb2d9e36571 104 if(!Menu) {
pwu64 5:4fb2d9e36571 105 playing = false;
pwu64 5:4fb2d9e36571 106 Menu = 1;
pwu64 5:4fb2d9e36571 107 printed_mutex.lock();
pwu64 5:4fb2d9e36571 108 printed =false;
pwu64 5:4fb2d9e36571 109 printed_mutex.unlock();
pwu64 5:4fb2d9e36571 110 }
pwu64 5:4fb2d9e36571 111 }
pwu64 5:4fb2d9e36571 112 break;
pwu64 5:4fb2d9e36571 113 case '8': //button 8 right arrow
pwu64 5:4fb2d9e36571 114 // change to play menu and play music
pwu64 5:4fb2d9e36571 115 if (bhit=='1') {
pwu64 5:4fb2d9e36571 116 if(Menu) {
pwu64 5:4fb2d9e36571 117 lcd_mutex.lock();
pwu64 5:4fb2d9e36571 118 uLCD.cls();
pwu64 5:4fb2d9e36571 119 // Draw a playing icon
pwu64 5:4fb2d9e36571 120 uLCD.circle(60,40,40,GREEN);
pwu64 5:4fb2d9e36571 121 uLCD.triangle(45,70,45,10,95,40,GREEN);
pwu64 5:4fb2d9e36571 122 uLCD.locate(0,12);
pwu64 5:4fb2d9e36571 123 currSong_mutex.lock();
pwu64 5:4fb2d9e36571 124 // Display current song playing
pwu64 5:4fb2d9e36571 125 uLCD.printf("%s playing...",currSong.substr(0,currSong.find(".wav")));
pwu64 5:4fb2d9e36571 126 currSong_mutex.unlock();
pwu64 5:4fb2d9e36571 127 lcd_mutex.unlock();
pwu64 5:4fb2d9e36571 128 playing =true;
pwu64 5:4fb2d9e36571 129 Menu = 0;
pwu64 5:4fb2d9e36571 130 }
pwu64 5:4fb2d9e36571 131 }
pwu64 5:4fb2d9e36571 132 break;
pwu64 5:4fb2d9e36571 133 default:
pwu64 5:4fb2d9e36571 134 break;
pwu64 5:4fb2d9e36571 135 }
pwu64 5:4fb2d9e36571 136 }
pwu64 5:4fb2d9e36571 137 }
pwu64 5:4fb2d9e36571 138 }
pwu64 5:4fb2d9e36571 139 stdio_mutex.unlock();
pwu64 5:4fb2d9e36571 140 }
pwu64 5:4fb2d9e36571 141 }
pwu64 5:4fb2d9e36571 142 Thread::wait(250); // wait .25s
dreschpe 0:f6a57b843f79 143 }
dreschpe 0:f6a57b843f79 144 }
dreschpe 0:f6a57b843f79 145
dreschpe 2:a69c8c5f5b03 146 // Thread 2
pwu64 5:4fb2d9e36571 147 // Play the currSong selected from the bluetooth controller
pwu64 5:4fb2d9e36571 148 // playing is a bool defined in the waveplayer as an extern variable that adds
pwu64 5:4fb2d9e36571 149 // play/stop functionality
dreschpe 0:f6a57b843f79 150 void thread2(void const *args)
dreschpe 0:f6a57b843f79 151 {
pwu64 5:4fb2d9e36571 152 while(true) {
pwu64 5:4fb2d9e36571 153 if(!Menu && playing && !(currSong == "")) {
pwu64 5:4fb2d9e36571 154 time_mutex.lock();
pwu64 5:4fb2d9e36571 155 // restart songTime
pwu64 5:4fb2d9e36571 156 songTime=0;
pwu64 5:4fb2d9e36571 157 time_mutex.unlock();
pwu64 5:4fb2d9e36571 158 string fileBuffer;
pwu64 5:4fb2d9e36571 159 currSong_mutex.lock();
pwu64 5:4fb2d9e36571 160 // concatenate the directory with the song selected
pwu64 5:4fb2d9e36571 161 fileBuffer = "/sd/myMusic/" + currSong;
pwu64 5:4fb2d9e36571 162 currSong_mutex.unlock();
pwu64 5:4fb2d9e36571 163 // convert to const char* for the wave_file to open
pwu64 5:4fb2d9e36571 164 const char* songToPlay = fileBuffer.c_str();
pwu64 5:4fb2d9e36571 165 wave_file = fopen(songToPlay, "r");
pwu64 5:4fb2d9e36571 166 waver.play(wave_file);
pwu64 5:4fb2d9e36571 167 fclose(wave_file);
pwu64 5:4fb2d9e36571 168 playing =false;
pwu64 5:4fb2d9e36571 169 Menu=1;
pwu64 5:4fb2d9e36571 170 printed_mutex.lock();
pwu64 5:4fb2d9e36571 171 printed = false;
pwu64 5:4fb2d9e36571 172 printed_mutex.unlock();
pwu64 5:4fb2d9e36571 173 }
dreschpe 2:a69c8c5f5b03 174 Thread::wait(500); // wait 0.5s
dreschpe 0:f6a57b843f79 175 }
dreschpe 0:f6a57b843f79 176 }
dreschpe 0:f6a57b843f79 177
pwu64 5:4fb2d9e36571 178 int main()
dreschpe 1:1c6a9eaf55b5 179 {
pwu64 5:4fb2d9e36571 180 uLCD.cls();
pwu64 5:4fb2d9e36571 181 // Read all files on SD card into a string vector called songList
pwu64 5:4fb2d9e36571 182 // Make sure to lock appropriate mutexes
pwu64 5:4fb2d9e36571 183 DIR *dp;
pwu64 5:4fb2d9e36571 184 struct dirent *dirp;
pwu64 5:4fb2d9e36571 185 dp = opendir("/sd/myMusic");
pwu64 5:4fb2d9e36571 186 numSongs = 0;
pwu64 5:4fb2d9e36571 187 if (dp != NULL) {
dreschpe 2:a69c8c5f5b03 188 lcd_mutex.lock();
pwu64 5:4fb2d9e36571 189 stdio_mutex.lock();
pwu64 5:4fb2d9e36571 190 while ((dirp = readdir(dp)) != NULL) {
pwu64 5:4fb2d9e36571 191 songList.push_back(string(dirp->d_name));
pwu64 5:4fb2d9e36571 192 //uLCD.printf("\r%s\r\n", string(dirp->d_name));
pwu64 5:4fb2d9e36571 193 numSongs++;
dreschpe 1:1c6a9eaf55b5 194 }
dreschpe 2:a69c8c5f5b03 195 lcd_mutex.unlock();
pwu64 5:4fb2d9e36571 196 stdio_mutex.unlock();
pwu64 5:4fb2d9e36571 197 } else {
pwu64 5:4fb2d9e36571 198 uLCD.printf("Could not open directory!\n");
pwu64 5:4fb2d9e36571 199 }
pwu64 5:4fb2d9e36571 200 closedir(dp);
pwu64 5:4fb2d9e36571 201
pwu64 5:4fb2d9e36571 202 // Print songsPerPage # onto the LCD screen
pwu64 5:4fb2d9e36571 203 for (int i = 0; i < songsPerPage; i++) {
pwu64 5:4fb2d9e36571 204 lcd_mutex.lock();
pwu64 5:4fb2d9e36571 205 uLCD.printf("\r%d. %s\r\n\r\n", (i+1), songList[startInx+i].substr(0,songList[startInx + i].find(".wav")));
pwu64 5:4fb2d9e36571 206 lcd_mutex.unlock();
dreschpe 1:1c6a9eaf55b5 207 }
pwu64 5:4fb2d9e36571 208 printed = true;
pwu64 5:4fb2d9e36571 209 // Set bluetooth baudrate
pwu64 5:4fb2d9e36571 210 blue.baud(9600);
pwu64 5:4fb2d9e36571 211
pwu64 5:4fb2d9e36571 212 // Start threading
pwu64 5:4fb2d9e36571 213 Thread t1(thread1); // bluetooth
pwu64 5:4fb2d9e36571 214 Thread t2(thread2); //song
pwu64 5:4fb2d9e36571 215
pwu64 5:4fb2d9e36571 216 songTime=0;
dreschpe 0:f6a57b843f79 217
pwu64 5:4fb2d9e36571 218 // Main thread - counts up songTime and displays the time the song has been
pwu64 5:4fb2d9e36571 219 // playing on LCD screen
pwu64 5:4fb2d9e36571 220 while(true) { // main is the next thread
pwu64 5:4fb2d9e36571 221 if(!Menu) {
pwu64 5:4fb2d9e36571 222 lcd_mutex.lock();
pwu64 5:4fb2d9e36571 223 stdio_mutex.lock();
pwu64 5:4fb2d9e36571 224 uLCD.locate(0,15);
pwu64 5:4fb2d9e36571 225 time_mutex.lock();
pwu64 5:4fb2d9e36571 226 uLCD.printf("%d:%02d",songTime/60,songTime%60);
pwu64 5:4fb2d9e36571 227 songTime++;
pwu64 5:4fb2d9e36571 228 time_mutex.unlock();
pwu64 5:4fb2d9e36571 229 lcd_mutex.unlock();
pwu64 5:4fb2d9e36571 230 stdio_mutex.unlock();
pwu64 5:4fb2d9e36571 231 } else {
pwu64 5:4fb2d9e36571 232 printed_mutex.lock();
pwu64 5:4fb2d9e36571 233 if(!printed) {
pwu64 5:4fb2d9e36571 234 lcd_mutex.lock();
pwu64 5:4fb2d9e36571 235 uLCD.cls();
pwu64 5:4fb2d9e36571 236 for (int i = 0; i < songsPerPage; i++) {
pwu64 5:4fb2d9e36571 237 // Creates a substring out of the wave file names which takes out the .wav in the title
pwu64 5:4fb2d9e36571 238 uLCD.printf("\r%d. %s\r\n\r\n", (i+1), songList[startInx+i].substr(0,songList[startInx + i].find(".wav")));
pwu64 5:4fb2d9e36571 239 }
pwu64 5:4fb2d9e36571 240 lcd_mutex.unlock();
pwu64 5:4fb2d9e36571 241 printed =true;
pwu64 5:4fb2d9e36571 242 }
pwu64 5:4fb2d9e36571 243 printed_mutex.unlock();
pwu64 5:4fb2d9e36571 244 }
pwu64 5:4fb2d9e36571 245 Thread::wait(1000); // Waits 1 second before updating songTime
4180_1 4:79863d2ea5a0 246 }
dreschpe 1:1c6a9eaf55b5 247 }