Max Houghton / Gamepad

Fork of Gamepad by Craig Evans

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 }
00229 
00230 // button interrupts ISRs
00231 // Each of these simply sets the appropriate event bit in the _event_state
00232 // variable
00233 void Gamepad::a_isr()
00234 {
00235     _event_state.set(A_PRESSED);
00236 }
00237 void Gamepad::b_isr()
00238 {
00239     _event_state.set(B_PRESSED);
00240 }
00241 void Gamepad::x_isr()
00242 {
00243     _event_state.set(X_PRESSED);
00244 }
00245 void Gamepad::y_isr()
00246 {
00247     _event_state.set(Y_PRESSED);
00248 }
00249 void Gamepad::l_isr()
00250 {
00251     _event_state.set(L_PRESSED);
00252 }
00253 void Gamepad::r_isr()
00254 {
00255     _event_state.set(R_PRESSED);
00256 }
00257 void Gamepad::back_isr()
00258 {
00259     _event_state.set(BACK_PRESSED);
00260 }
00261 void Gamepad::start_isr()
00262 {
00263     _event_state.set(START_PRESSED);
00264 }
00265 void Gamepad::joy_isr()
00266 {
00267     _event_state.set(JOY_PRESSED);
00268 }
00269 
00270 // get raw joystick coordinate in range -1 to 1
00271 // Direction (x,y)
00272 // North     (0,1)
00273 // East      (1,0)
00274 // South     (0,-1)
00275 // West      (-1,0)
00276 Vector2D Gamepad::get_coord()
00277 {
00278     // read() returns value in range 0.0 to 1.0 so is scaled and centre value
00279     // substracted to get values in the range -1.0 to 1.0
00280     float x = 2.0f*( _horiz->read() - _x0 );
00281     float y = 2.0f*( _vert->read()  - _y0 );
00282 
00283     // Note: the x value here is inverted to ensure the positive x is to the
00284     // right. This is simply due to how the potentiometer on the joystick
00285     // I was using was connected up. It could have been corrected in hardware
00286     // by swapping the power supply pins. Instead it is done in software so may
00287     // need to be changed depending on your wiring setup
00288 
00289     Vector2D coord = {-x,y};
00290     return coord;
00291 }
00292 
00293 // This maps the raw x,y coord onto a circular grid.
00294 // See:  http://mathproofs.blogspot.co.uk/2005/07/mapping-square-to-circle.html
00295 Vector2D Gamepad::get_mapped_coord()
00296 {
00297     Vector2D coord = get_coord();
00298 
00299     // do the transformation
00300     float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f);
00301     float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f);
00302 
00303     Vector2D mapped_coord = {x,y};
00304     return mapped_coord;
00305 }
00306 
00307 // this function converts the mapped coordinates into polar form
00308 Polar Gamepad::get_polar()
00309 {
00310     // get the mapped coordinate
00311     Vector2D coord = get_mapped_coord();
00312 
00313     // at this point, 0 degrees (i.e. x-axis) will be defined to the East.
00314     // We want 0 degrees to correspond to North and increase clockwise to 359
00315     // like a compass heading, so we need to swap the axis and invert y
00316     float x = coord.y;
00317     float y = coord.x;
00318 
00319     float mag = sqrt(x*x+y*y);  // pythagoras
00320     float angle = RAD2DEG*atan2(y,x);
00321     // angle will be in range -180 to 180, so add 360 to negative angles to
00322     // move to 0 to 360 range
00323     if (angle < 0.0f) {
00324         angle+=360.0f;
00325     }
00326 
00327     // the noise on the ADC causes the values of x and y to fluctuate slightly
00328     // around the centred values. This causes the random angle values to get
00329     // calculated when the joystick is centred and untouched. This is also when
00330     // the magnitude is very small, so we can check for a small magnitude and then
00331     // set the angle to -1. This will inform us when the angle is invalid and the
00332     // joystick is centred
00333 
00334     if (mag < TOL) {
00335         mag = 0.0f;
00336         angle = -1.0f;
00337     }
00338 
00339     Polar p = {mag,angle};
00340     return p;
00341 }