I’ve decided to upgrade my pit and get a Force sensitive mod for my stick. I’m currently using a stock Warthog, and I love it. the grip is fantastic. However, there is only one mod for it, which is the very expensive FSSB-R3 made by RealSimulators. The product seems to be a very good piece of engineering, and is a drop in replacement for the WH, slap the grip on the base and you are done. However, mounting in in a proper stick base is somewhat more problematic. The other Force-sensing mod is the FCC3 by ViperCore.nl it is somewhat cheaper, community proven for years. However, it has a major drawback, it requires the Cougar PCB to work. I have a cougar, but I refuse to use it 🙂 (see my TQS controller series).
But a lack of controller never stopped me 🙂 So I opted for the FCC3 and started to dig into my Cougar to understand what will be required.
In this post I’ll dive into the grip wiring and bit ordering, and all the other fun things I had to dig into a whole bunch of documents to find.
The Grip is connected with a 5 pin straight header with 0.1″ (2.54mm) pitch and looks very much like the JST EH connector (most likely because it is one.. I’ve ordered some, once they arrive I’ll be able to confirm). but even without the connector, you can use a standard 0.1″ header and it will plug in just fine (without directional cues or lock of course).
For Reference I’ve used some old cougar PCB drawing I found online (google for the rescue), and the Very good reference documentation for the Hempstick project by Hempstead which is an awesome project for low latency game-controllers. however, it will require a bulky (and somewhat expensive) ARM dev board (rather then a quick and dirty 5USD pro-micro, which is my device of choice).
Regardless, Hepstick Cougar Demo documentation can be found in the Hempstick download page. I’m also adding direct link to the PDF version.
The Cougar (and WH) grips are identical in terms of electronics. They both use 3 separate 8 bit shift registers chained together and all the input pins on them are pulled High (pressing a button will yield a low output). so the combined output is 24 bit long.
Arduino has a pretty good basic tutorial on the use of those (you know for extra reading): Arduino/Tutorial/ShiftIn.
The header wiring for the Cougar is as follows:
Pin Number | Role |
1 | Vcc |
2 | CS (Latch pin) |
3 | SPI_SCK (Clock Pin) |
4 | SPI_MISO (Data pin) |
5 | GND |
Reading the output is very straight forward, you just read bytes. initially I’ve just read all 3 bytes, and just bit shifted them over directly to a 32 bit uint. However, the bits are not “properly aliened” with the stick output, I guess it’s a prehistoric thing for thrust-master, and they just kept it for backward compatibility.
so with both the Cougar and the WH, bit order is almost the same.
Byte 1 contains the stick buttons.
Byte 2 is the Trim and TMS hats.
Byte 3 is the DMS and CMS hats.
However, WH contains one more button (CMS push) which is stored on the first byte.
This is the bit map ordered by the windows Button Number. I’ve added the bit mask and byte for each of them.
(and just a memory refresh if needed – Binary to HEX and DEC conversion)
HID button Id | Byte/Mask | Button Name |
1 | 1/0x01 | Trigger (1st Detent) |
2 | 1/0x08 | Weapon Release (Pickle) |
3 | 1/0x10 | Pinkie Switch |
4 | 1/0x20 | Paddle Switch |
5 | 1/0x40 | Missile Step (NWS) |
6 | 1/0x80 | Trigger (2nd Detent) |
7 | 2/0x10 | TMS up |
8 | 2/0x20 | TMS right |
9 | 2/0x40 | TMS down |
10 | 2/0x80 | TMS Left |
11 | 3/0x01 | DMS up |
12 | 3/0x02 | DMS right |
13 | 3/0x04 | DMS down |
14 | 3/0x08 | DMS Left |
15 | 3/0x10 | CMS up |
16 | 3/0x20 | CMS right |
17 | 3/0x40 | CMS down |
18 | 3/0x80 | CMS left |
19 | 1/0x02 | CMS Push (WH only) |
HAT_UP | 2/0x01 | Trim Fwd |
HAT_RIGHT | 2/0x02 | Trim right |
HAT_DOWN | 2/0x04 | Trim Aft |
HAT_LEFT | 2/0x08 | Trim left |
I’ve added here all the defines I’ve used in the code, it include both stick and raw bytes.
#define GripTriggerFirstDetent 0x01 #define GripPickle 0x02 #define GripPinkie 0x04 #define GripPaddle 0x08 #define GripMissleStep 0x10 #define GripTriggerSecondDetent 0x20 #define GripTmsFwd 0x40 #define GripTmsRight 0x80 #define GripTmsAft 0x100 #define GripTmsLeft 0x200 #define GripDmsFwd 0x400 #define GripDmsRight 0x800 #define GripDmsAft 0x1000 #define GripDmsLeft 0x2000 #define GripCmsFwd 0x4000 #define GripCmsRight 0x8000 #define GripCmsAft 0x10000 #define GripCmsLeft 0x20000 #define GripCmsDown 0x40000 #define GripBlank 0x80000 #define GripTrimFwd 0x100000 #define GripTrimRight 0x200000 #define GripTrimAft 0x400000 #define GripTrimLeft 0x800000 // Mapping from Grip to proper bytes //Byte 1: #define Trigger1st 0x01 #define CmsPush 0x02 #define Blank 0x04 #define WpnRel 0x08 #define Pinky 0x10 #define Paddle 0x20 #define MslStp 0x40 #define Trigger2nd 0x80 // Byte 2: #define TrimAll 0x0F #define TmsAll 0xF0 #define TrimFwd 0x01 #define TrimRight 0x02 #define TrimAft 0x04 #define TrimLeft 0x08 #define TmsFwd 0x10 #define TmsRight 0x20 #define TmsAft 0x40 #define TmsLeft 0x80 // Byte 3: #define DmsAll 0x0F #define CmsAll 0xF0 #define DmsFwd 0x01 #define DmsRight 0x02 #define DmsAft 0x04 #define DmsLeft 0x08 #define CmsFwd 0x10 #define CmsRight 0x20 #define CmsAft 0x40 #define CmsLeft 0x80