Leostick Joystick? Yes, and here's how.

A shrunk down Leonardo-compatible board, thumb drive sized with native USB support. [Product info]
drake250
Posts: 19
Joined: Mon May 28, 2012 1:17 pm
Location: Adelaide

Re: Leostick Joystick? Yes, and here's how.

Post by drake250 » Sat Aug 25, 2012 8:27 am

Glad to see you got it working. There's no reason why you couldn't add a hat switch and the analog axes - I've never tried the hat switch but you should be able to copy the relavent bits from one of my other versions for the analog inputs. I would highly recommend getting the HID descriptor tool and using that to create the descriptor, as it has a built in parser.

big_jose
Posts: 2
Joined: Fri Nov 23, 2012 10:19 pm

Re: Leostick Joystick? Yes, and here's how.

Post by big_jose » Fri Nov 23, 2012 10:38 pm

Hello,

I'm trying to compile the sketch of the wheel_pedals but it gives an error:
"wheel_pedals.ino: In function 'void loop()':"
"wheel_pedals:57: error: 'Joystick' was not declared in this scope"

It seems that I need the Joystick library right? Here can I find it?

Thanks

guitfiddle
Posts: 1
Joined: Thu Nov 29, 2012 2:49 pm

Re: Leostick Joystick? Yes, and here's how.

Post by guitfiddle » Thu Nov 29, 2012 2:55 pm

I modified the hdd and usbapi files to work with an arduino micro based on your guys' work. I plan on using the micro to create my own usb gamecontroller for interfacing with the DIY Drones APM Planner. It already shows up as a game controller. Thanks for helping me with this :) I wish I had known about leostick earlier, but now this works.
Attachments
USBAPI.h
(5.81 KiB) Downloaded 498 times
HID.cpp
(15.72 KiB) Downloaded 510 times

big_jose
Posts: 2
Joined: Fri Nov 23, 2012 10:19 pm

Re: Leostick Joystick? Yes, and here's how.

Post by big_jose » Fri Nov 30, 2012 11:07 pm

I'm trying to replicate the Logitech G25 with Leonardo or leostick. Is there any one that can help me with this?

Thanks :)

the nerdling
Posts: 10
Joined: Mon Dec 10, 2012 11:13 pm
Location: my house
Contact:

Re: Leostick Joystick? Yes, and here's how.

Post by the nerdling » Thu Sep 12, 2013 3:06 am

i can't do it :(
can you make a full step by step for it?
i have the v3.3 board profile and v2 bootloader

drake250
Posts: 19
Joined: Mon May 28, 2012 1:17 pm
Location: Adelaide

Re: Leostick Joystick? Yes, and here's how.

Post by drake250 » Thu Sep 12, 2013 1:49 pm

I haven't tried to emulate a joystick on the v2 bootloader yet, and the modifications I made to the code caused other issues (tone() still crashed) when I updated the bootloader from v1 - I need to have a go with the newer profile and v2 bootloader from scratch, but alas, I "released the magic smoke" from the zener diode this afternoon. :oops: (Good thing I have a second Leo)

It's not a simple process though, and requires modifying a couple of files plus using the HID descriptor tool http://www.usb.org/developers/hidpage#H ... tor%20Tool to build the descriptor that gets sent to the PC when the Leo connects. I'll give it a bash tomorrow and let you know how it goes and what the changes are for the v2 bootloader and 3.3 profile.

Anyone know where I can get a 5.6v 1W surface mount zener?

drake250
Posts: 19
Joined: Mon May 28, 2012 1:17 pm
Location: Adelaide

Re: Leostick Joystick? Yes, and here's how.

Post by drake250 » Sat Sep 14, 2013 2:48 am

Right, there's a simple change to get it working with the v2 bootloader - the USB code that gets compiled with your sketch isn't in the (sketchbook)/hardware/leostick folder any more (that's only for v1 bootloaders)

I'm using Arduino 1.0.5 and the Freetronics Leostick board profile v3.3

The files that you need to modify are (on my machine at least):
C:\Program Files\Arduino\hardware\arduino\cores\arduino\HID.cpp and USBAPI.h
These will be wherever the Arduino IDE is installed, and since the v2 Leostick uses the official Leonardo core the freetronics board profile doesn't need to be modified. (profile v3.3 at least, older board profiles may differ)

So, once you find the Arduino core files, open up HID.cpp and USBAPI.h in your favourite editor.

Step 1 - add a USB HID (Human Interface Device) descriptor for the joystick.
At the top of HID.cpp, look for this bit:

Code: Select all

//	Singletons for mouse and keyboard

Mouse_ Mouse;
Keyboard_ Keyboard;
and add this just below: (This isn't the HID descriptor, but it saves going back to do it later. It's the constructor for the interface class)

Code: Select all

// *** Add a joystick too
Joystick_ Joystick;
Now, just below you should see "// HID report descriptor" and a few #define lines, but the bit we're after is "const u8 _hidReportDescriptor[] = {"
Have a look at the list of hex values and their comments - it starts off defining the mouse interface, then the keyboard, then an optional raw HID device. This is how the leostick tells the PC what it's going to send and what it means.

Down where you see the #endif after the RAWHID section, we want to squeeze another HID descriptor for the joystick. Here's a descriptor for a 3 axis (X, Y, throttle) 8 button joystick, just below the RAW HID bit.

Code: Select all

#if RAWHID_ENABLED
	//	RAW HID
	0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE),	// 30
	0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE),

	0xA1, 0x01,				// Collection 0x01
    0x85, 0x03,             // REPORT_ID (3)
	0x75, 0x08,				// report size = 8 bits
	0x15, 0x00,				// logical minimum = 0
	0x26, 0xFF, 0x00,		// logical maximum = 255

	0x95, 64,				// report count TX
	0x09, 0x01,				// usage
	0x81, 0x02,				// Input (array)

	0x95, 64,				// report count RX
	0x09, 0x02,				// usage
	0x91, 0x02,				// Output (array)
	0xC0					// end collection
