ECE 4180 Final

Dependencies:   mbed wave_player mbed-rtos C12832_lcd 4DGL-uLCD-SE LCD_fonts SDFileSystem

main.cpp

Committer:
yqin70
Date:
2019-12-08
Revision:
21:cbcbb3480cad
Parent:
20:7d56cdcbc9a5

File content as of revision 21:cbcbb3480cad:

#include "mbed.h"
#include "rtos.h"
#include "stdio.h"
#include <stdlib.h>
#include <time.h>
#include "SDFileSystem.h"
#include "wave_player.h"
#include "mpr121.h"

#include "uLCD_4DGL.h"
#include "Small_6.h"
#include "Small_7.h"
#include "Arial_9.h"
#include "C12832_lcd.h"

#include "globals.h"

//#include "bubbles.h"
#include "stacys_mom.h"
//#include "the_middle.h"
#include "fireflies.h"
#include "sins.h"
#include "LED.hpp"

#include "Lane.hpp"
#include "Bubble.hpp"


//Setup RGB led using PWM pins and class
RGBLed myRGBled(p24,p23,p22); //RGB PWM pins
char bred=0;
char bgreen=0;
char bblue=0; 

volatile bool songselect = false;
volatile bool homescreen = true;
volatile bool songchange = false;
volatile bool playing = false;
Serial pc(USBTX, USBRX);
uLCD_4DGL uLCD(p28,p27,p30);
SDFileSystem sd(p5, p6, p7, p8, "sd"); //SD card
AnalogIn joy_pot(p16);
DigitalOut myled(LED1);
DigitalIn pb1(p20);
DigitalIn pb2(p19);
AnalogOut DACout(p18);
// Create the interrupt receiver object on pin 26 for touch pad IRQ
InterruptIn interrupt(p26);
// Setup the i2c bus on pins 9 and 10
I2C i2c(p9, p10);
// Setup the Mpr121:
// constructor(i2c object, i2c address of the mpr121)
Mpr121 mpr121(&i2c, Mpr121::ADD_VSS);
 
// Key hit/release interrupt routine
//void fallInterrupt() {
//  int key_code=0;
//  int i=0;
//  int value=mpr121.read(0x00);
//  value +=mpr121.read(0x01)<<8;
//  for (i=0; i<12; i++) {
//      if (((value>>i)&0x01)==1) {
//          key_code=i+1;
//      } 
//      }
//}

wave_player waver(&DACout);
Thread thread1, thread2, thread3, thread4;

Ticker nextsample;
volatile int songNdx = 0;
unsigned char *playingSong = NULL;

// mutex to make the lcd lib thread safe
Mutex lcd_mutex;
int songnum = 1;

unsigned short **currentBubbles = NULL;
int bubbleNdx = 0;
volatile float bubblesDrawn = 0;
volatile float bubblesMissed = 0;
volatile float bubblesHit = 0;
int key_code;
int prev_key_code = 0;
volatile bool touchpadPressed = false;


// Thread 1
// print homescreen to LCD
void homescreen_thread()
{
    while (true) {       // thread loop
        lcd_mutex.lock();
        if (homescreen){
            uLCD.cls();
            uLCD.text_height(1.3);
            uLCD.text_width(1.9);
            uLCD.color(WHITE);
            uLCD.locate(5,0);
            uLCD.printf("Tap Tap");
            uLCD.locate(4,1);
            uLCD.printf("Revolution");
            uLCD.locate(0,3);
            uLCD.printf("Pick a song!");
            uLCD.text_height(1.3);
            uLCD.text_width(1.9);
            uLCD.locate(3,5);
            uLCD.printf("Fireflies");
            uLCD.locate(3,7);
            uLCD.printf("Stacy's Mom");
            uLCD.locate(3,9);
            uLCD.printf("I Write Sins \n \t  Not Tragedies");
            uLCD.filled_circle(6, 43, 4, WHITE); //new selection with circle instead of rectangle
            homescreen = false;
        }
        if (songchange) {
            for (int i = 0; i < 3; i++){
                uLCD.filled_circle(6, i*15+43, 4,BLACK);
            }
            uLCD.filled_circle(6, (songnum-1)*15+43, 4,WHITE);
            songchange = false;
        }

        lcd_mutex.unlock();
        Thread::wait(500);
    }
}

