/ USB_SNES_Gamepad / teensySNES_test2 / teensySNES_test2.ino
teensySNES_test2.ino
  1  // SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries
  2  //
  3  // SPDX-License-Identifier: MIT
  4  
  5  const int pinAnalogXInput = 3;
  6  const int pinAnalogYInput = 1;
  7  const int pinAnalogZInput = 2;
  8  const int pinAnalogDummyInput = 0;
  9  
 10  #define KEYREPEAT 100  // milliseconds
 11  #define KEYDELAY 200 // delay from first to second character
 12  
 13  const int pinBtnUp = 0;
 14  const int pinBtnRight = 1;
 15  const int pinBtnDown = 2;
 16  const int pinBtnLeft = 3;
 17  
 18  const int pinBtnSelect = 4;
 19  const int pinBtnStart = 5;
 20  
 21  const int pinBtnB = 7;
 22  const int pinBtnA = 8;
 23  const int pinBtnY = 10;
 24  const int pinBtnX = 9;
 25  
 26  const int pinBtnTrigLeft = 6;
 27  const int pinBtnTrigRight = 23;
 28  
 29  const int pinLEDOutput = 11;
 30  
 31  //Variables for the states of the SNES buttons
 32  byte buttons[] = {  pinBtnUp, pinBtnRight, pinBtnDown, pinBtnLeft, pinBtnSelect, pinBtnStart,
 33                      pinBtnB, pinBtnA, pinBtnY, pinBtnX, pinBtnTrigLeft, pinBtnTrigRight
 34                   }; 
 35  short keys[] = {KEY_U, KEY_R, KEY_D, KEY_L, KEY_ENTER, KEY_TAB, KEY_B, KEY_A, KEY_Y, KEY_X, KEY_P, KEY_Q};
 36  
 37  #define NUMBUTTONS sizeof(buttons)
 38  
 39  typedef void KeyFunction_t(uint8_t c);
 40  
 41  KeyFunction_t* buttonActive[NUMBUTTONS];
 42  KeyFunction_t* keyList[] = {myset_key6, myset_key5, myset_key4, myset_key3, myset_key2, myset_key1};
 43  int            keySlot = sizeof(keyList) / sizeof(KeyFunction_t*);
 44  
 45  //Change these values if accelerometer reading are different:
 46  //How far the accerometer is tilted before
 47  //the Teensy starts moving the mouse:
 48  const int cintMovementThreshold = 18;
 49  
 50  //The average zero acceleration values read
 51  //from the accelerometer for each axis:
 52  const int cintZeroXValue = 328;
 53  const int cintZeroYValue = 328;
 54  const int cintZeroZValue = 328;
 55  
 56  //The maximum (positive) acceleration values read
 57  //from the accelerometer for each axis:
 58  const int cintMaxXValue = 396;
 59  const int cintMaxYValue = 396;
 60  const int cintMaxZValue = 396;
 61  
 62  //The minimum (negative) acceleration values read
 63  //from the accelerometer for each axis:
 64  const int cintMinXValue = 256;
 65  const int cintMinYValue = 256;
 66  const int cintMinZValue = 256;
 67  
 68  //The sign of the mouse movement relative to the acceleration.
 69  //If your cursor is going in the opposite direction you think it
 70  //should go, change the sign for the appropriate axis.
 71  const int cintXSign = 1;
 72  const int cintYSign = -1;
 73  const int cintZSign = 1;
 74  
 75  //const float cfloatMovementMultiplier = 1;
 76  
 77  //The maximum speed in each axis (x and y)
 78  //that the cursor should move. Set this to a higher or lower
 79  //number if the cursor does not move fast enough or is too fast.
 80  const int cintMaxMouseMovement = 10;
 81  
 82  //This reduces the 'twitchiness' of the cursor by calling
 83  //a delay function at the end of the main loop.
 84  //There is a better way to do this without delaying the whole
 85  //microcontroller, but that is left for another time or person.
 86  const int cintMouseDelay = 8;
 87  
 88  
 89  void setup()
 90  {
 91      //This is not needed and set to default but can be useful if you
 92    //want to get the full range out of the analog channels when
 93    //reading from the 3.3V ADXL335.
 94    //If the analog reference is used, the thresholds, zeroes,
 95    //maxima and minima will need to be re-evaluated.
 96    analogReference( DEFAULT );
 97    
 98    //Setup the pin modes.
 99    pinMode( pinLEDOutput, OUTPUT );
100  
101    //Special for the Teensy is the INPUT_PULLUP
102    //It enables a pullup resitor on the pin.
103    for (byte i=0; i< NUMBUTTONS; i++) {
104      pinMode(buttons[i], INPUT_PULLUP);
105    }
106  
107    //Uncomment this line to debug the acceleromter values:
108  //  Serial.begin();
109  
110  }
111  
112  
113  void loop()
114  {
115  //  //debugging the start button...
116    digitalWrite ( pinLEDOutput, digitalRead(pinBtnStart));
117  
118  
119    //Process the accelerometer to make the cursor move.
120    //Comment this line to debug the accelerometer values:
121    fcnProcessAccelerometer();
122  
123    //Progess the SNES controller buttons to send keystrokes.
124    fcnProcessButtons();
125    
126      
127    //Delay to avoid 'twitchiness' and bouncing inputs
128    //due to too fast of sampling.
129    //As said above, there is a better way to do this
130    //than delay the whole MCU.
131    delay(cintMouseDelay);
132  }
133  
134  
135  //Function to process the acclerometer data
136  //and send mouse movement information to the host computer.
137  void fcnProcessAccelerometer()
138  {
139    //Initialize values for the mouse cursor movement.
140    int intMouseXMovement = 0;
141    int intMouseYMovement = 0;
142    
143    //Read the dummy analog channel
144    //This must be done first because the X analog channel was first
145    //and was unstable, it dropped or pegged periodically regardless
146    //of pin or source.
147    analogRead( pinAnalogDummyInput );
148    
149    //Read accelerometer readings  
150    int intAnalogXReading = analogRead(pinAnalogXInput);
151    int intAnalogYReading = analogRead(pinAnalogYInput);
152    int intAnalogZReading = analogRead(pinAnalogZInput);
153  
154    //Calculate mouse movement
155    //If the analog X reading is ouside of the zero threshold...
156    if( cintMovementThreshold < abs( intAnalogXReading - cintZeroXValue ) )
157    {
158      //...calculate X mouse movement based on how far the X acceleration is from its zero value.
159      intMouseXMovement = cintXSign * ( ( ( (float)( 2 * cintMaxMouseMovement ) / ( cintMaxXValue - cintMinXValue ) ) * ( intAnalogXReading - cintMinXValue ) ) - cintMaxMouseMovement );
160      //it could use some improvement, like making it trigonometric.
161    }
162    else
163    {
164      //Within the zero threshold, the cursor does not move in the X.
165      intMouseXMovement = 0;
166    }
167  
168    //If the analog Y reading is ouside of the zero threshold... 
169    if( cintMovementThreshold < abs( intAnalogYReading - cintZeroYValue ) )
170    {
171      //...calculate Y mouse movement based on how far the Y acceleration is from its zero value.
172      intMouseYMovement = cintYSign * ( ( ( (float)( 2 * cintMaxMouseMovement ) / ( cintMaxYValue - cintMinYValue ) ) * ( intAnalogYReading - cintMinYValue ) ) - cintMaxMouseMovement );
173      //it could use some improvement, like making it trigonometric.
174    }
175    else
176    {
177      //Within the zero threshold, the cursor does not move in the Y.
178      intMouseYMovement = 0;
179    }
180   
181    Mouse.move(intMouseXMovement, intMouseYMovement);
182  
183  }
184  
185  //Function to process the buttons from the SNES controller
186  void fcnProcessButtons()
187  { 
188    bool keysPressed = false; 
189    bool keysReleased = false;
190    
191    // run through all the buttons
192    for (byte i = 0; i < NUMBUTTONS; i++) {
193      
194      // are any of them pressed?
195      if (! digitalRead(buttons[i])) 
196      {                              //this button is pressed
197        keysPressed = true;
198        if (!buttonActive[i])        //was it pressed before?
199          activateButton(i);            //no - activate the keypress
200      }
201      else
202      {                              //this button is not pressed
203        if (buttonActive[i]) {        //was it pressed before?
204          releaseButton(i);            //yes - release the keypress
205          keysReleased = true;
206        }
207      }
208    }
209    
210    if (keysPressed || keysReleased)
211      Keyboard.send_now();            //update all the keypresses
212  
213  }
214  
215  void activateButton(byte index)
216  {
217    if (keySlot)      //any key slots left?
218    {
219      keySlot--;                                //Push the keySlot stack
220      buttonActive[index] = keyList[keySlot];   //Associate the keySlot function pointer with the button
221      (*keyList[keySlot])(keys[index]);         //Call the key slot function to set the key value 
222    }
223  }
224  
225  void releaseButton(byte index)
226  {
227    keyList[keySlot] = buttonActive[index];    //retrieve the keySlot function pointer
228    buttonActive[index] = 0;                   //mark the button as no longer pressed
229    (*keyList[keySlot])(0);                    //release the key slot
230    keySlot++;                                 //pop the keySlot stack
231  }
232  
233  void myset_key1(uint8_t c)
234  {
235    Keyboard.set_key1(c);
236  }
237  
238  void myset_key2(uint8_t c)
239  {
240    Keyboard.set_key2(c);
241  }
242  
243  void myset_key3(uint8_t c)
244  {
245    Keyboard.set_key3(c);
246  }
247  
248  void myset_key4(uint8_t c)
249  {
250    Keyboard.set_key4(c);
251  }
252  
253  void myset_key5(uint8_t c)
254  {
255    Keyboard.set_key5(c);
256  }
257  
258  void myset_key6(uint8_t c)
259  {
260    Keyboard.set_key6(c);
261  }