#endif

   // JOYSTICK HID
   0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
   0x09, 0x04,                    // USAGE (Joystick)
   0xA1, 0x01,                 // Collection (Application)
   0x85, 0x04,                    // REPORT_ID (4)

   0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
   0x09, 0x01,                    // USAGE (Pointer)
   0xA1, 0x00,                    // Collection (Physical)
   0x09, 0x30,                    // USAGE (x)
   0x09, 0x31,                    // USAGE (y)
   0x15, 0x00,                    // LOGICAL_MINIMUM (0)
   0x26, 0xFF, 0x00,              // LOGICAL_MAXIMUM (255)
   0x75, 0x08,                    // REPORT_SIZE (8)
   0x95, 0x02,                    // REPORT_COUNT (2)
    0x81, 0x02,                    // INPUT (Data,Var,Abs)
    0xC0,                          // END_COLLECTION

   0x05, 0x02,                    // USAGE_PAGE (Simulation controls)
   0x09, 0xBB,                    // USAGE (Throttle)
   0x15, 0x00,                    // LOGICAL_MINIMUM (0)
   0x26, 0xFF, 0x00,              // LOGICAL_MAXIMUM (255)
   0x75, 0x08,                    // REPORT_SIZE (8)
   0x95, 0x01,                    // REPORT_COUNT (1)
    0x81, 0x02,                    // INPUT (Data,Var,Abs)

    0x05, 0x09,                    // USAGE_PAGE (Button)
    0x19, 0x01,                    // USAGE_MINIMUM (button 1)
    0x29, 0x08,                    // USAGE_MAXIMUM (button 8)
    0x15, 0x00,                    // LOGICAL_MINIMUM (0)
    0x25, 0x01,                    // LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    // REPORT_SIZE (1)
    0x95, 0x08,                    // REPORT_COUNT (8)
    0x55, 0x00,                    // UNIT_EXPONENT (0)
    0x65, 0x00,                    // UNIT (None)
    0x81, 0x02,                    // Input (Data,Var,Abs)
   0xC0              // end collection

};
This will let the PC know to expect a report containing 8 bit values for X, Y and throttle (in that order!) followed by 8 1 bit buttons. HID reports must be a whole number of bytes, so if you only wanted 4 buttons you need to pad it so it's still a whole byte (Can't recall how to do this right now, so 8 buttons it is!). Also, it's set as report number 4 (1: Mouse, 2: KB, 3: raw)

Now, this post is getting a little long and I need coffee, so I'll be back with part 2 shortly.

drake250
Posts: 19
Joined: Mon May 28, 2012 1:17 pm
Location: Adelaide

Re: Leostick Joystick? Yes, and here's how.

Post by drake250 » Sat Sep 14, 2013 3:54 am

Righteo, now that I've got coffe and my ADSL modem has crashed and rebooted, on with part 2!

The next step, now that we have defined the format of the joystick data, is to add the class that will send the data - Scroll down through HID.cpp until you find this bit:

Code: Select all

//================================================================================
//================================================================================
//	Mouse

Mouse_::Mouse_(void) : _buttons(0)
Just above that, I added this:

Code: Select all

//================================================================================
//================================================================================
// Joystick
//  Usage: Joystick.move(x, y, throttle, buttons)
//  x & y forward/left = 0, centre = 127, back/right = 255
//  throttle max = 0, min = 255
//  8 buttons packed into 1 byte

Joystick_::Joystick_()
{
}

void Joystick_::move(uint8_t x, uint8_t y, uint8_t throttle, uint8_t buttons)
{
    u8 j[4];
    j[0] = x;
    j[1] = y;
    j[2] = throttle;
    j[3] = buttons;
    //HID_SendReport(Report number, array of values in same order as HID descriptor, length)
    HID_SendReport(4, j, 4);
}
What this does is create a 4 byte array (unsigned 8 bit integers) and put the values into it in the same order as defined in the descriptor. If you mess up the order you'll see strange behavior. This example is pretty simple, sticking to whole bytes - things get fun when you try 10 bit inputs which have to be split over multiple bytes!
It then calls HID_SendReport(4, j, 4) to send the data to the PC. In this example, it's report number 4, the array is j and it's 4 bytes long.

