FINAL VERSION

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Gamepad.cpp Source File

Gamepad.cpp

00001 #include "Gamepad.h"
00002 
00003 #include "mbed.h"
00004 
00005 //////////// constructor/destructor ////////////
00006 Gamepad::Gamepad()
00007     :
00008     _led1(new PwmOut(PTA1)),
00009     _led2(new PwmOut(PTA2)),
00010     _led3(new PwmOut(PTC2)),
00011     _led4(new PwmOut(PTC3)),
00012     _led5(new PwmOut(PTC4)),
00013     _led6(new PwmOut(PTD3)),
00014 
00015     _button_A(new InterruptIn(PTB9)),
00016     _button_B(new InterruptIn(PTD0)),
00017     _button_X(new InterruptIn(PTC17)),
00018     _button_Y(new InterruptIn(PTC12)),
00019     _button_L(new InterruptIn(PTB18)),
00020     _button_R(new InterruptIn(PTB3)),
00021     _button_back(new InterruptIn(PTB19)),
00022     _button_start(new InterruptIn(PTC5)),
00023     _button_joystick(new InterruptIn(PTC16)),
00024 
00025     _vert(new AnalogIn(PTB10)),
00026     _horiz(new AnalogIn(PTB11)),
00027 
00028     _buzzer(new PwmOut(PTC10)),
00029     _pot(new AnalogIn(PTB2)),
00030 
00031     _timeout(new Timeout()),
00032 
00033     _event_state(0),
00034 
00035     _x0(0),
00036     _y0(0)
00037 {}
00038 
00039 Gamepad::~Gamepad()
00040 {
00041     delete _led1,_led2,_led3,_led4,_led5,_led6;
00042     delete _button_A,_button_B,_button_joystick,_vert,_horiz;
00043     delete _button_X,_button_Y,_button_back,_button_start;
00044     delete _button_L,_button_R, _buzzer, _pot, _timeout;
00045 }
00046 
00047 ///////////////// public methods /////////////////
00048 
00049 void Gamepad::init()
00050 {
00051     leds_off();
00052     init_buttons();
00053 
00054     // read centred values of joystick
00055     _x0 = _horiz->read();
00056     _y0 = _vert->read();
00057 
00058     // clear all flags
00059     _event_state = 0;
00060 }
00061 
00062 void Gamepad::leds_off()
00063 {
00064     leds(0.0);
00065 }
00066 
00067 void Gamepad::leds_on()
00068 {
00069     leds(1.0);
00070 }
00071 
00072 void Gamepad::leds(float val) const
00073 {
00074     if (val < 0.0f) {
00075         val = 0.0f;
00076     }
00077     if (val > 1.0f) {
00078         val = 1.0f;
00079     }
00080 
00081     // leds are active-low, so subtract from 1.0
00082     // 0.0 corresponds to fully-off, 1.0 to fully-on
00083     val = 1.0f - val;
00084 
00085     _led1->write(val);
00086     _led2->write(val);
00087     _led3->write(val);
00088     _led4->write(val);
00089     _led5->write(val);
00090     _led6->write(val);
00091 }
00092 
00093 void Gamepad::led(int n,float val) const
00094 {
00095     // ensure they are within vlaid range
00096     if (val < 0.0f) {
00097         val = 0.0f;
00098     }
00099     if (val > 1.0f) {
00100         val = 1.0f;
00101     }
00102     
00103     switch (n) {
00104         
00105         // check for valid LED number and set value
00106 
00107         case 1:
00108             _led1->write(1.0f-val);   // active-low so subtract from 1
00109             break;
00110         case 2:
00111             _led2->write(1.0f-val);   // active-low so subtract from 1
00112             break;
00113         case 3:
00114             _led3->write(1.0f-val);   // active-low so subtract from 1
00115             break;
00116         case 4:
00117             _led4->write(1.0f-val);   // active-low so subtract from 1
00118             break;
00119         case 5:
00120             _led5->write(1.0f-val);   // active-low so subtract from 1
00121             break;
00122         case 6:
00123             _led6->write(1.0f-val);   // active-low so subtract from 1
00124             break;
00125 
00126     }
00127 }
00128 
00129 float Gamepad::read_pot() const
00130 {
00131     return _pot->read();
00132 }
00133 
00134 void Gamepad::tone(float frequency, float duration)
00135 {
00136     _buzzer->period(1.0f/frequency);
00137     _buzzer->write(0.5);  // 50% duty cycle - square wave
00138     _timeout->attach(callback(this, &Gamepad::tone_off), duration );
00139 }
00140 
00141 bool Gamepad::check_event(GamepadEvent const id)
00142 {
00143     // Check whether event flag is set
00144     if (_event_state[id]) {
00145         _event_state.reset(id);  // clear flag
00146         return true;
00147     } else {
00148         return false;
00149     }
00150 }
00151 
00152 void Gamepad::reset_flags()
00153 {
00154     // reset all button flags
00155     _event_state.reset(A_PRESSED);
00156     _event_state.reset(B_PRESSED);
00157     _event_state.reset(X_PRESSED);
00158     _event_state.reset(Y_PRESSED);
00159     _event_state.reset(START_PRESSED);
00160     _event_state.reset(BACK_PRESSED);
00161     _event_state.reset(L_PRESSED);
00162     _event_state.reset(R_PRESSED);
00163 }
00164 
00165 // this method gets the magnitude of the joystick movement
00166 float Gamepad::get_mag()
00167 {
00168     Polar p = get_polar();
00169     return p.mag;
00170 }
00171 
00172 // this method gets the angle of joystick movement (0 to 360, 0 North)
00173 float Gamepad::get_angle()
00174 {
00175     Polar p = get_polar();
00176     return p.angle;
00177 }
00178 
00179 Direction Gamepad::get_direction()
00180 {
00181     float angle = get_angle();  // 0 to 360, -1 for centred
00182 
00183     Direction d;
00184     // partition 360 into segments and check which segment the angle is in
00185     if (angle < 0.0f) {
00186         d = CENTRE;   // check for -1.0 angle
00187     } else if (angle < 22.5f) {  // then keep going in 45 degree increments
00188         d = N;
00189     } else if (angle < 67.5f) {
00190         d = NE;
00191     } else if (angle < 112.5f) {
00192         d = E;
00193     } else if (angle < 157.5f) {
00194         d = SE;
00195     } else if (angle < 202.5f) {
00196         d = S;
00197     } else if (angle < 247.5f) {
00198         d = SW;
00199     } else if (angle < 292.5f) {
00200         d = W;
00201     } else if (angle < 337.5f) {
00202         d = NW;
00203     } else {
00204         d = N;
00205     }
00206 
00207     return d;
00208 }
00209 
00210 ///////////////////// private methods ////////////////////////
00211 
00212 void Gamepad::tone_off()
00213 {
00214     // called after timeout
00215     _buzzer->write(0.0);
00216 }
00217 
00218 void Gamepad::init_buttons()
00219 {
00220     // turn on pull-downs as other side of button is connected to 3V3
00221     // button is 0 when not pressed and 1 when pressed
00222     _button_A->mode(PullDown);
00223     _button_B->mode(PullDown);
00224     _button_X->mode(PullDown);
00225     _button_Y->mode(PullDown);
00226     _button_back->mode(PullDown);
00227     _button_start->mode(PullDown);
00228     _button_L->mode(PullDown);
00229     _button_R->mode(PullDown);
00230     _button_joystick->mode(PullDown);
00231     // therefore setup rising edge interrupts
00232     _button_A->rise(callback(this,&Gamepad::a_isr));
00233     _button_B->rise(callback(this,&Gamepad::b_isr));
00234     _button_X->rise(callback(this,&Gamepad::x_isr));
00235     _button_Y->rise(callback(this,&Gamepad::y_isr));
00236     _button_L->rise(callback(this,&Gamepad::l_isr));
00237     _button_R->rise(callback(this,&Gamepad::r_isr));
00238     _button_start->rise(callback(this,&Gamepad::start_isr));
00239     _button_back->rise(callback(this,&Gamepad::back_isr));
00240     _button_joystick->rise(callback(this,&Gamepad::joy_isr));
00241 }
00242 
00243 // button interrupts ISRs
00244 // Each of these simply sets the appropriate event bit in the _event_state
00245 // variable
00246 void Gamepad::a_isr()
00247 {
00248     _event_state.set(A_PRESSED);
00249 }
00250 void Gamepad::b_isr()
00251 {
00252     _event_state.set(B_PRESSED);
00253 }
00254 void Gamepad::x_isr()
00255 {
00256     _event_state.set(X_PRESSED);
00257 }
00258 void Gamepad::y_isr()
00259 {
00260     _event_state.set(Y_PRESSED);
00261 }
00262 void Gamepad::l_isr()
00263 {
00264     _event_state.set(L_PRESSED);
00265 }
00266 void Gamepad::r_isr()
00267 {
00268     _event_state.set(R_PRESSED);
00269 }
00270 void Gamepad::back_isr()
00271 {
00272     _event_state.set(BACK_PRESSED);
00273 }
00274 void Gamepad::start_isr()
00275 {
00276     _event_state.set(START_PRESSED);
00277 }
00278 void Gamepad::joy_isr()
00279 {
00280     _event_state.set(JOY_PRESSED);
00281 }
00282 
00283 // get raw joystick coordinate in range -1 to 1
00284 // Direction (x,y)
00285 // North     (0,1)
00286 // East      (1,0)
00287 // South     (0,-1)
00288 // West      (-1,0)
00289 Vector2D Gamepad::get_coord()
00290 {
00291     // read() returns value in range 0.0 to 1.0 so is scaled and centre value
00292     // substracted to get values in the range -1.0 to 1.0
00293     float x = 2.0f*( _horiz->read() - _x0 );
00294     float y = 2.0f*( _vert->read()  - _y0 );
00295 
00296     // Note: the x value here is inverted to ensure the positive x is to the
00297     // right. This is simply due to how the potentiometer on the joystick
00298     // I was using was connected up. It could have been corrected in hardware
00299     // by swapping the power supply pins. Instead it is done in software so may
00300     // need to be changed depending on your wiring setup
00301 
00302     Vector2D coord = {-x,y};
00303     return coord;
00304 }
00305 
00306 // This maps the raw x,y coord onto a circular grid.
00307 // See:  http://mathproofs.blogspot.co.uk/2005/07/mapping-square-to-circle.html
00308 Vector2D Gamepad::get_mapped_coord()
00309 {
00310     Vector2D coord = get_coord();
00311 
00312     // do the transformation
00313     float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f);
00314     float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f);
00315 
00316     Vector2D mapped_coord = {x,y};
00317     return mapped_coord;
00318 }
00319 
00320 // this function converts the mapped coordinates into polar form
00321 Polar Gamepad::get_polar()
00322 {
00323     // get the mapped coordinate
00324     Vector2D coord = get_mapped_coord();
00325 
00326     // at this point, 0 degrees (i.e. x-axis) will be defined to the East.
00327     // We want 0 degrees to correspond to North and increase clockwise to 359
00328     // like a compass heading, so we need to swap the axis and invert y
00329     float x = coord.y;
00330     float y = coord.x;
00331 
00332     float mag = sqrt(x*x+y*y);  // pythagoras
00333     float angle = RAD2DEG*atan2(y,x);
00334     // angle will be in range -180 to 180, so add 360 to negative angles to
00335     // move to 0 to 360 range
00336     if (angle < 0.0f) {
00337         angle+=360.0f;
00338     }
00339 
00340     // the noise on the ADC causes the values of x and y to fluctuate slightly
00341     // around the centred values. This causes the random angle values to get
00342     // calculated when the joystick is centred and untouched. This is also when
00343     // the magnitude is very small, so we can check for a small magnitude and then
00344     // set the angle to -1. This will inform us when the angle is invalid and the
00345     // joystick is centred
00346 
00347     if (mag < TOL) {
00348         mag = 0.0f;
00349         angle = -1.0f;
00350     }
00351 
00352     Polar p = {mag,angle};
00353     return p;
00354 }