ELEC2645 (2019/20) / Mbed 2 deprecated ELEC2645_Project_el18lg

Dependencies:   mbed

Committer:
el18lg
Date:
Sat May 23 17:21:24 2020 +0000
Revision:
1:bdafa20e71a0
Started my map, making my way onto my snake programme;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
el18lg 1:bdafa20e71a0 1 #include "Gamepad.h"
el18lg 1:bdafa20e71a0 2
el18lg 1:bdafa20e71a0 3 #include "mbed.h"
el18lg 1:bdafa20e71a0 4
el18lg 1:bdafa20e71a0 5 //////////// constructor/destructor ////////////
el18lg 1:bdafa20e71a0 6 Gamepad::Gamepad()
el18lg 1:bdafa20e71a0 7 :
el18lg 1:bdafa20e71a0 8 _led1(new PwmOut(PTA2)),
el18lg 1:bdafa20e71a0 9 _led2(new PwmOut(PTC2)),
el18lg 1:bdafa20e71a0 10 _led3(new PwmOut(PTC3)),
el18lg 1:bdafa20e71a0 11 _led4(new PwmOut(PTA1)),
el18lg 1:bdafa20e71a0 12 _led5(new PwmOut(PTC10)),
el18lg 1:bdafa20e71a0 13 _led6(new PwmOut(PTC11)),
el18lg 1:bdafa20e71a0 14
el18lg 1:bdafa20e71a0 15 _button_A(new InterruptIn(PTC7)),
el18lg 1:bdafa20e71a0 16 _button_B(new InterruptIn(PTC9)),
el18lg 1:bdafa20e71a0 17 _button_X(new InterruptIn(PTC5)),
el18lg 1:bdafa20e71a0 18 _button_Y(new InterruptIn(PTC0)),
el18lg 1:bdafa20e71a0 19 _button_start(new InterruptIn(PTC8)),
el18lg 1:bdafa20e71a0 20
el18lg 1:bdafa20e71a0 21 _vert(new AnalogIn(PTB11)),
el18lg 1:bdafa20e71a0 22 _horiz(new AnalogIn(PTB10)),
el18lg 1:bdafa20e71a0 23
el18lg 1:bdafa20e71a0 24 _pot1(new AnalogIn(PTB2)),
el18lg 1:bdafa20e71a0 25 _pot2(new AnalogIn(PTB3)),
el18lg 1:bdafa20e71a0 26
el18lg 1:bdafa20e71a0 27 dac(new AnalogOut(DAC0_OUT)),
el18lg 1:bdafa20e71a0 28 ticker(new Ticker),
el18lg 1:bdafa20e71a0 29 timeout(new Timeout),
el18lg 1:bdafa20e71a0 30 note_timeout(new Timeout),
el18lg 1:bdafa20e71a0 31
el18lg 1:bdafa20e71a0 32 _x0(0),
el18lg 1:bdafa20e71a0 33 _y0(0)
el18lg 1:bdafa20e71a0 34 {}
el18lg 1:bdafa20e71a0 35
el18lg 1:bdafa20e71a0 36
el18lg 1:bdafa20e71a0 37 ///////////////// public methods /////////////////
el18lg 1:bdafa20e71a0 38
el18lg 1:bdafa20e71a0 39 void Gamepad::init()
el18lg 1:bdafa20e71a0 40 {
el18lg 1:bdafa20e71a0 41 leds_off();
el18lg 1:bdafa20e71a0 42
el18lg 1:bdafa20e71a0 43 // read centred values of joystick
el18lg 1:bdafa20e71a0 44 _x0 = _horiz->read();
el18lg 1:bdafa20e71a0 45 _y0 = _vert->read();
el18lg 1:bdafa20e71a0 46
el18lg 1:bdafa20e71a0 47 // Set all buttons to PullUp
el18lg 1:bdafa20e71a0 48 _button_A->mode(PullUp);
el18lg 1:bdafa20e71a0 49 _button_B->mode(PullUp);
el18lg 1:bdafa20e71a0 50 _button_X->mode(PullUp);
el18lg 1:bdafa20e71a0 51 _button_Y->mode(PullUp);
el18lg 1:bdafa20e71a0 52 _button_start->mode(PullUp);
el18lg 1:bdafa20e71a0 53
el18lg 1:bdafa20e71a0 54 // Set up interrupts for the fall of buttons
el18lg 1:bdafa20e71a0 55 _button_A->fall(callback(this,&Gamepad::A_fall_interrupt));
el18lg 1:bdafa20e71a0 56 _button_B->fall(callback(this,&Gamepad::B_fall_interrupt));
el18lg 1:bdafa20e71a0 57 _button_X->fall(callback(this,&Gamepad::X_fall_interrupt));
el18lg 1:bdafa20e71a0 58 _button_Y->fall(callback(this,&Gamepad::Y_fall_interrupt));
el18lg 1:bdafa20e71a0 59 _button_start->fall(callback(this,&Gamepad::start_fall_interrupt));
el18lg 1:bdafa20e71a0 60
el18lg 1:bdafa20e71a0 61 // initalise button flags
el18lg 1:bdafa20e71a0 62 reset_buttons();
el18lg 1:bdafa20e71a0 63
el18lg 1:bdafa20e71a0 64 // number of samples
el18lg 1:bdafa20e71a0 65 _n = 16;
el18lg 1:bdafa20e71a0 66 _sample_array = new float[_n];
el18lg 1:bdafa20e71a0 67
el18lg 1:bdafa20e71a0 68 // create sample array for one period between 0.0 and 1.0
el18lg 1:bdafa20e71a0 69 for (int i = 0; i < _n ; i++) {
el18lg 1:bdafa20e71a0 70 _sample_array[i] = 0.5f + 0.5f*sin(i*2*PI/_n);
el18lg 1:bdafa20e71a0 71 //printf("y[%i] = %f\n",i,_sample_array[i]);
el18lg 1:bdafa20e71a0 72 }
el18lg 1:bdafa20e71a0 73
el18lg 1:bdafa20e71a0 74 }
el18lg 1:bdafa20e71a0 75
el18lg 1:bdafa20e71a0 76 void Gamepad::leds_off()
el18lg 1:bdafa20e71a0 77 {
el18lg 1:bdafa20e71a0 78 leds(0.0);
el18lg 1:bdafa20e71a0 79 }
el18lg 1:bdafa20e71a0 80
el18lg 1:bdafa20e71a0 81 void Gamepad::leds_on()
el18lg 1:bdafa20e71a0 82 {
el18lg 1:bdafa20e71a0 83 leds(1.0);
el18lg 1:bdafa20e71a0 84 }
el18lg 1:bdafa20e71a0 85
el18lg 1:bdafa20e71a0 86 void Gamepad::leds(float val) const
el18lg 1:bdafa20e71a0 87 {
el18lg 1:bdafa20e71a0 88 if (val < 0.0f) {
el18lg 1:bdafa20e71a0 89 val = 0.0f;
el18lg 1:bdafa20e71a0 90 }
el18lg 1:bdafa20e71a0 91 if (val > 1.0f) {
el18lg 1:bdafa20e71a0 92 val = 1.0f;
el18lg 1:bdafa20e71a0 93 }
el18lg 1:bdafa20e71a0 94
el18lg 1:bdafa20e71a0 95 // leds are active-low, so subtract from 1.0
el18lg 1:bdafa20e71a0 96 // 0.0 corresponds to fully-off, 1.0 to fully-on
el18lg 1:bdafa20e71a0 97 val = 1.0f - val;
el18lg 1:bdafa20e71a0 98
el18lg 1:bdafa20e71a0 99 _led1->write(val);
el18lg 1:bdafa20e71a0 100 _led2->write(val);
el18lg 1:bdafa20e71a0 101 _led3->write(val);
el18lg 1:bdafa20e71a0 102 _led4->write(val);
el18lg 1:bdafa20e71a0 103 _led5->write(val);
el18lg 1:bdafa20e71a0 104 _led6->write(val);
el18lg 1:bdafa20e71a0 105 }
el18lg 1:bdafa20e71a0 106
el18lg 1:bdafa20e71a0 107 void Gamepad::led(int n,float val) const
el18lg 1:bdafa20e71a0 108 {
el18lg 1:bdafa20e71a0 109 // ensure they are within valid range
el18lg 1:bdafa20e71a0 110 if (val < 0.0f) {
el18lg 1:bdafa20e71a0 111 val = 0.0f;
el18lg 1:bdafa20e71a0 112 }
el18lg 1:bdafa20e71a0 113 if (val > 1.0f) {
el18lg 1:bdafa20e71a0 114 val = 1.0f;
el18lg 1:bdafa20e71a0 115 }
el18lg 1:bdafa20e71a0 116
el18lg 1:bdafa20e71a0 117 switch (n) {
el18lg 1:bdafa20e71a0 118
el18lg 1:bdafa20e71a0 119 // check for valid LED number and set value
el18lg 1:bdafa20e71a0 120
el18lg 1:bdafa20e71a0 121 case 1:
el18lg 1:bdafa20e71a0 122 _led1->write(1.0f-val); // active-low so subtract from 1
el18lg 1:bdafa20e71a0 123 break;
el18lg 1:bdafa20e71a0 124 case 2:
el18lg 1:bdafa20e71a0 125 _led2->write(1.0f-val); // active-low so subtract from 1
el18lg 1:bdafa20e71a0 126 break;
el18lg 1:bdafa20e71a0 127 case 3:
el18lg 1:bdafa20e71a0 128 _led3->write(1.0f-val); // active-low so subtract from 1
el18lg 1:bdafa20e71a0 129 break;
el18lg 1:bdafa20e71a0 130 case 4:
el18lg 1:bdafa20e71a0 131 _led4->write(1.0f-val); // active-low so subtract from 1
el18lg 1:bdafa20e71a0 132 break;
el18lg 1:bdafa20e71a0 133 case 5:
el18lg 1:bdafa20e71a0 134 _led5->write(1.0f-val); // active-low so subtract from 1
el18lg 1:bdafa20e71a0 135 break;
el18lg 1:bdafa20e71a0 136 case 6:
el18lg 1:bdafa20e71a0 137 _led6->write(1.0f-val); // active-low so subtract from 1
el18lg 1:bdafa20e71a0 138 break;
el18lg 1:bdafa20e71a0 139
el18lg 1:bdafa20e71a0 140 }
el18lg 1:bdafa20e71a0 141 }
el18lg 1:bdafa20e71a0 142
el18lg 1:bdafa20e71a0 143 float Gamepad::read_pot1() const
el18lg 1:bdafa20e71a0 144 {
el18lg 1:bdafa20e71a0 145 return _pot1->read();
el18lg 1:bdafa20e71a0 146 }
el18lg 1:bdafa20e71a0 147
el18lg 1:bdafa20e71a0 148 float Gamepad::read_pot2() const
el18lg 1:bdafa20e71a0 149 {
el18lg 1:bdafa20e71a0 150 return _pot2->read();
el18lg 1:bdafa20e71a0 151 }
el18lg 1:bdafa20e71a0 152
el18lg 1:bdafa20e71a0 153
el18lg 1:bdafa20e71a0 154 // this method gets the magnitude of the joystick movement
el18lg 1:bdafa20e71a0 155 float Gamepad::get_mag()
el18lg 1:bdafa20e71a0 156 {
el18lg 1:bdafa20e71a0 157 Polar p = get_polar();
el18lg 1:bdafa20e71a0 158 return p.mag;
el18lg 1:bdafa20e71a0 159 }
el18lg 1:bdafa20e71a0 160
el18lg 1:bdafa20e71a0 161 // this method gets the angle of joystick movement (0 to 360, 0 North)
el18lg 1:bdafa20e71a0 162 float Gamepad::get_angle()
el18lg 1:bdafa20e71a0 163 {
el18lg 1:bdafa20e71a0 164 Polar p = get_polar();
el18lg 1:bdafa20e71a0 165 return p.angle;
el18lg 1:bdafa20e71a0 166 }
el18lg 1:bdafa20e71a0 167
el18lg 1:bdafa20e71a0 168 Direction Gamepad::get_direction()
el18lg 1:bdafa20e71a0 169 {
el18lg 1:bdafa20e71a0 170 float angle = get_angle(); // 0 to 360, -1 for centred
el18lg 1:bdafa20e71a0 171
el18lg 1:bdafa20e71a0 172 Direction d;
el18lg 1:bdafa20e71a0 173 // partition 360 into segments and check which segment the angle is in
el18lg 1:bdafa20e71a0 174 if (angle < 0.0f) {
el18lg 1:bdafa20e71a0 175 d = CENTRE; // check for -1.0 angle
el18lg 1:bdafa20e71a0 176 } else if (angle < 22.5f) { // then keep going in 45 degree increments
el18lg 1:bdafa20e71a0 177 d = N;
el18lg 1:bdafa20e71a0 178 } else if (angle < 67.5f) {
el18lg 1:bdafa20e71a0 179 d = NE;
el18lg 1:bdafa20e71a0 180 } else if (angle < 112.5f) {
el18lg 1:bdafa20e71a0 181 d = E;
el18lg 1:bdafa20e71a0 182 } else if (angle < 157.5f) {
el18lg 1:bdafa20e71a0 183 d = SE;
el18lg 1:bdafa20e71a0 184 } else if (angle < 202.5f) {
el18lg 1:bdafa20e71a0 185 d = S;
el18lg 1:bdafa20e71a0 186 } else if (angle < 247.5f) {
el18lg 1:bdafa20e71a0 187 d = SW;
el18lg 1:bdafa20e71a0 188 } else if (angle < 292.5f) {
el18lg 1:bdafa20e71a0 189 d = W;
el18lg 1:bdafa20e71a0 190 } else if (angle < 337.5f) {
el18lg 1:bdafa20e71a0 191 d = NW;
el18lg 1:bdafa20e71a0 192 } else {
el18lg 1:bdafa20e71a0 193 d = N;
el18lg 1:bdafa20e71a0 194 }
el18lg 1:bdafa20e71a0 195
el18lg 1:bdafa20e71a0 196 return d;
el18lg 1:bdafa20e71a0 197 }
el18lg 1:bdafa20e71a0 198
el18lg 1:bdafa20e71a0 199 void Gamepad::reset_buttons()
el18lg 1:bdafa20e71a0 200 {
el18lg 1:bdafa20e71a0 201 A_fall = B_fall = X_fall = Y_fall = start_fall = false;
el18lg 1:bdafa20e71a0 202 }
el18lg 1:bdafa20e71a0 203
el18lg 1:bdafa20e71a0 204 bool Gamepad::A_pressed()
el18lg 1:bdafa20e71a0 205 {
el18lg 1:bdafa20e71a0 206 if (A_fall) {
el18lg 1:bdafa20e71a0 207 A_fall = false;
el18lg 1:bdafa20e71a0 208 return true;
el18lg 1:bdafa20e71a0 209 } else {
el18lg 1:bdafa20e71a0 210 return false;
el18lg 1:bdafa20e71a0 211 }
el18lg 1:bdafa20e71a0 212 }
el18lg 1:bdafa20e71a0 213
el18lg 1:bdafa20e71a0 214 bool Gamepad::B_pressed()
el18lg 1:bdafa20e71a0 215 {
el18lg 1:bdafa20e71a0 216 if (B_fall) {
el18lg 1:bdafa20e71a0 217 B_fall = false;
el18lg 1:bdafa20e71a0 218 return true;
el18lg 1:bdafa20e71a0 219 } else {
el18lg 1:bdafa20e71a0 220 return false;
el18lg 1:bdafa20e71a0 221 }
el18lg 1:bdafa20e71a0 222 }
el18lg 1:bdafa20e71a0 223
el18lg 1:bdafa20e71a0 224 bool Gamepad::X_pressed()
el18lg 1:bdafa20e71a0 225 {
el18lg 1:bdafa20e71a0 226 if (X_fall) {
el18lg 1:bdafa20e71a0 227 X_fall = false;
el18lg 1:bdafa20e71a0 228 return true;
el18lg 1:bdafa20e71a0 229 } else {
el18lg 1:bdafa20e71a0 230 return false;
el18lg 1:bdafa20e71a0 231 }
el18lg 1:bdafa20e71a0 232 }
el18lg 1:bdafa20e71a0 233
el18lg 1:bdafa20e71a0 234 bool Gamepad::Y_pressed()
el18lg 1:bdafa20e71a0 235 {
el18lg 1:bdafa20e71a0 236 if (Y_fall) {
el18lg 1:bdafa20e71a0 237 Y_fall = false;
el18lg 1:bdafa20e71a0 238 return true;
el18lg 1:bdafa20e71a0 239 } else {
el18lg 1:bdafa20e71a0 240 return false;
el18lg 1:bdafa20e71a0 241 }
el18lg 1:bdafa20e71a0 242 }
el18lg 1:bdafa20e71a0 243
el18lg 1:bdafa20e71a0 244 bool Gamepad::start_pressed()
el18lg 1:bdafa20e71a0 245 {
el18lg 1:bdafa20e71a0 246 if (start_fall) {
el18lg 1:bdafa20e71a0 247 start_fall = false;
el18lg 1:bdafa20e71a0 248 return true;
el18lg 1:bdafa20e71a0 249 } else {
el18lg 1:bdafa20e71a0 250 return false;
el18lg 1:bdafa20e71a0 251 }
el18lg 1:bdafa20e71a0 252 }
el18lg 1:bdafa20e71a0 253
el18lg 1:bdafa20e71a0 254 bool Gamepad::A_held()
el18lg 1:bdafa20e71a0 255 {
el18lg 1:bdafa20e71a0 256 // Buttons are configured as PullUp hence the not
el18lg 1:bdafa20e71a0 257 return !_button_A->read();
el18lg 1:bdafa20e71a0 258 }
el18lg 1:bdafa20e71a0 259
el18lg 1:bdafa20e71a0 260 bool Gamepad::B_held()
el18lg 1:bdafa20e71a0 261 {
el18lg 1:bdafa20e71a0 262 return !_button_B->read();
el18lg 1:bdafa20e71a0 263 }
el18lg 1:bdafa20e71a0 264
el18lg 1:bdafa20e71a0 265 bool Gamepad::X_held()
el18lg 1:bdafa20e71a0 266 {
el18lg 1:bdafa20e71a0 267 return !_button_X->read();
el18lg 1:bdafa20e71a0 268 }
el18lg 1:bdafa20e71a0 269
el18lg 1:bdafa20e71a0 270 bool Gamepad::Y_held()
el18lg 1:bdafa20e71a0 271 {
el18lg 1:bdafa20e71a0 272 return !_button_Y->read();
el18lg 1:bdafa20e71a0 273 }
el18lg 1:bdafa20e71a0 274
el18lg 1:bdafa20e71a0 275 bool Gamepad::start_held()
el18lg 1:bdafa20e71a0 276 {
el18lg 1:bdafa20e71a0 277 return !_button_start->read();
el18lg 1:bdafa20e71a0 278 }
el18lg 1:bdafa20e71a0 279
el18lg 1:bdafa20e71a0 280 ///////////////////// private methods ////////////////////////
el18lg 1:bdafa20e71a0 281
el18lg 1:bdafa20e71a0 282 // get raw joystick coordinate in range -1 to 1
el18lg 1:bdafa20e71a0 283 // Direction (x,y)
el18lg 1:bdafa20e71a0 284 // North (0,1)
el18lg 1:bdafa20e71a0 285 // East (1,0)
el18lg 1:bdafa20e71a0 286 // South (0,-1)
el18lg 1:bdafa20e71a0 287 // West (-1,0)
el18lg 1:bdafa20e71a0 288 Vector2D Gamepad::get_coord()
el18lg 1:bdafa20e71a0 289 {
el18lg 1:bdafa20e71a0 290 // read() returns value in range 0.0 to 1.0 so is scaled and centre value
el18lg 1:bdafa20e71a0 291 // substracted to get values in the range -1.0 to 1.0
el18lg 1:bdafa20e71a0 292 float x = 2.0f*( _horiz->read() - _x0 );
el18lg 1:bdafa20e71a0 293 float y = 2.0f*( _vert->read() - _y0 );
el18lg 1:bdafa20e71a0 294
el18lg 1:bdafa20e71a0 295 // Note: the y value here is inverted to ensure the positive y is up
el18lg 1:bdafa20e71a0 296
el18lg 1:bdafa20e71a0 297 Vector2D coord = {x,-y};
el18lg 1:bdafa20e71a0 298 return coord;
el18lg 1:bdafa20e71a0 299 }
el18lg 1:bdafa20e71a0 300
el18lg 1:bdafa20e71a0 301 // This maps the raw x,y coord onto a circular grid.
el18lg 1:bdafa20e71a0 302 // See: http://mathproofs.blogspot.co.uk/2005/07/mapping-square-to-circle.html
el18lg 1:bdafa20e71a0 303 Vector2D Gamepad::get_mapped_coord()
el18lg 1:bdafa20e71a0 304 {
el18lg 1:bdafa20e71a0 305 Vector2D coord = get_coord();
el18lg 1:bdafa20e71a0 306
el18lg 1:bdafa20e71a0 307 // do the transformation
el18lg 1:bdafa20e71a0 308 float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f);
el18lg 1:bdafa20e71a0 309 float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f);
el18lg 1:bdafa20e71a0 310
el18lg 1:bdafa20e71a0 311 Vector2D mapped_coord = {x,y};
el18lg 1:bdafa20e71a0 312 return mapped_coord;
el18lg 1:bdafa20e71a0 313 }
el18lg 1:bdafa20e71a0 314
el18lg 1:bdafa20e71a0 315 // this function converts the mapped coordinates into polar form
el18lg 1:bdafa20e71a0 316 Polar Gamepad::get_polar()
el18lg 1:bdafa20e71a0 317 {
el18lg 1:bdafa20e71a0 318 // get the mapped coordinate
el18lg 1:bdafa20e71a0 319 Vector2D coord = get_mapped_coord();
el18lg 1:bdafa20e71a0 320
el18lg 1:bdafa20e71a0 321 // at this point, 0 degrees (i.e. x-axis) will be defined to the East.
el18lg 1:bdafa20e71a0 322 // We want 0 degrees to correspond to North and increase clockwise to 359
el18lg 1:bdafa20e71a0 323 // like a compass heading, so we need to swap the axis and invert y
el18lg 1:bdafa20e71a0 324 float x = coord.y;
el18lg 1:bdafa20e71a0 325 float y = coord.x;
el18lg 1:bdafa20e71a0 326
el18lg 1:bdafa20e71a0 327 float mag = sqrt(x*x+y*y); // pythagoras
el18lg 1:bdafa20e71a0 328 float angle = RAD2DEG*atan2(y,x);
el18lg 1:bdafa20e71a0 329 // angle will be in range -180 to 180, so add 360 to negative angles to
el18lg 1:bdafa20e71a0 330 // move to 0 to 360 range
el18lg 1:bdafa20e71a0 331 if (angle < 0.0f) {
el18lg 1:bdafa20e71a0 332 angle+=360.0f;
el18lg 1:bdafa20e71a0 333 }
el18lg 1:bdafa20e71a0 334
el18lg 1:bdafa20e71a0 335 // the noise on the ADC causes the values of x and y to fluctuate slightly
el18lg 1:bdafa20e71a0 336 // around the centred values. This causes the random angle values to get
el18lg 1:bdafa20e71a0 337 // calculated when the joystick is centred and untouched. This is also when
el18lg 1:bdafa20e71a0 338 // the magnitude is very small, so we can check for a small magnitude and then
el18lg 1:bdafa20e71a0 339 // set the angle to -1. This will inform us when the angle is invalid and the
el18lg 1:bdafa20e71a0 340 // joystick is centred
el18lg 1:bdafa20e71a0 341
el18lg 1:bdafa20e71a0 342 if (mag < TOL) {
el18lg 1:bdafa20e71a0 343 mag = 0.0f;
el18lg 1:bdafa20e71a0 344 angle = -1.0f;
el18lg 1:bdafa20e71a0 345 }
el18lg 1:bdafa20e71a0 346
el18lg 1:bdafa20e71a0 347 Polar p = {mag,angle};
el18lg 1:bdafa20e71a0 348 return p;
el18lg 1:bdafa20e71a0 349 }
el18lg 1:bdafa20e71a0 350
el18lg 1:bdafa20e71a0 351 // ISRs for buttons
el18lg 1:bdafa20e71a0 352 void Gamepad::A_fall_interrupt()
el18lg 1:bdafa20e71a0 353 {
el18lg 1:bdafa20e71a0 354 A_fall = true;
el18lg 1:bdafa20e71a0 355 }
el18lg 1:bdafa20e71a0 356 void Gamepad::B_fall_interrupt()
el18lg 1:bdafa20e71a0 357 {
el18lg 1:bdafa20e71a0 358 B_fall = true;
el18lg 1:bdafa20e71a0 359 }
el18lg 1:bdafa20e71a0 360 void Gamepad::X_fall_interrupt()
el18lg 1:bdafa20e71a0 361 {
el18lg 1:bdafa20e71a0 362 X_fall = true;
el18lg 1:bdafa20e71a0 363 }
el18lg 1:bdafa20e71a0 364 void Gamepad::Y_fall_interrupt()
el18lg 1:bdafa20e71a0 365 {
el18lg 1:bdafa20e71a0 366 Y_fall = true;
el18lg 1:bdafa20e71a0 367 }
el18lg 1:bdafa20e71a0 368 void Gamepad::start_fall_interrupt()
el18lg 1:bdafa20e71a0 369 {
el18lg 1:bdafa20e71a0 370 start_fall = true;
el18lg 1:bdafa20e71a0 371 }
el18lg 1:bdafa20e71a0 372
el18lg 1:bdafa20e71a0 373 void Gamepad::set_bpm(float bpm)
el18lg 1:bdafa20e71a0 374 {
el18lg 1:bdafa20e71a0 375 _bpm = bpm;
el18lg 1:bdafa20e71a0 376 }
el18lg 1:bdafa20e71a0 377
el18lg 1:bdafa20e71a0 378 void Gamepad::tone(float frequency,float duration)
el18lg 1:bdafa20e71a0 379 {
el18lg 1:bdafa20e71a0 380 // calculate time step between samples
el18lg 1:bdafa20e71a0 381 float dt = 1.0f/(frequency*_n);
el18lg 1:bdafa20e71a0 382 // start from beginning of LUT
el18lg 1:bdafa20e71a0 383 _sample = 0;
el18lg 1:bdafa20e71a0 384
el18lg 1:bdafa20e71a0 385 // setup ticker and timeout to stop ticker
el18lg 1:bdafa20e71a0 386
el18lg 1:bdafa20e71a0 387 // the ticker repeats every dt to plat each sample in turn
el18lg 1:bdafa20e71a0 388 ticker->attach(callback(this, &Gamepad::ticker_isr), dt);
el18lg 1:bdafa20e71a0 389 // the timeout stops the ticker after the required duration
el18lg 1:bdafa20e71a0 390 timeout->attach(callback(this, &Gamepad::timeout_isr), duration );
el18lg 1:bdafa20e71a0 391 }
el18lg 1:bdafa20e71a0 392
el18lg 1:bdafa20e71a0 393 void Gamepad::play_melody(int length,const int *notes,const int *durations,float bpm,bool repeat)
el18lg 1:bdafa20e71a0 394 {
el18lg 1:bdafa20e71a0 395 // copy arguments to member variables
el18lg 1:bdafa20e71a0 396 _bpm = bpm;
el18lg 1:bdafa20e71a0 397 _notes = notes; // pointer for array
el18lg 1:bdafa20e71a0 398 _durations = durations; // pointer for array
el18lg 1:bdafa20e71a0 399 _melody_length = length;
el18lg 1:bdafa20e71a0 400 _repeat = repeat;
el18lg 1:bdafa20e71a0 401
el18lg 1:bdafa20e71a0 402 _note = 0; // start from first note
el18lg 1:bdafa20e71a0 403
el18lg 1:bdafa20e71a0 404 play_next_note(); // play the next note in the melody
el18lg 1:bdafa20e71a0 405 }
el18lg 1:bdafa20e71a0 406
el18lg 1:bdafa20e71a0 407 void Gamepad::write_dac(float val)
el18lg 1:bdafa20e71a0 408 {
el18lg 1:bdafa20e71a0 409 if (val < 0.0f) {
el18lg 1:bdafa20e71a0 410 val = 0.0f;
el18lg 1:bdafa20e71a0 411 } else if (val > 1.0f) {
el18lg 1:bdafa20e71a0 412 val = 1.0f;
el18lg 1:bdafa20e71a0 413 }
el18lg 1:bdafa20e71a0 414 dac->write(val);
el18lg 1:bdafa20e71a0 415 }
el18lg 1:bdafa20e71a0 416
el18lg 1:bdafa20e71a0 417
el18lg 1:bdafa20e71a0 418 void Gamepad::play_next_note()
el18lg 1:bdafa20e71a0 419 {
el18lg 1:bdafa20e71a0 420 // _note is the note index to play
el18lg 1:bdafa20e71a0 421
el18lg 1:bdafa20e71a0 422 // calculate the duration and frequency of the note
el18lg 1:bdafa20e71a0 423 float duration = 60.0f/(_bpm*_durations[_note]);
el18lg 1:bdafa20e71a0 424 float frequency = float(_notes[_note]);
el18lg 1:bdafa20e71a0 425 //printf("[%i] f = %f d = %f\n",_note,frequency,duration);
el18lg 1:bdafa20e71a0 426
el18lg 1:bdafa20e71a0 427 // check if the note is not a space and if not then play the note
el18lg 1:bdafa20e71a0 428 if (frequency > 0) {
el18lg 1:bdafa20e71a0 429 tone(frequency,duration);
el18lg 1:bdafa20e71a0 430 }
el18lg 1:bdafa20e71a0 431
el18lg 1:bdafa20e71a0 432 // the timeout goes to the next note in the melody
el18lg 1:bdafa20e71a0 433 // double the duration to leave a bit of a gap in between notes to be better
el18lg 1:bdafa20e71a0 434 // able to distinguish them
el18lg 1:bdafa20e71a0 435 note_timeout->attach(callback(this, &Gamepad::note_timeout_isr), duration*2.0f );
el18lg 1:bdafa20e71a0 436 }
el18lg 1:bdafa20e71a0 437
el18lg 1:bdafa20e71a0 438 // called when the next note needs playing
el18lg 1:bdafa20e71a0 439 void Gamepad::note_timeout_isr()
el18lg 1:bdafa20e71a0 440 {
el18lg 1:bdafa20e71a0 441 _note++; // go onto next note
el18lg 1:bdafa20e71a0 442
el18lg 1:bdafa20e71a0 443 // if in repeat mode then reset the note counter when get to end of melody
el18lg 1:bdafa20e71a0 444 if (_repeat && _note == _melody_length) {
el18lg 1:bdafa20e71a0 445 _note=0;
el18lg 1:bdafa20e71a0 446 }
el18lg 1:bdafa20e71a0 447
el18lg 1:bdafa20e71a0 448 // check if note is within the melody
el18lg 1:bdafa20e71a0 449 if (_note < _melody_length) {
el18lg 1:bdafa20e71a0 450 play_next_note();
el18lg 1:bdafa20e71a0 451 }
el18lg 1:bdafa20e71a0 452 }
el18lg 1:bdafa20e71a0 453
el18lg 1:bdafa20e71a0 454 void Gamepad::ticker_isr()
el18lg 1:bdafa20e71a0 455 {
el18lg 1:bdafa20e71a0 456 dac->write(_sample_array[_sample%_n]); // use modulo to get index to play
el18lg 1:bdafa20e71a0 457 _sample++; // increment the sample ready for next time
el18lg 1:bdafa20e71a0 458 }
el18lg 1:bdafa20e71a0 459
el18lg 1:bdafa20e71a0 460 void Gamepad::timeout_isr()
el18lg 1:bdafa20e71a0 461 {
el18lg 1:bdafa20e71a0 462 // stops the ticker to end the note
el18lg 1:bdafa20e71a0 463 ticker->detach();
el18lg 1:bdafa20e71a0 464 }