Uri_ba's pit

Road to FCC, Part I – Reverse engineering the Cougar grip

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 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)

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

Leave a Reply