// Thread 2
// joystick control for song selection during homescreen
void joystick_thread() {
   while (true) {
        if (!playing) { // we dont want to be able to change the song if we're playing
            if ((joy_pot <= (1.4/3.3)) && songnum>1) {
            songnum--;
            songchange = true;
            } else if ((joy_pot >= (1.8/3.3)) && songnum<3){
                songnum++;
                songchange = true;
            }
            Thread::wait(250);
        }
        
    }
}

// Thread 3
// reads pushbuttons to control menu
void pbcontrol_thread()
{
    // The pb variables will be zero when the pushbutton is pressed
    pb1.mode(PullUp); //pb1 is to select song
    pb2.mode(PullUp); //pb2 is to return to homescreen
    while(true) {       // thread loop
        if (!pb2) {
            homescreen = true;
            songselect = false;
            playing = false;
        }
        if (!pb1) {
            songselect = true;
        }
        Thread::wait(100); 
    }
}

// Thread 4
// control LED effects
void LED_thread() {
    while (true) {
        if (!playing) { //spin LED colors at start menu
            myRGBled = red;
            Thread::wait(200);
            myRGBled = yellow;
            Thread::wait(200);
            myRGBled = orange;
            Thread::wait(200);
            myRGBled = blue;
            Thread::wait(200);
            myRGBled = green;
            Thread::wait(200);
        } else if (playing) {
            //lcd_mutex.lock();
//            uLCD.printf("%d", bubblesMissed);
//            lcd_mutex.unlock();
            if (bubblesHit <= 1) {
                myRGBled = red;
            } else if (bubblesHit <= 3) {
                myRGBled = blue;
            } else {
                myRGBled = green;
            }
            Thread::wait(300);
            
        }
    }
}

// Thread 5
// this thread plays music using the ticker class
void playsound() {
    if (playing) {
        DACout.write(playingSong[songNdx++] / 255.0);
        if (songNdx>120000) {
            playing = false;
            songNdx = 0;
        } 
    } else {
        DACout.write(0.0);
        songNdx = 0;
    }
}

void pickSong() {
    switch (songnum) {
        case 1:
        {
            playingSong = (unsigned char *) fireflies;
            playing = true;
            break;
        }
        
        case 2:
        {
            playingSong = (unsigned char *) stacys_mom;
            playing = true;
            break;
        }
        case 3:
        {
            playingSong = (unsigned char *) sins;
            playing = true;
            break;
        }
        default:
            break;
    }
}