Now, that line at the start of HID.cpp: Joystick_ Joystick;
It creates an instance of the Joystick_ class and calls it Joystick so in our sketch we're using this instance rather than the class. If you have no idea what this means, don't worry too much, it just means that you don't need to create a Joystick object in your sketch because it's already been done for you.

Now, the final thing to do is go to USBAPI.h and look for the Mouse_ class. This is a header file which will tell the compiler what methods the Joystick_ class has and what data it needs. So, in between the end of the Serial_ class and the start of the Mouse_ class we'll put our Joystick_ class:

Code: Select all

//================================================================================
//================================================================================
// Joystick
// Implemented in HID.cpp

class Joystick_
{
public:
   Joystick_();
   void move(uint8_t x, uint8_t y, uint8_t throttle, uint8_t buttons);
};
extern Joystick_ Joystick;
This needs to match the move method we created in HID.cpp - if it doesn't, the compiler will fail.

Now that that's all done, all you need to do is write your sketch, get your inputs and all that stuff, and call the following: Joystick.move(x, y, throttle, buttons);
where x, y and throttle are 0-255 and buttons is the 8 buttons packed into one byte.

Now, to save having to copy all that out, here's the modified files (Arduino IDE v 1.0.5) and a simple demo sketch. All code is public domain, since it's mostly hacked from existing Arduino code.

Code: Select all

// Leostick joystick test
// Example of Joystick.move()
// X axis on A0, Y axis on A1, Throttle on A2
// Buttons on D0-7

void setup() {
pinMode(0, INPUT);
pinMode(1, INPUT);
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(4, INPUT);
pinMode(5, INPUT);
pinMode(6, INPUT);
pinMode(7, INPUT);
}

void loop() {
  int buttons = digitalRead(0) | (digitalRead(1) << 1 | (digitalRead(2) << 2 | 
    digitalRead(3) << 3 | digitalRead(4) << 4 | digitalRead(5) << 5 |
    digitalRead(6) << 6 |digitalRead(7) << 7;
  int x = analogRead(A0);
  int y = analogRead(A1);
  int throttle = analogRead(A2);

  x = map(x, 0, 1023, 0, 255); // Re-map the 10 bit inputs to 8 bit outputs
  y = map(y, 0, 1023, 0, 255);
  throttle = map(throttle, 0, 1023, 0, 255);
  
  Joystick.move(x, y, throttle, buttons);
  delay(20);
}
Attachments
USBAPI.h
(5.51 KiB) Downloaded 386 times
HID.cpp
(15.91 KiB) Downloaded 377 times

drake250
Posts: 19
Joined: Mon May 28, 2012 1:17 pm
Location: Adelaide

Re: Leostick Joystick? Yes, and here's how.

Post by drake250 » Sat Sep 14, 2013 4:35 am

Now, after all that, if you don't want a 3 axis 8 button joystick but would rather a different number of inputs, or 10 bit axes instead of 8 bit, you'll have to create your own descriptor using the HID descriptor tool I linked to earlier (And I'll mention again that it is FAR from user friendly, but more reliable than creating the descriptor manually) then modify HID.cpp and USBAPI.h to suit the new descriptor.

If you use the HID tool, save it as .h then you can copy-paste the data into HID.cpp - it's a lot easier and it comments each line.

The HID descriptor format is a little complicated at first, and takes a little bit of effort to get the hang of, but there's plenty of information available. Check out http://www.usb.org/developers/hidpage/ for more info.
The HID usage tables (ALL of them!) are described here: http://www.usb.org/developers/devclass_ ... 1_12v2.pdf but be warned, it's 168 pages and describes everything from Joysticks to Medical Imaging controls. Seriously though, it should be possible to create any HID interface listed here (like using a Nintendo DS touch panel as a digitizing tablet - that would be so sweet!)
If you're keen, there's a 97 page pdf explaining HID classes http://www.usb.org/developers/devclass_docs/HID1_11.pdf

And if I've confused the hell out of you, I'm sorry. Keyboards and Mice are fairly generic, so the default Arduino code works fine for them - Joysticks generally have different inputs from one stick to the next (flight yoke, racing wheel, gamepad, etc) so they really need a "bespoke" interface, which might explain why there's no official Joystick class. Good luck!

jake2701
Posts: 3
Joined: Fri Sep 27, 2013 11:07 am

Re: Leostick Joystick? Yes, and here's how.

Post by jake2701 » Fri Sep 27, 2013 8:32 pm

You seem to be deep into Leostick software. Could you look at my post viewtopic.php?f=27&t=5521 and tel me what you think. Thanks Jake

Post Reply