Library for ELEC2645 Gamepad PCB. University of Leeds Version 2 January 2020
Dependents: ELEC2645_Ticker_WAV ELEC2645_Project_username ELEC2645_Project_el18vgt ELEC2645_Project_el17oc11 ... more
Diff: Gamepad.cpp
- Revision:
- 21:da0b4e14c867
- Parent:
- 18:e0a4f15a7750
- Child:
- 22:72357412608d
diff -r c0959710291b -r da0b4e14c867 Gamepad.cpp --- a/Gamepad.cpp Wed Apr 26 13:58:10 2017 +0000 +++ b/Gamepad.cpp Mon Jan 27 12:31:15 2020 +0000 @@ -5,58 +5,72 @@ //////////// constructor/destructor //////////// Gamepad::Gamepad() : - _led1(new PwmOut(PTA1)), - _led2(new PwmOut(PTA2)), - _led3(new PwmOut(PTC2)), - _led4(new PwmOut(PTC3)), - _led5(new PwmOut(PTC4)), - _led6(new PwmOut(PTD3)), + _led1(new PwmOut(PTA2)), + _led2(new PwmOut(PTC2)), + _led3(new PwmOut(PTC3)), + _led4(new PwmOut(PTA1)), + _led5(new PwmOut(PTC10)), + _led6(new PwmOut(PTC11)), - _button_A(new InterruptIn(PTB9)), - _button_B(new InterruptIn(PTD0)), - _button_X(new InterruptIn(PTC17)), - _button_Y(new InterruptIn(PTC12)), - _button_L(new InterruptIn(PTB18)), - _button_R(new InterruptIn(PTB3)), - _button_back(new InterruptIn(PTB19)), - _button_start(new InterruptIn(PTC5)), - _button_joystick(new InterruptIn(PTC16)), + _button_A(new InterruptIn(PTC7)), + _button_B(new InterruptIn(PTC9)), + _button_X(new InterruptIn(PTC5)), + _button_Y(new InterruptIn(PTC0)), + _button_start(new InterruptIn(PTC8)), - _vert(new AnalogIn(PTB10)), - _horiz(new AnalogIn(PTB11)), + _vert(new AnalogIn(PTB11)), + _horiz(new AnalogIn(PTB10)), - _buzzer(new PwmOut(PTC10)), - _pot(new AnalogIn(PTB2)), - - _timeout(new Timeout()), - - _event_state(0), + _pot1(new AnalogIn(PTB2)), + _pot2(new AnalogIn(PTB3)), + + dac(new AnalogOut(DAC0_OUT)), + ticker(new Ticker), + timeout(new Timeout), + note_timeout(new Timeout), _x0(0), _y0(0) {} -Gamepad::~Gamepad() -{ - delete _led1,_led2,_led3,_led4,_led5,_led6; - delete _button_A,_button_B,_button_joystick,_vert,_horiz; - delete _button_X,_button_Y,_button_back,_button_start; - delete _button_L,_button_R, _buzzer, _pot, _timeout; -} ///////////////// public methods ///////////////// void Gamepad::init() { leds_off(); - init_buttons(); // read centred values of joystick _x0 = _horiz->read(); _y0 = _vert->read(); - // clear all flags - _event_state = 0; + // Set all buttons to PullUp + _button_A->mode(PullUp); + _button_B->mode(PullUp); + _button_X->mode(PullUp); + _button_Y->mode(PullUp); + _button_start->mode(PullUp); + + // Set up interrupts for the fall of buttons + _button_A->fall(callback(this,&Gamepad::A_fall_interrupt)); + _button_B->fall(callback(this,&Gamepad::B_fall_interrupt)); + _button_X->fall(callback(this,&Gamepad::X_fall_interrupt)); + _button_Y->fall(callback(this,&Gamepad::Y_fall_interrupt)); + _button_start->fall(callback(this,&Gamepad::start_fall_interrupt)); + + // initalise button flags + reset_buttons(); + + // number of samples + _n = 16; + _sample_array = new float[_n]; + + // create sample array for one period between 0.0 and 1.0 + for (int i = 0; i < _n ; i++) { + _sample_array[i] = 0.5f + 0.5f*sin(i*2*PI/_n); + //printf("y[%i] = %f\n",i,_sample_array[i]); + } + } void Gamepad::leds_off() @@ -92,7 +106,7 @@ void Gamepad::led(int n,float val) const { - // ensure they are within vlaid range + // ensure they are within valid range if (val < 0.0f) { val = 0.0f; } @@ -126,28 +140,16 @@ } } -float Gamepad::read_pot() const +float Gamepad::read_pot1() const { - return _pot->read(); + return _pot1->read(); } -void Gamepad::tone(float frequency, float duration) +float Gamepad::read_pot2() const { - _buzzer->period(1.0f/frequency); - _buzzer->write(0.5); // 50% duty cycle - square wave - _timeout->attach(callback(this, &Gamepad::tone_off), duration ); + return _pot2->read(); } -bool Gamepad::check_event(GamepadEvent const id) -{ - // Check whether event flag is set - if (_event_state[id]) { - _event_state.reset(id); // clear flag - return true; - } else { - return false; - } -} // this method gets the magnitude of the joystick movement float Gamepad::get_mag() @@ -194,79 +196,78 @@ return d; } -///////////////////// private methods //////////////////////// +void Gamepad::reset_buttons() { + A_fall = B_fall = X_fall = Y_fall = start_fall = false; +} -void Gamepad::tone_off() -{ - // called after timeout - _buzzer->write(0.0); +bool Gamepad::A_pressed() { + if (A_fall) { + A_fall = false; + return true; + } else { + return false; + } } -void Gamepad::init_buttons() -{ - // turn on pull-downs as other side of button is connected to 3V3 - // button is 0 when not pressed and 1 when pressed - _button_A->mode(PullDown); - _button_B->mode(PullDown); - _button_X->mode(PullDown); - _button_Y->mode(PullDown); - _button_back->mode(PullDown); - _button_start->mode(PullDown); - _button_L->mode(PullDown); - _button_R->mode(PullDown); - _button_joystick->mode(PullDown); - // therefore setup rising edge interrupts - _button_A->rise(callback(this,&Gamepad::a_isr)); - _button_B->rise(callback(this,&Gamepad::b_isr)); - _button_X->rise(callback(this,&Gamepad::x_isr)); - _button_Y->rise(callback(this,&Gamepad::y_isr)); - _button_L->rise(callback(this,&Gamepad::l_isr)); - _button_R->rise(callback(this,&Gamepad::r_isr)); - _button_start->rise(callback(this,&Gamepad::start_isr)); - _button_back->rise(callback(this,&Gamepad::back_isr)); - _button_joystick->rise(callback(this,&Gamepad::joy_isr)); +bool Gamepad::B_pressed() { + if (B_fall) { + B_fall = false; + return true; + } else { + return false; + } +} + +bool Gamepad::X_pressed() { + if (X_fall) { + X_fall = false; + return true; + } else { + return false; + } } -// button interrupts ISRs -// Each of these simply sets the appropriate event bit in the _event_state -// variable -void Gamepad::a_isr() -{ - _event_state.set(A_PRESSED); +bool Gamepad::Y_pressed() { + if (Y_fall) { + Y_fall = false; + return true; + } else { + return false; + } } -void Gamepad::b_isr() -{ - _event_state.set(B_PRESSED); -} -void Gamepad::x_isr() -{ - _event_state.set(X_PRESSED); -} -void Gamepad::y_isr() -{ - _event_state.set(Y_PRESSED); + +bool Gamepad::start_pressed() { + if (start_fall) { + start_fall = false; + return true; + } else { + return false; + } } -void Gamepad::l_isr() -{ - _event_state.set(L_PRESSED); + +bool Gamepad::A_held() { + // Buttons are configured as PullUp hence the not + return !_button_A->read(); } -void Gamepad::r_isr() -{ - _event_state.set(R_PRESSED); + +bool Gamepad::B_held() { + return !_button_B->read(); } -void Gamepad::back_isr() -{ - _event_state.set(BACK_PRESSED); + +bool Gamepad::X_held() { + return !_button_X->read(); } -void Gamepad::start_isr() -{ - _event_state.set(START_PRESSED); + +bool Gamepad::Y_held() { + return !_button_Y->read(); } -void Gamepad::joy_isr() -{ - _event_state.set(JOY_PRESSED); + +bool Gamepad::start_held() { + return !_button_start->read(); } +///////////////////// private methods //////////////////////// + // get raw joystick coordinate in range -1 to 1 // Direction (x,y) // North (0,1) @@ -300,7 +301,7 @@ float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f); float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f); - Vector2D mapped_coord = {x,y}; + Vector2D mapped_coord = {-x,-y}; return mapped_coord; } @@ -338,4 +339,104 @@ Polar p = {mag,angle}; return p; -} \ No newline at end of file +} + +// ISRs for buttons +void Gamepad::A_fall_interrupt() { + A_fall = true; +} +void Gamepad::B_fall_interrupt() { + B_fall = true; +} +void Gamepad::X_fall_interrupt() { + X_fall = true; +} +void Gamepad::Y_fall_interrupt() { + Y_fall = true; +} +void Gamepad::start_fall_interrupt() { + start_fall = true; +} + +void Gamepad::set_bpm(float bpm) +{ + _bpm = bpm; +} + +void Gamepad::tone(float frequency,float duration) +{ + // calculate time step between samples + float dt = 1.0f/(frequency*_n); + // start from beginning of LUT + _sample = 0; + + // setup ticker and timeout to stop ticker + + // the ticker repeats every dt to plat each sample in turn + ticker->attach(callback(this, &Gamepad::ticker_isr), dt); + // the timeout stops the ticker after the required duration + timeout->attach(callback(this, &Gamepad::timeout_isr), duration ); +} + +void Gamepad::play_melody(int length,const int *notes,const int *durations,float bpm,bool repeat) +{ + // copy arguments to member variables + _bpm = bpm; + _notes = notes; // pointer for array + _durations = durations; // pointer for array + _melody_length = length; + _repeat = repeat; + + _note = 0; // start from first note + + play_next_note(); // play the next note in the melody +} + + +void Gamepad::play_next_note() +{ + // _note is the note index to play + + // calculate the duration and frequency of the note + float duration = 60.0f/(_bpm*_durations[_note]); + float frequency = float(_notes[_note]); + //printf("[%i] f = %f d = %f\n",_note,frequency,duration); + + // check if the note is not a space and if not then play the note + if (frequency > 0) { + tone(frequency,duration); + } + + // the timeout goes to the next note in the melody + // double the duration to leave a bit of a gap in between notes to be better + // able to distinguish them + note_timeout->attach(callback(this, &Gamepad::note_timeout_isr), duration*2.0f ); +} + +// called when the next note needs playing +void Gamepad::note_timeout_isr() +{ + _note++; // go onto next note + + // if in repeat mode then reset the note counter when get to end of melody + if (_repeat && _note == _melody_length) { + _note=0; + } + + // check if note is within the melody + if (_note < _melody_length) { + play_next_note(); + } +} + +void Gamepad::ticker_isr() +{ + dac->write(_sample_array[_sample%_n]); // use modulo to get index to play + _sample++; // increment the sample ready for next time +} + +void Gamepad::timeout_isr() +{ + // stops the ticker to end the note + ticker->detach(); +}