No changes

Dependents:   el17rrrs el17rrrs

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Gamepad.cpp Source File

Gamepad.cpp

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