Custom Joystick with Teensy 2.0 ++

Status
Not open for further replies.
The most common joystick request has been many more sliders or throttle inputs or axes.

Do you suppose people who've asked for this would not be able to use it, if it existed?

Possibly.

I guess that for most games, the DirectX limits are not a problem. I would think that for other games such as flight sims, they might use the raw input api instead or maybe directly through the hid drivers.

I might have a look at the raw input api over the weekend to see if it's any better.

Regards,

Les
 
Thanks for looking into this.

If Windows really is limited to only 8 axes+sliders, then it hardly seems worthwhile adding code to support more. I do not believe any of the joystick requests I've heard relate to usage with Mac or Linux.

Maybe allocating 9 or more bits to POVs would be worthwhile afterall?
 
After spending a lot of time looking through Pointy's example he posted Here I think I am really close to getting what I want.

I am able to get Pointy's joystick testing program to recognize my teensy board as a gamepad with 64 buttons and 6 axes as shown in my picture below.



Maybe my problem is with this part:


The last part will be the most challenging. It's also the part you can get not-quite-right and thing might sort-of work. It's all in usb_joystick.h.

First, find this. Actually, it's in both usb_joystick.h and usb_joystick.h.c

Code:
extern uint32_t usb_joystick_data[3];

I'm not sure why but none of the switches I have wired up seemed to respond to the joystick test. Don't think the problem is in my sketch because I loaded Point's 4 axes and 11 button joystick example and everything seem to responded appropriately.
So basically all I did was follow the steps in Pointy’s Example then edited the following files:

‘usb.c’, ‘usb_api.cpp’, ‘usb_api.h’ & ‘usb_private.h’

Starting with the file usb_private.h I edited: #define STR_PRODUCT to read DCS Switch Panel.

Then I changed
Code:
#define GAMEPAD_SIZE
from 8 to 16

And finally I changed
Code:
extern uint8_t gamepad_report_data[7];
to
Code:
extern uint8_t gamepad_report_data[16];
For this part I found this picture that Pointy made very helpful



Pointy’s example had 4 axes and 11 buttons plus 5 padding for a total of 56 bits or 7 bytes
Mine will have 6 axis and 64 buttons plus 4 padding for a total of 128 bits or 16 bytes.

Here is my usb_private.h Code:
Code:
#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              0x0488
#define TRANSMIT_FLUSH_TIMEOUT  4   /* in milliseconds */
#define TRANSMIT_TIMEOUT        25   /* in milliseconds */

/**************************************************************************
 *
 *  Endpoint Buffer Configuration
 *
 **************************************************************************/

// 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.

#define STR_PRODUCT             L"DCS Switch Panel"
#define ENDPOINT0_SIZE          64

#define GAMEPAD_INTERFACE	0
#define GAMEPAD_ENDPOINT	1
#define GAMEPAD_SIZE		16
#define GAMEPAD_BUFFER		EP_DOUBLE_BUFFER
#define GAMEPAD_INTERVAL	1

#define NUM_ENDPOINTS		2
#define NUM_INTERFACE		1

// 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;
// this holds the actual usb data sent from the controller to the pc
extern uint8_t gamepad_report_data[16];

#ifdef __cplusplus
} // extern "C"
#endif
#endif

Next I edited the file usb_c:

Theis is where I changed the gamepad description from 4 axes and 11 buttons to 6 axes and 64 buttons. I also made sure to change
Code:
uint8_t gamepad_report_data[7] USBSTATE;
to
Code:
uint8_t gamepad_report_data[16] USBSTATE;

