inital commit
Dependencies: mbed wave_player mbed-rtos 4DGL-uLCD-SE SDFileSystem2 PinDetect MMA8452
main.cpp
- Committer:
- lfink6
- Date:
- 2021-12-15
- Revision:
- 11:1a47726ac72a
- Parent:
- 10:5bd6abd66d12
File content as of revision 11:1a47726ac72a:
/** * @file main.cpp * @authors Christopher Rothmann (chrisrothmann@gatech.edu) & Luke Fink (lfink6@gatech.edu) * @brief C++ Code to create an MP3 player from an mBED * @version 1.0 * @date 2021-12-13 * * @copyright Copyright (c) 2021 **/ // Define included libraries; all libraries below must be compiled together // Note: Some libraries have been updated to work with this code. Ensure all libraries // are the correct by using those included in this github #include "mbed.h" #include "rtos.h" #include "SDFileSystem.h" #include "uLCD_4DGL.h" #include "wave_player.h" #include "MMA8452.h" #include "PinDetect.h" #include <string> #include <vector> // Defining mBED inputs & outputs // mBED LED Outputs for Audiovisualizer/Testing & Diagnostics DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); // Pushbuttons for MP3 Player Controls PinDetect prev(p21); PinDetect next(p22); PinDetect shuffle(p23); PinDetect play(p24); // Serial & Analog Inputs & Ouputs for Data Communication RawSerial blueTooth(p28,p27); Serial pc(USBTX, USBRX); SDFileSystem sd(p5, p6, p7, p12, "sd"); uLCD_4DGL uLCD(p13,p14,p11); MMA8452 acc(p9, p10, 100000); AnalogOut DACout(p18); wave_player waver(&DACout); // Defining Internal Global Variables bool playing = false; int currentSong = 0; int songCount = 0; vector<string> songList; unsigned short max_range = 0xFFFF; // Defining Functions /** * @brief Increments integer variable currentSong by one, while circling back to first song at end of list * @details Function is called both when "next song" pushbutton pressed or bluetooth command is sent; * LED1 switches value when called for diagnostics & testing **/ void nextSong() { //led1 = !led1; if (currentSong == songCount - 1) { currentSong = 0; } else { currentSong++; } } /** * @brief Increments integer variable currentSong by minus one, while circling back to last song at zero * @details Function is called both when "previous song" pushbutton pressed or bluetooth command is sent; * LED2 switches value when called for diagnostics & testing **/ void prevSong() { //led2 = !led2; if (currentSong == 0) { currentSong = songCount - 1; } else { currentSong--; } } /** * @brief Switches boolean variable playing * @details Function is called both when "pause/play" pushbutton pressed or bluetooth command is sent; * LED3 switches value when called for diagnostics & testing **/ void playSong() { //led3 = !led3; playing = !playing; } /** * @brief Generates random integer within song list range to assign integer variable currentSong * @details Function is called both when "shuffle song" pushbutton pressed or bluetooth command is sent; * function seeds a true random value through the noise present on the 5th decimal place of an * accelerometer's input values; * LED4 switches value when called for diagnostics & testing **/ void shuffleSong() { //led4 = !led4; double x, y, z; acc.readXYZGravity(&x,&y,&z); currentSong = int(100000 * (x + y + z)) % songCount; } // Defining Threads /** * @brief Updates LCD screen according to user input & selections * @details First configures LCD screen layout & songlist, then continously checks for changes in global variables * integer currentSong & boolean playing to update LCD screen accordingly. No updates made if no changes found. * All LCD communications occur strictly in this thread. * @param *arguments Input arguments to thread used for RTOS thread library. Not needed to understand thread code. */ void LCDThread(void const *argument) { // Configure LCD screen uLCD.cls(); uLCD.baudrate(3000000); uLCD.background_color(BLACK); uLCD.color(WHITE); uLCD.text_width(1); uLCD.text_height(1); // Print Song List to LCD Screen uLCD.locate(0,0); uLCD.printf("Song List: "); uLCD.locate(0,1); uLCD.printf("->"); for(int i = 0; i < songCount; i++) { uLCD.locate(3,i+1); uLCD.printf("%s\n\r", songList[i].substr(0,songList[i].find(".wav"))); } // Print "NOW PLAYING: " & "STATUS: " feature; initialize to first song on SD card & paused uLCD.locate(0,12); uLCD.printf("NOW PLAYING:"); uLCD.locate(0,13); uLCD.printf("%s", songList[currentSong].substr(0,songList[currentSong].find(".wav"))); uLCD.locate(0,14); uLCD.printf("STATUS: PAUSED"); // Initialize internal thread variables to check for changes to external global variables bool prevPlayLCD = false; int previousSongLCD = 0; // Thread while loop to continously check for changes and update screen accordingly while (true) { // Check if new song has been selected if (previousSongLCD != currentSong) { // Update "NOW PLAYING: " feature uLCD.locate(0,12); uLCD.printf("NOW PLAYING:"); uLCD.locate(0,13); uLCD.printf("%s ", songList[currentSong].substr(0,songList[currentSong].find(".wav"))); // Update "->" feature uLCD.locate(0, previousSongLCD + 1); uLCD.printf(" "); uLCD.locate(0, currentSong + 1); uLCD.printf("->"); // Set internal change check to currentSong previousSongLCD = currentSong; } //Check if change to play/pause status if (prevPlayLCD != playing) { // Update "STATUS: " feature uLCD.locate(0,14); if (playing) { uLCD.printf("STATUS: PLAYING"); } else { uLCD.printf("STATUS: PAUSED "); } // Set internal change check to playing prevPlayLCD = playing; } Thread::wait(50); } } /** * @brief Updates phone screen to latest currentSong playing, sends phone commands to mBED, all over BlueTooth * @details See commenting in thread for step-by-step approach * All BlueTooth communications occur strictly in this thread * BlueTooth Control Pad Module Controls: 1 = Pause/Play, 2 = Next Song, 3 = Previous Song, 4 = Shuffle Song * @param *arguments Input arguments to thread used for RTOS thread library. Not needed to understand thread code. */ void BluetoothThread(void const *argument) { // Initialize internal thread variable to check for changes to external global variables int previousSongBLE = 0; // Thread while look to continously check for BlueTooth commands and update currentSong on phone while (true) { // Update currentSong on phone if (blueTooth.writeable()) { // Check if new song has been selected if (previousSongBLE != currentSong) { // Send currentSong name over BlueTooth string str = "Current Song: "; for (int i = 0; i < 14; i++) { blueTooth.putc(str[i]); } for (int i = 0; i < songList[currentSong].size() - 4; i++) { blueTooth.putc(songList[currentSong][i]); } blueTooth.putc('\n'); previousSongBLE = currentSong; } } // Read in commands from BlueTooth module if (blueTooth.readable()) { // Check for '!B' to be compatible with "Control Pad" Module serial output if (blueTooth.getc()=='!') { if (blueTooth.getc()=='B') { // Check which command was hit char bnum = blueTooth.getc(); // Ensure mBED only updates on release, not hit char bhit = blueTooth.getc(); if (bhit == '0') { switch (bnum) { case '1': playSong(); break; case '2': nextSong(); break; case '3': prevSong(); break; case '4': shuffleSong(); break; default: break; } } } } } Thread::wait(50); } } /** * @brief Updates Mbed LEDs to show current volume level * @details Read and scales analogOut level, then sets leds to show the level in 4 tiers. * @param *arguments Input arguments to thread used for RTOS thread library. Not needed to understand thread code. */ void AudioVisualizerThread(void const *argument) { while(1) { if(playing) { float level = (DACout.read() - 0.25f) * 3.3f; if(level<0.825) { led1=true; led2=led3=led4=false; } else if(level>0.825&&level<1.65) { led1=led2=true; led3=led4=false; } else if(level>1.65&&level<2.47) { led1=led2=led3=true; led4=false; } else if(level>2.47) { led1=led2=led3=led4=true; } Thread::wait(50); } } } // Button Interupt Functions /** * @brief runs nextSong() function on pushbotton hit. Attached using PinDetect. **/ void nextInt() { nextSong(); } /** * @brief runs prevSong() function on pushbotton hit. Attached using PinDetect. **/ void prevInt() { prevSong(); } /** * @brief runs playSong() function on pushbotton hit. Attached using PinDetect. **/ void playInt() { playSong(); } /** * @brief runs shuffleSong() function on pushbotton hit. Attached using PinDetect. **/ void shuffleInt() { shuffleSong(); } /** * @brief Program main routine. * @return int No return expected. */ int main() { // Attach & configure interupts to pushbuttons next.mode(PullUp); prev.mode(PullUp); play.mode(PullUp); shuffle.mode(PullUp); next.attach_deasserted(&nextInt); prev.attach_deasserted(&prevInt); play.attach_deasserted(&playInt); shuffle.attach_deasserted(&shuffleInt); next.setSampleFrequency(); prev.setSampleFrequency(); play.setSampleFrequency(); shuffle.setSampleFrequency(); // Wait 10 milliseconds to ensure functions are attached Thread::wait(10); // Extract file list from SD Card, place in vector<string> songList DIR *dp; struct dirent *dirp; dp = opendir("/sd/myMusic"); if(dp !=NULL) { while ((dirp = readdir(dp)) != NULL) { songList.push_back(string(dirp->d_name)); songCount++; } } // Wait 10 miliseconds to ensure SD card communication complete Thread::wait(10); // Start LCD & BlueTooth Thread Thread thread1(LCDThread); Thread thread2(BluetoothThread); Thread thread3(AudioVisualizerThread); // Main while loop: // Main loop is now considered the Speaker Thread, playing/pausing current song // based on changes in global varaibles boolean playing & integer currentSong while (true) { // Read in selected file FILE *wave_file; string selectedSong= "/sd/myMusic/" + songList[currentSong]; const char* song = selectedSong.c_str(); wave_file=fopen(song,"r"); if(wave_file==NULL) { uLCD.locate(0,12); uLCD.printf("file open error!"); } // Wait 10 miliseconds to ensure file properly loaded Thread::wait(10); // Play file; stop/play feature built into waver library waver.play(wave_file); // Close file fclose(wave_file); // Reset playing variable so song does not repeat playing = false; } }