void showScore () {
    
    lcd_mutex.lock();
    uLCD.cls();
    uLCD.color(0x00FF00);        // Change text color and set up menu
    uLCD.text_bold(ON);
    uLCD.locate(1,1);
    uLCD.text_width(2); //4X size text
    uLCD.text_height(2);
    uLCD.printf("Thanks for playing Tap Tap Revolution!");
//    winSound();
    wait(1.5);
    uLCD.cls();
    uLCD.text_width(1); //4X size text
    uLCD.text_height(1);
    uLCD.text_bold(OFF);
    uLCD.color(0xFFFFFF);
    uLCD.locate(2,8);
    uLCD.printf("Your Score:");
    uLCD.color(0x00FF00);
    uLCD.locate(2,10);
    
    float scorePercent = ((bubblesHit) / bubblesDrawn) * 100.0;
    uLCD.printf("Bubbles Hit %4.2f \n", bubblesHit);
    uLCD.printf("Bubbles Drawn %4.2f \n", bubblesDrawn);
    uLCD.printf("Your Score: %4.2f % \n", scorePercent);
    bubblesHit = 0;
    bubblesDrawn = 0;
    //uLCD.printf("%d %", scorePercent);
    wait(10);   
    uLCD.cls();
    uLCD.locate(5,0);
    lcd_mutex.unlock();
    Thread::wait(2000);
}
//touchpad interrupt code
void fallInterrupt()
{
    prev_key_code = key_code;
    key_code=0;
    int i=0;
    int value=mpr121.read(0x00);
    value +=mpr121.read(0x01)<<8;
    i=0;
    //acquires value
    for (i=0; i<12; i++) {
        if (((value>>i)&0x01)==1) key_code=i+1;
    }
    touchpadPressed = true;
}
int main() {
//<<<<<<< working copy
//    
    uLCD.baudrate(3000000); // set baud rate to max
//    
//=======
//    interrupt.fall(&fallInterrupt);
//    interrupt.mode(PullUp);  //for touch keypad
//    lcd_mutex.lock();
//    uLCD.baudrate(3000000);
    uLCD.cls();
    uLCD.media_init();
    uLCD.set_sector_address(0x0077, 0x4002);
    uLCD.display_video(0,0);
//    wait(4);
//    lcd_mutex.unlock();
//>>>>>>> merge rev
    // seed random
    srand (time(NULL));

    thread1.start(homescreen_thread);
    thread2.start(joystick_thread);
    thread3.start(pbcontrol_thread);
    thread4.start(LED_thread);
    nextsample.attach(&playsound, 1.0/8000.0);
    
    Lane *bubbleLanes[3];
    // these positions may need to be adjusted as I assume they're positioned incorrectly...
    bubbleLanes[0] = new Lane(20,15);
    bubbleLanes[1] = new Lane(60,15);
    bubbleLanes[2] = new Lane(100,15);
    interrupt.fall(&fallInterrupt);
    interrupt.mode(PullUp);
    //startup sound?
    
    while(true) {
        if (songselect) {
            homescreen = false;
//            lcd_mutex.lock();
//            uLCD.cls();
//            uLCD.printf("You selected song %2d", songnum);
//            lcd_mutex.unlock();
            pickSong();
            homescreen = false;
            
            // "playing" is updated by playsound() thread
            bubbleLanes[0]->add();
//            bubbleLanes[1]->add();
//            bubbleLanes[2]->add();
            bubbleNdx = 0;
            bool runninggame = true;
            bubblesMissed = 0;
            lcd_mutex.lock();
            uLCD.cls();
            lcd_mutex.unlock();
            while (runninggame)  {
                
                // draw unufilled circles at the bottom of the screen where the user should "tap"
                lcd_mutex.lock();
                uLCD.circle(20,110, 10, GREEN);
                uLCD.circle(60,110, 10, GREEN);
                uLCD.circle(100,110, 10, GREEN);
                lcd_mutex.unlock();
                
                // add bubbles to lanes
//                uLCD.printf("%d", fireflies_bubbles[bubbleNdx][0]);
                /*if (songNdx > fireflies_bubbles[bubbleNdx][0]) { // check if it's time to load a bubble
                    bool addedbubbles = false;
                    if (fireflies_bubbles[bubbleNdx][2]) { // check if add bubble at ndx
                        bubbleLanes[0]->add();
                        addedbubbles = true;
                    }
                
                    if (fireflies_bubbles[bubbleNdx][3]) { // check if add bubble at ndx
                        bubbleLanes[1]->add();
                        addedbubbles = true;
                    }
                
                     if (fireflies_bubbles[bubbleNdx][4]) { // check if add bubble at ndx
                        bubbleLanes[2]->add();
                        addedbubbles = true;
                     }
                     
                     if (addedbubbles) ++bubbleNdx;
                }*/
                
                if (playing && ((rand() % 99) < 20)) { // 20% chance of inserting a bubble
                    bubbleLanes[rand() % 3]->add();
                }
                
                // draw all bubbles
                lcd_mutex.lock();
                bubbleLanes[0]->draw();
                bubbleLanes[1]->draw();
                bubbleLanes[2]->draw();
                uLCD.locate(0,0);
                uLCD.printf("%4.2f", bubblesHit);
                lcd_mutex.unlock();
                
                
                // TODO: check for hits with capacitive touchpad
                // if there is a hit, delete the bubble from the dynamic array
                // replace "true" in the next 3 lines with your logic of when to check for a hit
                //if touchpad has been pressed, checks if bubble in right spot
                if(touchpadPressed){
                //lcd_mutex.lock();
                //uLCD.printf("%d", key_code);
                //lcd_mutex.unlock();
                //pc.printf("Pressed/n");
                if (key_code == 12) bubblesHit += bubbleLanes[0]->checkHit();
                if (key_code == 8) bubblesHit += bubbleLanes[1]->checkHit();
                if (key_code == 4) bubblesHit += bubbleLanes[2]->checkHit();
                }
                touchpadPressed = false;
                
                // move down all the bubbles, deleting bubbles that are out of bounds if required
                bubbleLanes[0]->moveDown();
                bubbleLanes[1]->moveDown();
                bubbleLanes[2]->moveDown();
                
                if (!playing && bubbleLanes[0]->isEmpty() && bubbleLanes[1]->isEmpty() && bubbleLanes[2]->isEmpty()) {
                    runninggame = false;
                }
                
                //this wait delay may need to be tuned
                Thread::wait(100);
            }
            
            // uncomment this when gameplay works
            showScore();
            
            // return to homescreen when
            songselect = false;
            homescreen = true;
        }
        Thread::wait(100);    
    }
}