Here is the usb_c code:
Code:
/* 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[] = {
	1, EP_TYPE_INTERRUPT_IN,  EP_SIZE(GAMEPAD_SIZE) | GAMEPAD_BUFFER,
	0
};

/**************************************************************************
 *
 *  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
};

static const uint8_t PROGMEM gamepad_hid_report_desc[] = {
	0x05, 0x01,				// USAGE_PAGE (Generic Desktop)
	0x09, 0x04,				// USAGE (Joystick)
	0xa1, 0x01,				// COLLECTION (Application)
	0x09, 0x04,				// USAGE (Joystick)
	0xa1, 0x00,				// COLLECTION (Physical)
	0x05, 0x09,				// USAGE_PAGE (Button)
	0x19, 0x01,				// USAGE_MINIMUM (Button 1)
	0x29, 0x40,				// USAGE_MAXIMUM (Button 64)
	0x15, 0x00,				// LOGICAL_MINIMUM (0)
	0x25, 0x01,				// LOGICAL_MAXIMUM (1)
	0x75, 0x01,				// REPORT_SIZE (1)
	0x95, 0x40,				// REPORT_COUNT (64)
	0x81, 0x02,				// INPUT (Data,Var,Abs)
	0x75, 0x01,				// REPORT_SIZE (1)
	0x95, 0x04,				// REPORT_COUNT (4)
	0x81, 0x03,				// INPUT (Cnst,Var,Abs)	
	0x05, 0x01,				// USAGE_PAGE (Generic Desktop)
	0x09, 0x30,				// USAGE (X)
	0x09, 0x31,				// USAGE (Y)
	0x09, 0x33,				// USAGE (Rx)
	0x09, 0x34,				// USAGE (Ry)
	0x09, 0x35,             // Usage (Rz)
	0x09, 0x36,             // Usage (Slider)
	0x75, 0x0A,				// REPORT_SIZE (10)
	0x95, 0x06,				// REPORT_COUNT (6)
        0x15, 0x00,                      	// Logical Minimum (0)
        0x26, 0xFF, 0x03,               	// Logical Maximum (1023)
	0x81, 0x02,				// INPUT (Data,Var,Abs)
        0xC0,                                   // end collection
        0xC0                                    // end collection
};

#define CONFIG1_DESC_SIZE		( 9 + 9+9+7 )
#define GAMEPAD_HID_DESC_OFFSET		(  9 + 9 )

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
        GAMEPAD_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(gamepad_hid_report_desc),       // wDescriptorLength
        0,
        // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
        7,                                      // bLength
        5,                                      // bDescriptorType
        GAMEPAD_ENDPOINT | 0x80,               // bEndpointAddress
        0x03,                                   // bmAttributes (0x03=intr)
        GAMEPAD_SIZE, 0,			// wMaxPacketSize
        GAMEPAD_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, GAMEPAD_INTERFACE, gamepad_hid_report_desc, sizeof(gamepad_hid_report_desc)},
        {0x2100, GAMEPAD_INTERFACE, config1_descriptor+GAMEPAD_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;

uint8_t gamepad_report_data[16] 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;
	gamepad_report_data[0] = 0;
	gamepad_report_data[1] = 0;
	gamepad_report_data[2] = 0;
	gamepad_report_data[3] = 0;
	gamepad_report_data[4] =  0x0F;
	gamepad_report_data[5] =  0x20;
	gamepad_report_data[6] =  0x80;
	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;
}


// Public API functions moved to usb_api.cpp

/**************************************************************************
 *
 *  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 (keyboard_idle_config && (++div4 & 3) == 0) {
//                        UENUM = KEYBOARD_ENDPOINT;
//                        if (UEINTX & (1<<RWAL)) {
//                                keyboard_idle_count++;
//                                if (keyboard_idle_count == keyboard_idle_config) {
//                                        keyboard_idle_count = 0;
//					len = keyboard_protocol ? sizeof(keyboard_keys) : 8;
//                                        for (i=0; i < 8; i++) {
//                                                UEDATX = keyboard_report_data[i];
//                                        }
//                                        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, en;
	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;
			usb_send_in();
			cfg = endpoint_config_table;
			for (i=1; i<NUM_ENDPOINTS; i++) {
				UENUM = i;
				pgm_read_byte_postinc(en, cfg);
				UECONX = en;
				if (en) {
					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 == GAMEPAD_INTERFACE) {
                        if (bmRequestType == 0xA1) {
                                if (bRequest == HID_GET_REPORT) {
                                        usb_wait_in_ready();
					for (i=0; i<12; i++) {
						UEDATX = gamepad_report_data[i];
					}
                                        usb_send_in();
                                        return;
				}
			}
		}
		if (bRequest == 0xC9 && bmRequestType == 0x40) {
			usb_send_in();
			usb_wait_in_ready();
			_restart_Teensyduino_();
		}
        }
	UECONX = (1<<STALLRQ) | (1<<EPEN);	// stall
}

Next edited file usb_api.h.

The only change I made here was
Code:
extern uint8_t gamepad_report_data[7];
to
Code:
extern uint8_t gamepad_report_data[16];

Here is the usb_api.h code:

Code:
#ifndef USBserial_h_
#define USBserial_h_

#include <inttypes.h>

#include "keylayouts.h"
#include "Print.h"
#include "Stream.h"

extern uint8_t gamepad_report_data[16];

class usb_gamepad_class
{
	public:
	usb_gamepad_class() { manual_mode = 0; }
	inline void button(uint8_t button, bool val) {
		button--;
		uint8_t mask = (1 << (button & 7)); // create button mask
		if (val)
		{
			// set bit with logical or
			if (button < 8) gamepad_report_data[0] |= mask; // buttons 0 to 7
			else if (button < 16) gamepad_report_data[1] |= mask; // buttons 8 - 10
		}
		else
		{
			// reset bit with  logical and
			mask = ~mask; // invert button mask
			if (button < 8) gamepad_report_data[0] &= mask; // buttons 0 to 7
			else if (button < 16) gamepad_report_data[1] &= mask; // buttons 8 to 10
		}
		if (!manual_mode) send_now();
	}
	inline void X(uint16_t val) {
		if (val > 1023) val = 1023;
		gamepad_report_data[2] = val; // use bottom 8 bit of x axis in byte 2
		gamepad_report_data[3] = (gamepad_report_data[3] & 0xFC) | (val >> 8); // move top 2 bits of x axis into byte 3
		if (!manual_mode) send_now();
	}
	inline void Y(uint16_t val) {
		if (val > 1023) val = 1023;
		gamepad_report_data[3] = (gamepad_report_data[3] & 0x3F) | (val << 2); // move bottom 6 bits of y axis into byte 3
		gamepad_report_data[4] = (gamepad_report_data[4] & 0xF0) | (val >> 6); // move top 4 bytes of y axis into byte 4
		if (!manual_mode) send_now();
	}
	inline void RX(uint16_t val) {
		gamepad_report_data[4] = (gamepad_report_data[4] & 0x0F) | (val << 4); // move bottom 4 buyes of rx axis into byte 4
		gamepad_report_data[5] = (gamepad_report_data[5] & 0xC0) | (val >> 4); // move top 6 bits of ry rx axis into byte 5
			if (!manual_mode) send_now();
	}
	inline void RY(uint16_t val) {
		if (val > 1023) val = 1023;
		gamepad_report_data[5] = (gamepad_report_data[5] & 0x3F ) | (val << 8); // move bottom 2 bytes of ry axis into byte 5
		gamepad_report_data[6] =   (val >> 2); // move top 8 bits of ry axis into byte 6
		if (!manual_mode) send_now();
	}

	inline void useManualSend(bool mode) {
		manual_mode = mode;
	}
	
	void send_now(void);
	
	private:
	uint8_t manual_mode;
};

extern usb_gamepad_class Gamepad;

#endif

Thats it, I did not make any changes to usp_api.cpp.

Code:
/* 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_gamepad_class::send_now(void)
{
        uint8_t intr_state, timeout;

        if (!usb_configuration) return;
        intr_state = SREG;
        cli();
        UENUM = GAMEPAD_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 = GAMEPAD_ENDPOINT;
        }
        UEDATX = gamepad_report_data[0];
        UEDATX = gamepad_report_data[1];
        UEDATX = gamepad_report_data[2];
        UEDATX = gamepad_report_data[3];
        UEDATX = gamepad_report_data[4];
        UEDATX = gamepad_report_data[5];
        UEDATX = gamepad_report_data[6];
        UEINTX = 0x3A;
        SREG = intr_state;
}

// Preinstantiate Objects //////////////////////////////////////////////////////
usb_gamepad_class	Gamepad = usb_gamepad_class();

If any of you see a step I forgot please let me know. Like I said I think I am close. I really hope someone can give me some input.

Thanks!
 
Status
Not open for further replies.
Back
Top