No changes
Embed:
(wiki syntax)
Show/hide line numbers
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 }
Generated on Sat Jul 16 2022 02:47:01 by
1.7.2