Omar Alebiary / Mbed 2 deprecated el17oa

Dependencies:   mbed FXOS8700CQQQ

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Gamepad.cpp Source File

Gamepad.cpp

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