ELEC2645 (2019/20) / Mbed 2 deprecated ELEC2645_Project_el18nw

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