Steven Mahasin / Mbed 2 deprecated DreamDungeon

Dependencies:   mbed MotionSensor

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 // this method gets the magnitude of the joystick movement
00153 float Gamepad::get_mag()
00154 {
00155     Polar p = get_polar();
00156     return p.mag;
00157 }
00158 
00159 // this method gets the angle of joystick movement (0 to 360, 0 North)
00160 float Gamepad::get_angle()
00161 {
00162     Polar p = get_polar();
00163     return p.angle;
00164 }
00165 
00166 Direction Gamepad::get_direction()
00167 {
00168     float angle = get_angle();  // 0 to 360, -1 for centred
00169 
00170     Direction d;
00171     // partition 360 into segments and check which segment the angle is in
00172     if (angle < 0.0f) {
00173         d = CENTRE;   // check for -1.0 angle
00174     } else if (angle < 22.5f) {  // then keep going in 45 degree increments
00175         d = N;
00176     } else if (angle < 67.5f) {
00177         d = NE;
00178     } else if (angle < 112.5f) {
00179         d = E;
00180     } else if (angle < 157.5f) {
00181         d = SE;
00182     } else if (angle < 202.5f) {
00183         d = S;
00184     } else if (angle < 247.5f) {
00185         d = SW;
00186     } else if (angle < 292.5f) {
00187         d = W;
00188     } else if (angle < 337.5f) {
00189         d = NW;
00190     } else {
00191         d = N;
00192     }
00193 
00194     return d;
00195 }
00196 
00197 ///////////////////// private methods ////////////////////////
00198 
00199 void Gamepad::tone_off()
00200 {
00201     // called after timeout
00202     _buzzer->write(0.0);
00203 }
00204 
00205 void Gamepad::init_buttons()
00206 {
00207     // turn on pull-downs as other side of button is connected to 3V3
00208     // button is 0 when not pressed and 1 when pressed
00209     _button_A->mode(PullDown);
00210     _button_B->mode(PullDown);
00211     _button_X->mode(PullDown);
00212     _button_Y->mode(PullDown);
00213     _button_back->mode(PullDown);
00214     _button_start->mode(PullDown);
00215     _button_L->mode(PullDown);
00216     _button_R->mode(PullDown);
00217     _button_joystick->mode(PullDown);
00218     // therefore setup rising edge interrupts
00219     _button_A->rise(callback(this,&Gamepad::a_isr));
00220     _button_B->rise(callback(this,&Gamepad::b_isr));
00221     _button_X->rise(callback(this,&Gamepad::x_isr));
00222     _button_Y->rise(callback(this,&Gamepad::y_isr));
00223     _button_L->rise(callback(this,&Gamepad::l_isr));
00224     _button_R->rise(callback(this,&Gamepad::r_isr));
00225     _button_start->rise(callback(this,&Gamepad::start_isr));
00226     _button_back->rise(callback(this,&Gamepad::back_isr));
00227     _button_joystick->rise(callback(this,&Gamepad::joy_isr));
00228     // therefore setup falling edge interrupts
00229     _button_A->fall(callback(this,&Gamepad::a_reset_isr));
00230     _button_B->fall(callback(this,&Gamepad::b_reset_isr));
00231     _button_X->fall(callback(this,&Gamepad::x_reset_isr));
00232     _button_Y->fall(callback(this,&Gamepad::y_reset_isr));
00233     _button_L->fall(callback(this,&Gamepad::l_reset_isr));
00234     _button_R->fall(callback(this,&Gamepad::r_reset_isr));
00235     _button_start->fall(callback(this,&Gamepad::start_reset_isr));
00236     _button_back->fall(callback(this,&Gamepad::back_reset_isr));
00237     _button_joystick->fall(callback(this,&Gamepad::joy_reset_isr));
00238 }
00239 
00240 // button interrupts ISRs
00241 // Each of these simply sets the appropriate event bit in the _event_state
00242 // variable
00243 void Gamepad::a_isr()
00244 {
00245     _event_state.set(A_PRESSED);
00246 }
00247 void Gamepad::b_isr()
00248 {
00249     _event_state.set(B_PRESSED);
00250 }
00251 void Gamepad::x_isr()
00252 {
00253     _event_state.set(X_PRESSED);
00254 }
00255 void Gamepad::y_isr()
00256 {
00257     _event_state.set(Y_PRESSED);
00258 }
00259 void Gamepad::l_isr()
00260 {
00261     _event_state.set(L_PRESSED);
00262 }
00263 void Gamepad::r_isr()
00264 {
00265     _event_state.set(R_PRESSED);
00266 }
00267 void Gamepad::back_isr()
00268 {
00269     _event_state.set(BACK_PRESSED);
00270 }
00271 void Gamepad::start_isr()
00272 {
00273     _event_state.set(START_PRESSED);
00274 }
00275 void Gamepad::joy_isr()
00276 {
00277     _event_state.set(JOY_PRESSED);
00278 }
00279 
00280 // button interrupts ISRs
00281 // Each of these simply resets the appropriate event bit in the _event_state
00282 // variable
00283 void Gamepad::a_reset_isr()
00284 {
00285     _event_state.reset(A_PRESSED);
00286 }
00287 void Gamepad::b_reset_isr()
00288 {
00289     _event_state.reset(B_PRESSED);
00290 }
00291 void Gamepad::x_reset_isr()
00292 {
00293     _event_state.reset(X_PRESSED);
00294 }
00295 void Gamepad::y_reset_isr()
00296 {
00297     _event_state.reset(Y_PRESSED);
00298 }
00299 void Gamepad::l_reset_isr()
00300 {
00301     _event_state.reset(L_PRESSED);
00302 }
00303 void Gamepad::r_reset_isr()
00304 {
00305     _event_state.reset(R_PRESSED);
00306 }
00307 void Gamepad::back_reset_isr()
00308 {
00309     _event_state.reset(BACK_PRESSED);
00310 }
00311 void Gamepad::start_reset_isr()
00312 {
00313     _event_state.reset(START_PRESSED);
00314 }
00315 void Gamepad::joy_reset_isr()
00316 {
00317     _event_state.reset(JOY_PRESSED);
00318 }
00319 
00320 // get raw joystick coordinate in range -1 to 1
00321 // Direction (x,y)
00322 // North     (0,1)
00323 // East      (1,0)
00324 // South     (0,-1)
00325 // West      (-1,0)
00326 Vector2D Gamepad::get_coord()
00327 {
00328     // read() returns value in range 0.0 to 1.0 so is scaled and centre value
00329     // substracted to get values in the range -1.0 to 1.0
00330     float x = 2.0f*( _horiz->read() - _x0 );
00331     float y = 2.0f*( _vert->read()  - _y0 );
00332 
00333     // Note: the x value here is inverted to ensure the positive x is to the
00334     // right. This is simply due to how the potentiometer on the joystick
00335     // I was using was connected up. It could have been corrected in hardware
00336     // by swapping the power supply pins. Instead it is done in software so may
00337     // need to be changed depending on your wiring setup
00338 
00339     Vector2D coord = {-x,y};
00340     return coord;
00341 }
00342 
00343 // This maps the raw x,y coord onto a circular grid.
00344 // See:  http://mathproofs.blogspot.co.uk/2005/07/mapping-square-to-circle.html
00345 Vector2D Gamepad::get_mapped_coord()
00346 {
00347     Vector2D coord = get_coord();
00348 
00349     // do the transformation
00350     float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f);
00351     float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f);
00352 
00353     Vector2D mapped_coord = {x,y};
00354     return mapped_coord;
00355 }
00356 
00357 // this function converts the mapped coordinates into polar form
00358 Polar Gamepad::get_polar()
00359 {
00360     // get the mapped coordinate
00361     Vector2D coord = get_mapped_coord();
00362 
00363     // at this point, 0 degrees (i.e. x-axis) will be defined to the East.
00364     // We want 0 degrees to correspond to North and increase clockwise to 359
00365     // like a compass heading, so we need to swap the axis and invert y
00366     float x = coord.y;
00367     float y = coord.x;
00368 
00369     float mag = sqrt(x*x+y*y);  // pythagoras
00370     float angle = RAD2DEG*atan2(y,x);
00371     // angle will be in range -180 to 180, so add 360 to negative angles to
00372     // move to 0 to 360 range
00373     if (angle < 0.0f) {
00374         angle+=360.0f;
00375     }
00376 
00377     // the noise on the ADC causes the values of x and y to fluctuate slightly
00378     // around the centred values. This causes the random angle values to get
00379     // calculated when the joystick is centred and untouched. This is also when
00380     // the magnitude is very small, so we can check for a small magnitude and then
00381     // set the angle to -1. This will inform us when the angle is invalid and the
00382     // joystick is centred
00383 
00384     if (mag < TOL) {
00385         mag = 0.0f;
00386         angle = -1.0f;
00387     }
00388 
00389     Polar p = {mag,angle};
00390     return p;
00391 }