Dont be silly. It's a time machine.You are wrong!
I haven't a clue what it is meant to do :)I think it's obvious that this tool is needed to remotely tickle my cat in every possible way.
the terms 'male' 'female' (...) is deemed politically incorrectI'll let my
I think I'm gonna send a tweet with this box to someone with a really really big red button.
Mine might not be as big as his is, but I have plenty of them :P
I think I'm gonna send a tweet with this box to someone with a really really big red button.
I follow this project with great interest.
which hand of you is designated to fiddle with so many switches and buttons?I think the general misunderstanding here is that such game devices are always thought to be absolutely intuitive and user friendly.
I have been trying to get 5 USB devices - Joystick, pedals, throttle and 2 MFD's - to work with IL2 46.The same software combo VJoy + Joystick Gremlin could do the trick too.
The order of devices, VJoy and physical ones, stays the same even after reboot. Even if I unplug a hardware device and plug it in later again, it will rejoin at the very same place in the list.
Apparently, regardless how many VJoy devices I configure - all but one will be at the beginning of the list, and one will be at the end.
If it's just one VJoy device, it will always be at the end of the list.
Therefore, if you need to map existing hardware devices to a smaller number of VJoy devices, this will be possible. Just configure one more VJoy device than you actually need, so you have the needed ones in the beginning of the list.
Therefore that seems to be a viable solution for your issue Glynn.
For my purpose it definitely works well.
#include "ButtonMatrix.h"
const byte ROWS = 10; //four rows
const byte COLS = 8; //three columns
byte rowPins[ROWS] = {8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {27, 0, 1, 2, 3, 4, 5, 7}; //connect to the column pinouts of the keypad
int16_t buttonDirs[8] = {0, 45, 90, 135, 180, 225, 270, 315};
ButtonMatrix buttonmatrix = ButtonMatrix( rowPins, colPins, ROWS, COLS );
unsigned long loopCount;
unsigned long startTime;
unsigned long ledTime;
unsigned long joystickTime;
const int ledPin = 6;
String msg;
const int numButtons = 80;
void setup() {
Serial.begin(9600);
Joystick.useManualSend(true);
Serial.println("Begin Mike's Switchbox TEST");
Serial.print("Maximum Number of Buttons: ");
Serial.println(buttonmatrix.numButtons());
loopCount = 0;
startTime = millis();
ledTime = millis();
joystickTime = millis();
pinMode(ledPin, OUTPUT);
msg = "";
buttonmatrix.getButtons();
for (int i = 0; i < numButtons; i++) {
if (buttonmatrix.button[i].bstate == PRESSED || buttonmatrix.button[i].bstate == HOLD) {
Joystick.button(i + 1, 1);
} else {
Joystick.button(i + 1, 0);
}
}
Joystick.send_now();
Joystick.X(512);
Joystick.Y(512);
Joystick.Z(512);
Joystick.Xrotate(512);
Joystick.Yrotate(512);
Joystick.hat(1, -1);
Joystick.hat(2, -1);
Joystick.hat(3, -1);
for (int i = 0; i < 12; i++) {
Serial.print("joystick_report_data[");
Serial.print(i);
Serial.print("]=");
Serial.println(Joystick.get_joystick_report_data(i));
}
buttonmatrix.addEventListener(buttonEvent); // Add an event listener for this keypad
}
byte allButtons[numButtons];
byte prevButtons[numButtons];
int angle = 0;
int analog = 0;
void loop() {
loopCount++;
if ( (millis() - startTime) > 30000 ) {
Serial.print("Average loops per second = ");
Serial.println(loopCount / 30);
startTime = millis();
loopCount = 0;
}
if ( (millis() - ledTime) > 1 ) {
ledTime = millis();
digitalWrite(ledPin, LOW);
}
buttonmatrix.getButtons();
if ( (millis() - joystickTime) > 10 ) {
joystickTime = millis();
Joystick.X(analogRead(0));
Joystick.Y(analogRead(1));
Joystick.Z(analogRead(2));
Joystick.Xrotate(analogRead(3));
Joystick.Yrotate(analogRead(4));
Joystick.send_now();
}
delay(5);
}
void buttonEvent(ButtonEvent listIndex) {
switch (buttonmatrix.button[listIndex].bstate) {
case PRESSED:
msg = " PRESSED.";
break;
case RELEASED:
msg = " RELEASED.";
break;
case HOLD:
case IDLE:
default:
return;
}
ledTime = millis();
digitalWrite(ledPin, HIGH);
Serial.print("Button ");
Serial.print(buttonmatrix.button[listIndex].bindex);
Serial.println(msg);
int buttonIndex = buttonmatrix.button[listIndex].bindex;
bool buttonPressed = false;
if (buttonmatrix.button[listIndex].bstate == PRESSED || buttonmatrix.button[listIndex].bstate == HOLD) {
buttonPressed = true;
}
if (buttonIndex < 32) {
if (buttonPressed) {
Joystick.button(buttonIndex + 1, 1);
} else {
Joystick.button(buttonIndex + 1, 0);
}
}
else if (buttonIndex < 40) {
if (buttonPressed) {
Joystick.hat(1, buttonDirs[buttonIndex-32]);
} else {
Joystick.hat(1, -1);
}
}
else if (buttonIndex < 48) {
if (buttonPressed) {
Joystick.hat(2, buttonDirs[buttonIndex-40]);
} else {
Joystick.hat(2, -1);
}
}
else if (buttonIndex < 56) {
if (buttonPressed) {
Joystick.hat(3, buttonDirs[buttonIndex-48]);
} else {
Joystick.hat(3, -1);
}
}
else if (buttonIndex < 64) {
if (buttonPressed) {
Joystick.hat(4, buttonDirs[buttonIndex-56]);
} else {
Joystick.hat(4, -1);
}
}
//Joystick.send_now();
}
#include "ButtonMatrix.h"
ButtonMatrix::ButtonMatrix(byte *row, byte *col, byte numRows, byte numCols) {
rowPins = row;
columnPins = col;
sizeBM.rows = numRows;
sizeBM.columns = numCols;
setDebounceTime(10);
setHoldTime(500);
buttonEventListener = 0;
startTime = 0;
single_button = false;
}
// Returns a single button only. Retained for backwards compatibility.
int ButtonMatrix::getButton() {
single_button = true;
if (getButtons() && button[0].stateChanged && (button[0].bstate==PRESSED))
return button[0].bindex;
single_button = false;
return NO_BUTTON;
}
// Populate the button list.
bool ButtonMatrix::getButtons() {
bool buttonActivity = false;
// Limit how often the button matrix is scanned. This makes the loop() run 10 times as fast.
if ( (millis()-startTime)>debounceTime ) {
scanButtons();
buttonActivity = updateList();
startTime = millis();
}
return buttonActivity;
}
// Private : Hardware scan
void ButtonMatrix::scanButtons() {
// Re-intialize the row pins. Allows sharing these pins with other hardware.
for (byte r=0; r<sizeBM.rows; r++) {
pin_mode(rowPins[r],INPUT_PULLUP);
}
// bitMap stores ALL the buttons that are being pressed.
for (byte c=0; c<sizeBM.columns; c++) {
pin_mode(columnPins[c],OUTPUT);
pin_write(columnPins[c], LOW); // Begin column pulse output.
for (byte r=0; r<sizeBM.rows; r++) {
bitWrite(bitMap[r], c, !pin_read(rowPins[r])); // button press is active low so invert to high.
}
// Set pin to high impedance input. Effectively ends column pulse.
pin_write(columnPins[c],HIGH);
pin_mode(columnPins[c],INPUT);
}
}
// Manage the list without rearranging the keys. Returns true if any keys on the list changed state.
bool ButtonMatrix::updateList() {
bool anyActivity = false;
// Delete any IDLE buttons
for (byte i=0; i<LIST_MAX; i++) {
if (button[i].bstate==IDLE) {
button[i].bindex = NO_BUTTON;
button[i].stateChanged = false;
}
}
// Add new buttons to empty slots in the button list.
for (byte r=0; r<sizeBM.rows; r++) {
for (byte c=0; c<sizeBM.columns; c++) {
boolean bbutton = bitRead(bitMap[r],c);
int buttonIndex = r * sizeBM.columns + c;
int idx = findInList (buttonIndex);
// Key is already on the list so set its next state.
if (idx > -1) {
nextButtonState(idx, bbutton);
}
// Button is NOT on the list so add it.
if ((idx == -1) && bbutton) {
for (byte i=0; i<LIST_MAX; i++) {
if (button[i].bindex==NO_BUTTON) { // Find an empty slot or don't add button to list.
button[i].bindex = buttonIndex;
button[i].bstate = IDLE; // Buttons NOT on the list have an initial state of IDLE.
nextButtonState (i, bbutton);
break; // Don't fill all the empty slots with the same button.
}
}
}
}
}
// Report if the user changed the state of any button.
for (byte i=0; i<LIST_MAX; i++) {
if (button[i].stateChanged) anyActivity = true;
}
return anyActivity;
}
// Private
// This function is a state machine but is also used for debouncing the buttons.
void ButtonMatrix::nextButtonState(byte idx, boolean bbutton) {
button[idx].stateChanged = false;
switch (button[idx].bstate) {
case IDLE:
if (bbutton==CLOSED) {
transitionTo (idx, PRESSED);
holdTimer = millis(); } // Get ready for next HOLD state.
break;
case PRESSED:
if ((millis()-holdTimer)>holdTime) // Waiting for a key HOLD...
transitionTo (idx, HOLD);
else if (bbutton==OPEN) // or for a key to be RELEASED.
transitionTo (idx, RELEASED);
break;
case HOLD:
if (bbutton==OPEN)
transitionTo (idx, RELEASED);
break;
case RELEASED:
transitionTo (idx, IDLE);
break;
}
}
bool ButtonMatrix::isPressed(int buttonIndex) {
for (byte i=0; i<LIST_MAX; i++) {
if ( button[i].bindex == buttonIndex ) {
if ( (button[i].bstate == PRESSED) && button[i].stateChanged )
return true;
}
}
return false; // Not pressed.
}
// Search by index for a button in the list of active buttons.
// Returns -1 if not found, returns the active buttons list index if found.
int ButtonMatrix::findInList (int buttonIndex) {
for (byte i=0; i<LIST_MAX; i++) {
if (button[i].bindex == buttonIndex) {
return i;
}
}
return -1;
}
int ButtonMatrix::waitForButton() {
int waitButton = NO_BUTTON;
while( (waitButton = getButton()) == NO_BUTTON ); // Block everything while waiting for a keypress.
return waitButton;
}
ButtonState ButtonMatrix::getState() {
return button[0].bstate;
}
// The end user can test for any changes in state before deciding
// if any variables, etc. needs to be updated in their code.
bool ButtonMatrix::buttonStateChanged() {
return button[0].stateChanged;
}
// The number of buttons on the button list, button[LIST_MAX], equals the number
// of bytes in the button list divided by the number of bytes in a Button object.
byte ButtonMatrix::numButtons() {
return sizeof(button)/sizeof(Button);
}
// Minimum debounceTime is 1 ms. Any lower *will* slow down the loop().
void ButtonMatrix::setDebounceTime(uint debounce) {
debounce<1 ? debounceTime=1 : debounceTime=debounce;
}
void ButtonMatrix::setHoldTime(uint hold) {
holdTime = hold;
}
void ButtonMatrix::addEventListener(void (*listener)(int)){
buttonEventListener = listener;
}
void ButtonMatrix::transitionTo(byte idx, ButtonState nextState) {
button[idx].bstate = nextState;
button[idx].stateChanged = true;
// Sketch used the getButton() function.
// Calls buttonEventListener only when the first button in slot 0 changes state.
if (single_button) {
if ( (buttonEventListener!=NULL) && (idx==0) ) {
buttonEventListener(0);
}
}
// Sketch used the getButtons() function.
// Calls buttonEventListener on any button that changes state.
else {
if (buttonEventListener!=NULL) {
buttonEventListener(idx);
}
}
}
#ifndef BUTTON_MATRIX_H
#define BUTTON_MATRIX_H
#include "Button.h"
#ifndef INPUT_PULLUP
#warning "Using pinMode() INPUT_PULLUP AVR emulation"
#define INPUT_PULLUP 0x2
#define pinMode(_pin, _mode) _mypinMode(_pin, _mode)
#define _mypinMode(_pin, _mode) \
do { \
if(_mode == INPUT_PULLUP) \
pinMode(_pin, INPUT); \
digitalWrite(_pin, 1); \
if(_mode != INPUT_PULLUP) \
pinMode(_pin, _mode); \
}while(0)
#endif
#define OPEN LOW
#define CLOSED HIGH
typedef int ButtonEvent;
typedef unsigned int uint;
typedef unsigned long ulong;
// Made changes according to this post http://arduino.cc/forum/index.php?topic=58337.0
// by Nick Gammon. Thanks for the input Nick. It actually saved 78 bytes for me. :)
typedef struct {
byte rows;
byte columns;
} ButtonMatrixSize;
#define LIST_MAX 100 // Max number of keys on the active list.
#define MAPSIZE 10 // MAPSIZE is the number of rows (times 16 columns)
//class ButtonMatrix : public Button, public HAL_obj {
class ButtonMatrix : public Button {
public:
ButtonMatrix(byte *row, byte *col, byte numRows, byte numCols);
virtual void pin_mode(byte pinNum, byte mode) { pinMode(pinNum, mode); }
virtual void pin_write(byte pinNum, boolean level) { digitalWrite(pinNum, level); }
virtual int pin_read(byte pinNum) { return digitalRead(pinNum); }
uint bitMap[MAPSIZE]; // 10 row x 16 column array of bits. Except Due which has 32 columns.
Button button[LIST_MAX];
unsigned long holdTimer;
int getButton();
bool getButtons();
ButtonState getState();
bool isPressed(int buttonIndex);
void setDebounceTime(uint);
void setHoldTime(uint);
void addEventListener(void (*listener)(int));
int findInList(int buttonIndex);
int waitForButton();
bool buttonStateChanged();
byte numButtons();
private:
unsigned long startTime;
byte *rowPins;
byte *columnPins;
ButtonMatrixSize sizeBM;
uint debounceTime;
uint holdTime;
bool single_button;
void scanButtons();
bool updateList();
void nextButtonState(byte n, boolean bbutton);
void transitionTo(byte n, ButtonState nextState);
void (*buttonEventListener)(int);
};
#endif
#include "Button.h"
Button::Button() {
bindex = NO_BUTTON;
bstate = IDLE;
stateChanged = false;
}
void Button::button_update (int userButtonIndex, ButtonState userState, boolean userStatus) {
bindex = userButtonIndex;
bstate = userState;
stateChanged = userStatus;
}
#ifndef BUTTON_H_
#define BUTTON_H_
#include <Arduino.h>
#define OPEN LOW
#define CLOSED HIGH
typedef unsigned int uint;
typedef enum{ IDLE, PRESSED, HOLD, RELEASED } ButtonState;
const int NO_BUTTON = -1;
class Button {
public:
// members
int bindex;
ButtonState bstate;
boolean stateChanged;
// methods
Button();
void button_update(int userButtonIndex, ButtonState userState, boolean userStatus);
private:
};
#endif
#ifndef usb_serial_h__
#define usb_serial_h__
#include <stdint.h>
#ifdef __cplusplus
extern "C"{
#endif
/**************************************************************************
*
* Configurable Options
*
**************************************************************************/
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0482
#define TRANSMIT_FLUSH_TIMEOUT 4 /* in milliseconds */
#define TRANSMIT_TIMEOUT 25 /* in milliseconds */
/**************************************************************************
*
* Endpoint Buffer Configuration
*
**************************************************************************/
// 0: control 64
// 1: debug IN 64x2
// 2: debug OUT 32x2
// 3: joystick IN 16x2
// Some operating systems, especially Windows, may cache USB device
// info. Changes to the device name may not update on the same
// computer unless the vendor or product ID numbers change, or the
// "bcdDevice" revision code is increased.
#ifndef STR_PRODUCT
#define STR_PRODUCT L"Mikes Switchbox WIP"
#endif
#define ENDPOINT0_SIZE 64
#define DEBUG_INTERFACE 1
#define DEBUG_TX_ENDPOINT 1
#define DEBUG_TX_SIZE 64
#define DEBUG_TX_BUFFER EP_DOUBLE_BUFFER
#define DEBUG_TX_INTERVAL 1
#define DEBUG_RX_ENDPOINT 2
#define DEBUG_RX_SIZE 32
#define DEBUG_RX_BUFFER EP_DOUBLE_BUFFER
#define DEBUG_RX_INTERVAL 2
#define JOYSTICK_INTERFACE 2
#define JOYSTICK_ENDPOINT 3
#define JOYSTICK_SIZE 16
#define JOYSTICK_BUFFER EP_DOUBLE_BUFFER
#define JOYSTICK_INTERVAL 2
#define NUM_ENDPOINTS 4
#define NUM_INTERFACE 2
// setup
void usb_init(void); // initialize everything
void usb_shutdown(void); // shut off USB
// variables
extern volatile uint8_t usb_configuration;
extern volatile uint8_t usb_suspended;
extern volatile uint8_t debug_flush_timer;
extern uint8_t joystick_report_data[13];
#ifdef __cplusplus
} // extern "C"
#endif
#endif
#define CORE_TEENSY_HID
#if defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define CORE_TEENSY_JOYSTICK
#endif
/* USB API for Teensy USB Development Board
* http://www.pjrc.com/teensy/teensyduino.html
* Copyright (c) 2008 PJRC.COM, LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <stdint.h>
#include "usb_common.h"
#include "usb_private.h"
#include "usb_api.h"
#include "wiring.h"
void usb_joystick_class::send_now(void)
{
uint8_t intr_state, timeout;
if (!usb_configuration) return;
intr_state = SREG;
cli();
UENUM = JOYSTICK_ENDPOINT;
timeout = UDFNUML + 50;
while (1) {
// are we ready to transmit?
if (UEINTX & (1<<RWAL)) break;
SREG = intr_state;
// has the USB gone offline?
if (!usb_configuration) return;
// have we waited too long?
if (UDFNUML == timeout) return;
// get ready to try checking again
intr_state = SREG;
cli();
UENUM = JOYSTICK_ENDPOINT;
}
UEDATX = joystick_report_data[0];
UEDATX = joystick_report_data[1];
UEDATX = joystick_report_data[2];
UEDATX = joystick_report_data[3];
UEDATX = joystick_report_data[4];
UEDATX = joystick_report_data[5];
UEDATX = joystick_report_data[6];
UEDATX = joystick_report_data[7];
UEDATX = joystick_report_data[8];
UEDATX = joystick_report_data[9];
UEDATX = joystick_report_data[10];
UEDATX = joystick_report_data[11];
UEDATX = joystick_report_data[12];
UEINTX = 0x3A;
SREG = intr_state;
}
uint16_t usb_joystick_class::get_joystick_report_data(uint8_t index) {
return joystick_report_data[index];
}
static volatile uint8_t prev_byte=0;
void usb_serial_class::begin(long speed)
{
// make sure USB is initialized
usb_init();
uint16_t begin_wait = (uint16_t)millis();
while (1) {
if (usb_configuration) {
delay(200); // a little time for host to load a driver
return;
}
if (usb_suspended) {
uint16_t begin_suspend = (uint16_t)millis();
while (usb_suspended) {
// must remain suspended for a while, because
// normal USB enumeration causes brief suspend
// states, typically under 0.1 second
if ((uint16_t)millis() - begin_suspend > 250) {
return;
}
}
}
// ... or a timout (powered by a USB power adaptor that
// wiggles the data lines to keep a USB device charging)
if ((uint16_t)millis() - begin_wait > 2500) return;
}
prev_byte = 0;
}
void usb_serial_class::end()
{
usb_shutdown();
delay(25);
}
// number of bytes available in the receive buffer
int usb_serial_class::available()
{
uint8_t c;
c = prev_byte; // assume 1 byte static volatile access is atomic
if (c) return 1;
c = readnext();
if (c) {
prev_byte = c;
return 1;
}
return 0;
}
// get the next character, or -1 if nothing received
int usb_serial_class::read()
{
uint8_t c;
c = prev_byte;
if (c) {
prev_byte = 0;
return c;
}
c = readnext();
if (c) return c;
return -1;
}
int usb_serial_class::peek()
{
uint8_t c;
c = prev_byte;
if (c) return c;
c = readnext();
if (c) {
prev_byte = c;
return c;
}
return -1;
}
// get the next character, or 0 if nothing
uint8_t usb_serial_class::readnext(void)
{
uint8_t c, intr_state;
// interrupts are disabled so these functions can be
// used from the main program or interrupt context,
// even both in the same program!
intr_state = SREG;
cli();
if (!usb_configuration) {
SREG = intr_state;
return 0;
}
UENUM = DEBUG_RX_ENDPOINT;
try_again:
if (!(UEINTX & (1<<RWAL))) {
// no packet in buffer
SREG = intr_state;
return 0;
}
// take one byte out of the buffer
c = UEDATX;
if (c == 0) {
// if we see a zero, discard it and
// discard the rest of this packet
UEINTX = 0x6B;
goto try_again;
}
// if this drained the buffer, release it
if (!(UEINTX & (1<<RWAL))) UEINTX = 0x6B;
SREG = intr_state;
return c;
}
// discard any buffered input
void usb_serial_class::flush()
{
uint8_t intr_state;
if (usb_configuration) {
intr_state = SREG;
cli();
UENUM = DEBUG_RX_ENDPOINT;
while ((UEINTX & (1<<RWAL))) {
UEINTX = 0x6B;
}
SREG = intr_state;
}
prev_byte = 0;
}
// transmit a character.
size_t usb_serial_class::write(uint8_t c)
{
//static uint8_t previous_timeout=0;
uint8_t timeout, intr_state;
// if we're not online (enumerated and configured), error
if (!usb_configuration) goto error;
// interrupts are disabled so these functions can be
// used from the main program or interrupt context,
// even both in the same program!
intr_state = SREG;
cli();
UENUM = DEBUG_TX_ENDPOINT;
// if we gave up due to timeout before, don't wait again
#if 0
// this seems to be causig a lockup... why????
if (previous_timeout) {
if (!(UEINTX & (1<<RWAL))) {
SREG = intr_state;
return;
}
previous_timeout = 0;
}
#endif
// wait for the FIFO to be ready to accept data
timeout = UDFNUML + TRANSMIT_TIMEOUT;
while (1) {
// are we ready to transmit?
if (UEINTX & (1<<RWAL)) break;
SREG = intr_state;
// have we waited too long? This happens if the user
// is not running an application that is listening
if (UDFNUML == timeout) {
//previous_timeout = 1;
goto error;
}
// has the USB gone offline?
if (!usb_configuration) goto error;
// get ready to try checking again
intr_state = SREG;
cli();
UENUM = DEBUG_TX_ENDPOINT;
}
// actually write the byte into the FIFO
UEDATX = c;
// if this completed a packet, transmit it now!
if (!(UEINTX & (1<<RWAL))) {
UEINTX = 0x3A;
debug_flush_timer = 0;
} else {
debug_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
}
SREG = intr_state;
return 1;
error:
setWriteError();
return 0;
}
// These are Teensy-specific extensions to the Serial object
// immediately transmit any buffered output.
// This doesn't actually transmit the data - that is impossible!
// USB devices only transmit when the host allows, so the best
// we can do is release the FIFO buffer for when the host wants it
void usb_serial_class::send_now(void)
{
uint8_t intr_state;
intr_state = SREG;
cli();
if (debug_flush_timer) {
UENUM = DEBUG_TX_ENDPOINT;
while ((UEINTX & (1<<RWAL))) {
UEDATX = 0;
}
UEINTX = 0x3A;
debug_flush_timer = 0;
}
SREG = intr_state;
}
uint32_t usb_serial_class::baud(void)
{
return ((uint32_t)DEBUG_TX_SIZE * 10000 / DEBUG_TX_INTERVAL);
}
uint8_t usb_serial_class::stopbits(void)
{
return 1;
}
uint8_t usb_serial_class::paritytype(void)
{
return 0;
}
uint8_t usb_serial_class::numbits(void)
{
return 8;
}
uint8_t usb_serial_class::dtr(void)
{
return 1;
}
uint8_t usb_serial_class::rts(void)
{
return 1;
}
usb_serial_class::operator bool()
{
if (usb_configuration) return true;
return false;
}
// Preinstantiate Objects //////////////////////////////////////////////////////
usb_serial_class Serial = usb_serial_class();
usb_joystick_class Joystick = usb_joystick_class();
#ifndef USBserial_h_
#define USBserial_h_
#include <inttypes.h>
#include "Print.h"
#include "Stream.h"
extern uint8_t joystick_report_data[13];
class usb_joystick_class
{
public:
usb_joystick_class() { manual_mode = 0; }
inline void button(uint8_t button, bool val) {
button--;
uint8_t mask = (1 << (button & 7));
if (val) {
if (button < 8) joystick_report_data[0] |= mask;
else if (button < 16) joystick_report_data[1] |= mask;
else if (button < 24) joystick_report_data[2] |= mask;
else if (button < 32) joystick_report_data[3] |= mask;
} else {
mask = ~mask;
if (button < 8) joystick_report_data[0] &= mask;
else if (button < 16) joystick_report_data[1] &= mask;
else if (button < 24) joystick_report_data[2] &= mask;
else if (button < 32) joystick_report_data[3] &= mask;
}
if (!manual_mode) send_now();
}
inline void X(uint16_t val) {
if (val > 1023) val = 1023;
joystick_report_data[4] = val;
joystick_report_data[5] = (joystick_report_data[5] & 0xFC) | (val >> 8);
if (!manual_mode) send_now();
}
inline void Y(uint16_t val) {
if (val > 1023) val = 1023;
joystick_report_data[5] = (joystick_report_data[5] & 0x03) | (val << 2);
joystick_report_data[6] = (joystick_report_data[6] & 0xF0) | (val >> 6);
if (!manual_mode) send_now();
}
inline void position(uint16_t x, uint16_t y) {
if (x > 1023) x = 1023;
if (y > 1023) y = 1023;
joystick_report_data[4] = x;
joystick_report_data[5] = (x >> 8) | (y << 2);
joystick_report_data[6] = (joystick_report_data[6] & 0xF0) | (y >> 6);
if (!manual_mode) send_now();
}
inline void Z(uint16_t val) {
if (val > 1023) val = 1023;
joystick_report_data[6] = (joystick_report_data[6] & 0x0F) | (val << 4);
joystick_report_data[7] = (joystick_report_data[7] & 0xC0) | (val >> 4);
if (!manual_mode) send_now();
}
inline void Xrotate(uint16_t val) {
if (val > 1023) val = 1023;
joystick_report_data[7] = (joystick_report_data[7] & 0x3F) | (val << 6);
joystick_report_data[8] = (val >> 2);
if (!manual_mode) send_now();
}
inline void Yrotate(uint16_t val) {
if (val > 1023) val = 1023;
joystick_report_data[9] = val;
joystick_report_data[10] = (joystick_report_data[10] & 0xFC) | (val >> 8);
if (!manual_mode) send_now();
}
inline void hat(uint8_t hatnum, int16_t dir) {
uint8_t val = 15;
if (dir < 0) val = 15;
else if (dir < 23) val = 0;
else if (dir < 68) val = 1;
else if (dir < 113) val = 2;
else if (dir < 158) val = 3;
else if (dir < 203) val = 4;
else if (dir < 245) val = 5;
else if (dir < 293) val = 6;
else if (dir < 338) val = 7;
switch(hatnum) {
case 1:
joystick_report_data[10] = (joystick_report_data[10] & 0x0F) | (val << 4);
break;
case 2:
joystick_report_data[11] = (joystick_report_data[11] & 0xF0) | val;
break;
case 3:
joystick_report_data[11] = (joystick_report_data[11] & 0x0F) | (val << 4);
break;
case 4:
joystick_report_data[12] = (joystick_report_data[12] & 0xF0) | val;
break;
default:
break;
}
if (!manual_mode) send_now();
}
inline void useManualSend(bool mode) {
manual_mode = mode;
}
uint16_t get_joystick_report_data(uint8_t index);
void send_now(void);
private:
uint8_t manual_mode;
};
extern usb_joystick_class Joystick;
class usb_serial_class : public Stream
{
public:
// standard Arduino functions
void begin(long);
void end();
virtual int available();
virtual int read();
virtual int peek();
virtual void flush();
virtual size_t write(uint8_t);
using Print::write;
operator bool();
// Teensy extensions
void send_now(void);
uint32_t baud(void);
uint8_t stopbits(void);
uint8_t paritytype(void);
uint8_t numbits(void);
uint8_t dtr(void);
uint8_t rts(void);
private:
uint8_t readnext(void);
};
extern usb_serial_class Serial;
#endif
/* USB Serial Example for Teensy USB Development Board
* http://www.pjrc.com/teensy/usb_serial.html
* Copyright (c) 2008 PJRC.COM, LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "usb_common.h"
#include "usb_private.h"
/**************************************************************************
*
* Endpoint Buffer Configuration
*
**************************************************************************/
static const uint8_t PROGMEM endpoint_config_table[] = {
EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER,
EP_TYPE_INTERRUPT_OUT, EP_SIZE(DEBUG_RX_SIZE) | DEBUG_RX_BUFFER,
EP_TYPE_INTERRUPT_IN, EP_SIZE(JOYSTICK_SIZE) | JOYSTICK_BUFFER,
};
/**************************************************************************
*
* Descriptor Data
*
**************************************************************************/
// Descriptors are the data that your computer reads when it auto-detects
// this USB device (called "enumeration" in USB lingo). The most commonly
// changed items are editable at the top of this file. Changing things
// in here should only be done by those who've read chapter 9 of the USB
// spec and relevant portions of any USB class specifications!
static const uint8_t PROGMEM device_descriptor[] = {
18, // bLength
1, // bDescriptorType
0x00, 0x02, // bcdUSB
0, // bDeviceClass
0, // bDeviceSubClass
0, // bDeviceProtocol
ENDPOINT0_SIZE, // bMaxPacketSize0
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct
0x05, 0x01, // bcdDevice
0, // iManufacturer
1, // iProduct
0, // iSerialNumber
1 // bNumConfigurations
};
#ifdef JOYSTICK_INTERFACE
static const uint8_t PROGMEM joystick_hid_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x20, // Report Count (32)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (Button #1)
0x29, 0x20, // Usage Maximum (Button #32)
0x81, 0x02, // Input (variable,absolute)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection ()
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x03, // Logical Maximum (1023)
0x75, 0x0A, // Report Size (10)
0x95, 0x05, // Report Count (5)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x33, // Usage (Rx)
0x09, 0x34, // Usage (Ry)
0x81, 0x02, // Input (variable,absolute)
0xC0, // End Collection
0x75, 0x02, // Report Size (2)
0x95, 0x01, // Report Count (1)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x75, 0x04, // Report Size (4)
0x95, 0x04, // Report Count (4)
0x65, 0x14, // Unit (20)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x39, // Usage (Hat switch)
0x09, 0x39, // Usage (Hat switch)
0x09, 0x39, // Usage (Hat switch)
0x09, 0x39, // Usage (Hat switch)
0x81, 0x42, // Input (variable,absolute,null_state)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0xC0 // End Collection
};
#endif
static const uint8_t PROGMEM debug_hid_report_desc[] = {
0x06, 0xC9, 0xFF, // Usage Page 0xFFC9 (vendor defined)
0x09, 0x04, // Usage 0x04
0xA1, 0x5C, // Collection 0x5C
0x75, 0x08, // report size = 8 bits (global)
0x15, 0x00, // logical minimum = 0 (global)
0x26, 0xFF, 0x00, // logical maximum = 255 (global)
0x95, DEBUG_TX_SIZE, // report count (global)
0x09, 0x75, // usage (local)
0x81, 0x02, // Input
0x95, DEBUG_RX_SIZE, // report count (global)
0x09, 0x76, // usage (local)
0x91, 0x02, // Output
0x95, 0x04, // report count (global)
0x09, 0x76, // usage (local)
0xB1, 0x02, // Feature
0xC0 // end collection
};
#define DEBUG_HID_DESC_OFFSET ( 9 + 9 )
#define JOYSTICK_HID_DESC_OFFSET ( 9 + 9+9+7+7 + 9 )
#define CONFIG1_DESC_SIZE ( 9 + 9+9+7+7 + 9+9+7 )
static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
9, // bLength;
2, // bDescriptorType;
LSB(CONFIG1_DESC_SIZE), // wTotalLength
MSB(CONFIG1_DESC_SIZE),
NUM_INTERFACE, // bNumInterfaces
1, // bConfigurationValue
0, // iConfiguration
0xC0, // bmAttributes
50, // bMaxPower
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
DEBUG_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
2, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(debug_hid_report_desc), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
DEBUG_TX_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
DEBUG_TX_SIZE, 0, // wMaxPacketSize
DEBUG_TX_INTERVAL, // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
DEBUG_RX_ENDPOINT, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
DEBUG_RX_SIZE, 0, // wMaxPacketSize
DEBUG_RX_INTERVAL, // bInterval
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
JOYSTICK_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(joystick_hid_report_desc), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
JOYSTICK_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
JOYSTICK_SIZE, 0, // wMaxPacketSize
JOYSTICK_INTERVAL, // bInterval
};
// If you're desperate for a little extra code memory, these strings
// can be completely removed if iManufacturer, iProduct, iSerialNumber
// in the device desciptor are changed to zeros.
struct usb_string_descriptor_struct {
uint8_t bLength;
uint8_t bDescriptorType;
int16_t wString[];
};
static const struct usb_string_descriptor_struct PROGMEM string0 = {
4,
3,
{0x0409}
};
static const struct usb_string_descriptor_struct PROGMEM string1 = {
sizeof(STR_PRODUCT),
3,
STR_PRODUCT
};
// This table defines which descriptor data is sent for each specific
// request from the host (in wValue and wIndex).
static const struct descriptor_list_struct {
uint16_t wValue;
uint16_t wIndex;
const uint8_t *addr;
uint8_t length;
} PROGMEM descriptor_list[] = {
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
{0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)},
{0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9},
{0x2200, JOYSTICK_INTERFACE, joystick_hid_report_desc, sizeof(joystick_hid_report_desc)},
{0x2100, JOYSTICK_INTERFACE, config1_descriptor+JOYSTICK_HID_DESC_OFFSET, 9},
{0x0300, 0x0000, (const uint8_t *)&string0, 4},
{0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_PRODUCT)},
};
#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct))
/**************************************************************************
*
* Variables - these are the only non-stack RAM usage
*
**************************************************************************/
// zero when we are not configured, non-zero when enumerated
volatile uint8_t usb_configuration USBSTATE;
volatile uint8_t usb_suspended USBSTATE;
// the time remaining before we transmit any partially full
// packet, or send a zero length packet.
volatile uint8_t debug_flush_timer USBSTATE;
// joystick data
uint8_t joystick_report_data[13] USBSTATE;
/**************************************************************************
*
* Public Functions - these are the API intended for the user
*
**************************************************************************/
// initialize USB serial
void usb_init(void)
{
uint8_t u;
u = USBCON;
if ((u & (1<<USBE)) && !(u & (1<<FRZCLK))) return;
HW_CONFIG();
USB_FREEZE(); // enable USB
PLL_CONFIG(); // config PLL
while (!(PLLCSR & (1<<PLOCK))) ; // wait for PLL lock
USB_CONFIG(); // start USB clock
UDCON = 0; // enable attach resistor
usb_configuration = 0;
usb_suspended = 0;
debug_flush_timer = 0;
joystick_report_data[0] = 0;
joystick_report_data[1] = 0;
joystick_report_data[2] = 0;
joystick_report_data[3] = 0;
joystick_report_data[4] = 0;
joystick_report_data[5] = 0x02;
joystick_report_data[6] = 0x08;
joystick_report_data[7] = 0x20;
joystick_report_data[8] = 0x80;
joystick_report_data[9] = 0;
joystick_report_data[10] = 0xF2;
joystick_report_data[11] = 0xFF;
joystick_report_data[12] = 0xFF;
UDINT = 0;
UDIEN = (1<<EORSTE)|(1<<SOFE);
//sei(); // init() in wiring.c does this
}
void usb_shutdown(void)
{
UDIEN = 0; // disable interrupts
UDCON = 1; // disconnect attach resistor
USBCON = 0; // shut off USB periperal
PLLCSR = 0; // shut off PLL
usb_configuration = 0;
usb_suspended = 1;
}
/**************************************************************************
*
* Private Functions - not intended for general user consumption....
*
**************************************************************************/
// USB Device Interrupt - handle all device-level events
// the transmit buffer flushing is triggered by the start of frame
//
ISR(USB_GEN_vect)
{
uint8_t intbits, t;//, i;
// static uint8_t div4=0;
intbits = UDINT;
UDINT = 0;
if (intbits & (1<<EORSTI)) {
UENUM = 0;
UECONX = 1;
UECFG0X = EP_TYPE_CONTROL;
UECFG1X = EP_SIZE(ENDPOINT0_SIZE) | EP_SINGLE_BUFFER;
UEIENX = (1<<RXSTPE);
usb_configuration = 0;
}
if ((intbits & (1<<SOFI)) && usb_configuration) {
t = debug_flush_timer;
if (t) {
debug_flush_timer = -- t;
if (!t) {
UENUM = DEBUG_TX_ENDPOINT;
while ((UEINTX & (1<<RWAL))) {
UEDATX = 0;
}
UEINTX = 0x3A;
}
}
}
if (intbits & (1<<SUSPI)) {
// USB Suspend (inactivity for 3ms)
UDIEN = (1<<WAKEUPE);
usb_configuration = 0;
usb_suspended = 1;
#if (F_CPU >= 8000000L)
// WAKEUPI does not work with USB clock freeze
// when CPU is running less than 8 MHz.
// Is this a hardware bug?
USB_FREEZE(); // shut off USB
PLLCSR = 0; // shut off PLL
#endif
// to properly meet the USB spec, current must
// reduce to less than 2.5 mA, which means using
// powerdown mode, but that breaks the Arduino
// user's paradigm....
}
if (usb_suspended && (intbits & (1<<WAKEUPI))) {
// USB Resume (pretty much any activity)
#if (F_CPU >= 8000000L)
PLL_CONFIG();
while (!(PLLCSR & (1<<PLOCK))) ;
USB_CONFIG();
#endif
UDIEN = (1<<EORSTE)|(1<<SOFE)|(1<<SUSPE);
usb_suspended = 0;
return;
}
}
// Misc functions to wait for ready and send/receive packets
static inline void usb_wait_in_ready(void)
{
while (!(UEINTX & (1<<TXINI))) ;
}
static inline void usb_send_in(void)
{
UEINTX = ~(1<<TXINI);
}
static inline void usb_wait_receive_out(void)
{
while (!(UEINTX & (1<<RXOUTI))) ;
}
static inline void usb_ack_out(void)
{
UEINTX = ~(1<<RXOUTI);
}
// USB Endpoint Interrupt - endpoint 0 is handled here. The
// other endpoints are manipulated by the user-callable
// functions, and the start-of-frame interrupt.
//
ISR(USB_COM_vect)
{
uint8_t intbits;
const uint8_t *list;
const uint8_t *cfg;
uint8_t i, n, len;
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
uint16_t desc_val;
const uint8_t *desc_addr;
uint8_t desc_length;
UENUM = 0;
intbits = UEINTX;
if (intbits & (1<<RXSTPI)) {
bmRequestType = UEDATX;
bRequest = UEDATX;
read_word_lsbfirst(wValue, UEDATX);
read_word_lsbfirst(wIndex, UEDATX);
read_word_lsbfirst(wLength, UEDATX);
UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI));
if (bRequest == GET_DESCRIPTOR) {
list = (const uint8_t *)descriptor_list;
for (i=0; ; i++) {
if (i >= NUM_DESC_LIST) {
UECONX = (1<<STALLRQ)|(1<<EPEN); //stall
return;
}
pgm_read_word_postinc(desc_val, list);
if (desc_val != wValue) {
list += sizeof(struct descriptor_list_struct)-2;
continue;
}
pgm_read_word_postinc(desc_val, list);
if (desc_val != wIndex) {
list += sizeof(struct descriptor_list_struct)-4;
continue;
}
pgm_read_word_postinc(desc_addr, list);
desc_length = pgm_read_byte(list);
break;
}
len = (wLength < 256) ? wLength : 255;
if (len > desc_length) len = desc_length;
list = desc_addr;
do {
// wait for host ready for IN packet
do {
i = UEINTX;
} while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
if (i & (1<<RXOUTI)) return; // abort
// send IN packet
n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
for (i = n; i; i--) {
pgm_read_byte_postinc(UEDATX, list);
}
len -= n;
usb_send_in();
} while (len || n == ENDPOINT0_SIZE);
return;
}
if (bRequest == SET_ADDRESS) {
usb_send_in();
usb_wait_in_ready();
UDADDR = wValue | (1<<ADDEN);
return;
}
if (bRequest == SET_CONFIGURATION && bmRequestType == 0) {
usb_configuration = wValue;
debug_flush_timer = 0;
usb_send_in();
cfg = endpoint_config_table;
for (i=1; i<7; i++) {
UENUM = i;
UECONX = 1;
pgm_read_byte_postinc(UECFG0X, cfg);
pgm_read_byte_postinc(UECFG1X, cfg);
}
UERST = 0x1E;
UERST = 0;
return;
}
if (bRequest == GET_CONFIGURATION && bmRequestType == 0x80) {
usb_wait_in_ready();
UEDATX = usb_configuration;
usb_send_in();
return;
}
if (bRequest == GET_STATUS) {
usb_wait_in_ready();
i = 0;
if (bmRequestType == 0x82) {
UENUM = wIndex;
if (UECONX & (1<<STALLRQ)) i = 1;
UENUM = 0;
}
UEDATX = i;
UEDATX = 0;
usb_send_in();
return;
}
if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE)
&& bmRequestType == 0x02 && wValue == 0) {
i = wIndex & 0x7F;
if (i >= 1 && i <= NUM_ENDPOINTS) {
usb_send_in();
UENUM = i;
if (bRequest == SET_FEATURE) {
UECONX = (1<<STALLRQ)|(1<<EPEN);
} else {
UECONX = (1<<STALLRQC)|(1<<RSTDT)|(1<<EPEN);
UERST = (1 << i);
UERST = 0;
}
return;
}
}
if (wIndex == JOYSTICK_INTERFACE) {
if (bmRequestType == 0xA1) {
if (bRequest == HID_GET_REPORT) {
usb_wait_in_ready();
for (i=0; i<13; i++) {
UEDATX = joystick_report_data[i];
}
usb_send_in();
return;
}
}
}
if (wIndex == DEBUG_INTERFACE) {
if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) {
len = wLength;
do {
// wait for host ready for IN packet
do {
i = UEINTX;
} while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
if (i & (1<<RXOUTI)) return; // abort
// send IN packet
n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
for (i = n; i; i--) {
UEDATX = 0;
}
len -= n;
usb_send_in();
} while (len || n == ENDPOINT0_SIZE);
return;
}
if (bRequest == HID_SET_REPORT && bmRequestType == 0x21) {
if (wValue == 0x0300 && wLength == 0x0004) {
uint8_t b1, b2, b3, b4;
usb_wait_receive_out();
b1 = UEDATX;
b2 = UEDATX;
b3 = UEDATX;
b4 = UEDATX;
usb_ack_out();
usb_send_in();
if (b1 == 0xA9 && b2 == 0x45 && b3 == 0xC2 && b4 == 0x6B)
_reboot_Teensyduino_();
if (b1 == 0x8B && b2 == 0xC5 && b3 == 0x1D && b4 == 0x70)
_restart_Teensyduino_();
}
}
}
if (bRequest == 0xC9 && bmRequestType == 0x40) {
usb_send_in();
usb_wait_in_ready();
_restart_Teensyduino_();
}
}
UECONX = (1<<STALLRQ) | (1<<EPEN); // stall
}
No more funny and fancy unintended things happening just because I pressed Alt+P where Shift+P would have been the right combo...
I suppose he is going to label them.Thank you Skylla. The labels are helpful, you quickly get used to the switchboard and it gives me a feeling of more realism.
At least I would do so ;)
But aside from this, after having to look at the labels for a while I would certainly expect to find the right button "blind" at some point.
Anyway, congratulations Blaubär!
They get recognized as 'Gamecontroller' and there are two controllers but somehow both have the same name. But that doesn't bother me at all.That's a Windows/DirectX issue. In fact the two controllers have different names, but DirectX fails to query the 2nd node on the same physical device for it's name, that's why.
The Arduino Error (can't even put code or the complete message in here)Change that to "return NULL;" and you'll be fine.
/////
return false;
^~~~~
cannot convert 'bool' to 'ListNode<SwitchButton*>*' in return
/////