Craig Evans / Mbed 2 deprecated ELEC2645_Gamepad2_Test

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(PTA2)),
00009     _led2(new PwmOut(PTC2)),
00010     _led3(new PwmOut(PTC3)),
00011     _led4(new PwmOut(PTA1)),
00012     _led5(new PwmOut(PTC10)),
00013     _led6(new PwmOut(PTC11)),
00014 
00015     _button_A(new InterruptIn(PTC7)),
00016     _button_B(new InterruptIn(PTC9)),
00017     _button_X(new InterruptIn(PTC5)),
00018     _button_Y(new InterruptIn(PTC0)),
00019     _button_start(new InterruptIn(PTC8)),
00020 
00021 
00022     _vert(new AnalogIn(PTB11)),
00023     _horiz(new AnalogIn(PTB10)),
00024 
00025     
00026     _pot1(new AnalogIn(PTB2)),
00027     _pot2(new AnalogIn(PTB3)),
00028 
00029     _speaker(new AnalogOut(DAC0_OUT)),
00030     _ticker(new Ticker()),
00031     _timeout(new Timeout()),
00032 
00033 
00034 
00035     _x0(0),
00036     _y0(0)
00037 {}
00038 
00039 
00040 ///////////////// public methods /////////////////
00041 
00042 void Gamepad::init()
00043 {
00044     leds_off();
00045 
00046     // read centred values of joystick
00047     _x0 = _horiz->read();
00048     _y0 = _vert->read();
00049 
00050     // Set all buttons to PullUp
00051     _button_A->mode(PullUp);
00052     _button_B->mode(PullUp);
00053     _button_X->mode(PullUp);
00054     _button_Y->mode(PullUp);
00055     _button_start->mode(PullUp);
00056 
00057     // Set up interrupts for the fall of buttons
00058     _button_A->fall(callback(this,&Gamepad::A_fall_interrupt));
00059     _button_B->fall(callback(this,&Gamepad::B_fall_interrupt));
00060     _button_X->fall(callback(this,&Gamepad::X_fall_interrupt));
00061     _button_Y->fall(callback(this,&Gamepad::Y_fall_interrupt));
00062     _button_start->fall(callback(this,&Gamepad::start_fall_interrupt));
00063 
00064     // initalise button flags
00065     reset_buttons();
00066 
00067     // Initalise speaker as low
00068     _speaker->write(0);    
00069 }
00070 
00071 void Gamepad::leds_off()
00072 {
00073     leds(0.0);
00074 }
00075 
00076 void Gamepad::leds_on()
00077 {
00078     leds(1.0);
00079 }
00080 
00081 void Gamepad::leds(float val) const
00082 {
00083     if (val < 0.0f) {
00084         val = 0.0f;
00085     }
00086     if (val > 1.0f) {
00087         val = 1.0f;
00088     }
00089 
00090     // leds are active-low, so subtract from 1.0
00091     // 0.0 corresponds to fully-off, 1.0 to fully-on
00092     val = 1.0f - val;
00093 
00094     _led1->write(val);
00095     _led2->write(val);
00096     _led3->write(val);
00097     _led4->write(val);
00098     _led5->write(val);
00099     _led6->write(val);
00100 }
00101 
00102 void Gamepad::led(int n,float val) const
00103 {
00104     // ensure they are within valid range
00105     if (val < 0.0f) {
00106         val = 0.0f;
00107     }
00108     if (val > 1.0f) {
00109         val = 1.0f;
00110     }
00111     
00112     switch (n) {
00113         
00114         // check for valid LED number and set value
00115 
00116         case 1:
00117             _led1->write(1.0f-val);   // active-low so subtract from 1
00118             break;
00119         case 2:
00120             _led2->write(1.0f-val);   // active-low so subtract from 1
00121             break;
00122         case 3:
00123             _led3->write(1.0f-val);   // active-low so subtract from 1
00124             break;
00125         case 4:
00126             _led4->write(1.0f-val);   // active-low so subtract from 1
00127             break;
00128         case 5:
00129             _led5->write(1.0f-val);   // active-low so subtract from 1
00130             break;
00131         case 6:
00132             _led6->write(1.0f-val);   // active-low so subtract from 1
00133             break;
00134 
00135     }
00136 }
00137 
00138 float Gamepad::read_pot1() const
00139 {
00140     return _pot1->read();
00141 }
00142 
00143 float Gamepad::read_pot2() const
00144 {
00145     return _pot2->read();
00146 }
00147 
00148 void Gamepad::tone(float frequency, float duration)
00149 {
00150     // Too low frequencys can damage the speaker
00151     if (frequency < 1000) {
00152         return;
00153     }
00154     // Generates a square wave by flipping the dac from 1 to 0
00155     // and vice versa at half the time period
00156     _ticker->attach(callback(this,&Gamepad::flip_DAC),(1.0f/frequency)*0.5f);
00157 
00158     // After the duration the ticker is detached.
00159     _timeout->attach(callback(this, &Gamepad::tone_off), duration );
00160 }
00161 
00162 
00163 
00164 // this method gets the magnitude of the joystick movement
00165 float Gamepad::get_mag()
00166 {
00167     Polar p = get_polar();
00168     return p.mag;
00169 }
00170 
00171 // this method gets the angle of joystick movement (0 to 360, 0 North)
00172 float Gamepad::get_angle()
00173 {
00174     Polar p = get_polar();
00175     return p.angle;
00176 }
00177 
00178 Direction Gamepad::get_direction()
00179 {
00180     float angle = get_angle();  // 0 to 360, -1 for centred
00181 
00182     Direction d;
00183     // partition 360 into segments and check which segment the angle is in
00184     if (angle < 0.0f) {
00185         d = CENTRE;   // check for -1.0 angle
00186     } else if (angle < 22.5f) {  // then keep going in 45 degree increments
00187         d = N;
00188     } else if (angle < 67.5f) {
00189         d = NE;
00190     } else if (angle < 112.5f) {
00191         d = E;
00192     } else if (angle < 157.5f) {
00193         d = SE;
00194     } else if (angle < 202.5f) {
00195         d = S;
00196     } else if (angle < 247.5f) {
00197         d = SW;
00198     } else if (angle < 292.5f) {
00199         d = W;
00200     } else if (angle < 337.5f) {
00201         d = NW;
00202     } else {
00203         d = N;
00204     }
00205 
00206     return d;
00207 }
00208 
00209 void Gamepad::reset_buttons() {
00210     A_fall = B_fall = X_fall = Y_fall = start_fall = false;
00211 }
00212 
00213 bool Gamepad::A_pressed() {
00214     if (A_fall) {
00215         A_fall = false;
00216         return true;
00217     } else {
00218         return false;
00219     }
00220 }
00221 
00222 bool Gamepad::B_pressed() {
00223     if (B_fall) {
00224         B_fall = false;
00225         return true;
00226     } else {
00227         return false;
00228     }
00229 }
00230 
00231 bool Gamepad::X_pressed() {
00232     if (X_fall) {
00233         X_fall = false;
00234         return true;
00235     } else {
00236         return false;
00237     }
00238 }
00239 
00240 bool Gamepad::Y_pressed() {
00241     if (Y_fall) {
00242         Y_fall = false;
00243         return true;
00244     } else {
00245         return false;
00246     }
00247 }
00248 
00249 bool Gamepad::start_pressed() {
00250     if (start_fall) {
00251         start_fall = false;
00252         return true;
00253     } else {
00254         return false;
00255     }
00256 }
00257 
00258 bool Gamepad::A_held() {
00259     // Buttons are configured as PullUp hence the not
00260     return !_button_A->read();
00261 }
00262 
00263 bool Gamepad::B_held() {
00264     return !_button_B->read();
00265 }
00266 
00267 bool Gamepad::X_held() {
00268     return !_button_X->read();
00269 }
00270 
00271 bool Gamepad::Y_held() {
00272     return !_button_Y->read();
00273 }
00274 
00275 bool Gamepad::start_held() {
00276     return !_button_start->read();
00277 }
00278 
00279 ///////////////////// private methods ////////////////////////
00280 
00281 void Gamepad::tone_off()
00282 {
00283    _ticker->detach();
00284 }
00285 
00286 void Gamepad::flip_DAC()
00287 {
00288     if (_speaker->read() == 1) {
00289         _speaker->write(0);
00290     } else {
00291         _speaker->write(1);
00292     }
00293 }
00294 
00295 
00296 
00297 // get raw joystick coordinate in range -1 to 1
00298 // Direction (x,y)
00299 // North     (0,1)
00300 // East      (1,0)
00301 // South     (0,-1)
00302 // West      (-1,0)
00303 Vector2D Gamepad::get_coord()
00304 {
00305     // read() returns value in range 0.0 to 1.0 so is scaled and centre value
00306     // substracted to get values in the range -1.0 to 1.0
00307     float x = 2.0f*( _horiz->read() - _x0 );
00308     float y = 2.0f*( _vert->read()  - _y0 );
00309 
00310     // Note: the x value here is inverted to ensure the positive x is to the
00311     // right. This is simply due to how the potentiometer on the joystick
00312     // I was using was connected up. It could have been corrected in hardware
00313     // by swapping the power supply pins. Instead it is done in software so may
00314     // need to be changed depending on your wiring setup
00315 
00316     Vector2D coord = {-x,y};
00317     return coord;
00318 }
00319 
00320 // This maps the raw x,y coord onto a circular grid.
00321 // See:  http://mathproofs.blogspot.co.uk/2005/07/mapping-square-to-circle.html
00322 Vector2D Gamepad::get_mapped_coord()
00323 {
00324     Vector2D coord = get_coord();
00325 
00326     // do the transformation
00327     float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f);
00328     float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f);
00329 
00330     Vector2D mapped_coord = {-x,-y};
00331     return mapped_coord;
00332 }
00333 
00334 // this function converts the mapped coordinates into polar form
00335 Polar Gamepad::get_polar()
00336 {
00337     // get the mapped coordinate
00338     Vector2D coord = get_mapped_coord();
00339 
00340     // at this point, 0 degrees (i.e. x-axis) will be defined to the East.
00341     // We want 0 degrees to correspond to North and increase clockwise to 359
00342     // like a compass heading, so we need to swap the axis and invert y
00343     float x = coord.y;
00344     float y = coord.x;
00345 
00346     float mag = sqrt(x*x+y*y);  // pythagoras
00347     float angle = RAD2DEG*atan2(y,x);
00348     // angle will be in range -180 to 180, so add 360 to negative angles to
00349     // move to 0 to 360 range
00350     if (angle < 0.0f) {
00351         angle+=360.0f;
00352     }
00353 
00354     // the noise on the ADC causes the values of x and y to fluctuate slightly
00355     // around the centred values. This causes the random angle values to get
00356     // calculated when the joystick is centred and untouched. This is also when
00357     // the magnitude is very small, so we can check for a small magnitude and then
00358     // set the angle to -1. This will inform us when the angle is invalid and the
00359     // joystick is centred
00360 
00361     if (mag < TOL) {
00362         mag = 0.0f;
00363         angle = -1.0f;
00364     }
00365 
00366     Polar p = {mag,angle};
00367     return p;
00368 }
00369 
00370 // ISRs for buttons
00371 void Gamepad::A_fall_interrupt() {
00372     A_fall = true;
00373 }
00374 void Gamepad::B_fall_interrupt() {
00375     B_fall = true;
00376 }
00377 void Gamepad::X_fall_interrupt() {
00378     X_fall = true;
00379 }
00380 void Gamepad::Y_fall_interrupt() {
00381     Y_fall = true;
00382 }
00383 void Gamepad::start_fall_interrupt() {
00384     start_fall = true;
00385 }