R
Embed:
(wiki syntax)
Show/hide line numbers
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 }
Generated on Fri Jul 15 2022 06:35:54 by
1.7.2