George Sykes ELEC2645 project

Dependencies:   mbed

https://os.mbed.com/media/uploads/el18gs/pixil-frame-0.png

GHOST HUNTER

In a world of ghostly horrors there is much money to be made in underground ghost fighting rings. You've managed to get hold of a Ghostbuster, a special piece of equipment that allows you to catch, train and fight ghosts.

Instructions

Below you will find the instructions for the game. Please note that due to COVID-19 a large part of the game (fighting ghosts) could not be added as it would have required access to a second gamepad which i could not acquire.

Welcome screen

When first started you will be presented with a welcome screen

  • Pot 1 to adjust the contrast on the screen
  • Press A to continue.

Main menu

You have three options, catch ghosts (add ghosts to your inventory), inventory (sell ghosts) or settings(adjust the games settings).

  • Press X and B to move the selection up and down respectively
  • Press A to enter the selected submenu

Catch Ghost

Will now be presented with two challenges. In the first you need to find a ghost, in the second you catch it. Theses stages will start automatically.

Find ghost

Rotate the gamepad on its roll and pitch axis until all the LED's turn on. The ones on the left indicate roll and the right pitch.

  • Rotate the gamepad on it roll and pitch to light up the LED's

Catch ghost

Return the gamepad to a comfortable position and use the joystick to move the crosshairs onto the ghost sprite. When ready press the A button to catch the ghost. You will be told what kind of ghost you have captured and it will be added to your inventory.

  • Press A to catch the ghost
  • Move the joystick to move the crosshairs

Inventory

The inventory allows you to view your ghosts and sell them.

  • Use Pot 1 to scroll through the ghosts
  • Pot 2 to scroll up and down the details of the individual ghosts
  • Press X to prepare to sell a ghost and press again to confirm, if you don't press again the sale screen will disappear after 5 seconds
  • Press Start to return to the main menu

Settings

This menu allows you to adjust some of the settings of the game.

  • Press X to go up one option
  • Press B to go down one option
  • Press A to enter the selected submenu
  • Press Start to return to the main menu

Contrast

Set the contrast of the LCD screen, the contrast will adjust on this screen so you can see the effect (contrast is bounded between 0.4 and 0.6).

  • Pot 1 to increase or decrease the contrast
  • Press A to set the contrast

Button Delay

Set the minimum time between button presses; if this is too low the game will detect two button presses when there was only one, too high and the buttons will seem unresponsive. So as to ensure these issues do not occur while changing the setting button X temporarily operates on the new delay but none of the others will until A is pressed.

  • Pot 1 to increase or decrease the delay
  • Press X to test the new delay, this will toggle the small circle to be filled in or unfilled
  • Press A to save the setting
Committer:
el18gs
Date:
Tue May 26 13:37:32 2020 +0000
Revision:
17:3ebcf7bba112
Parent:
2:eaf245af2aae
Final Submission. I have read and agreed with Statement of Academic Integrity.

Who changed what in which revision?

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