Click here to Skip to main content
15,881,882 members
Articles / Programming Languages / C++
Article

Wired PS3 Six Axis Controller Using USB HID as Input

Rate me:
Please Sign up or sign in to vote.
3.86/5 (9 votes)
14 Feb 2008CPOL3 min read 1.4M   8K   28   20
An article on using the USB Human Interface Device api for reading a wired PS3 controller including motion.
ps3_shot.jpg

Introduction

A lot can be found for interfacing a Wii-mote, but almost nothing could be found for accessing the new PS3 controller. This is not yet a complete highly re-usable library. Instead it looks more like a hack. But it does provide the eager programmer a way to communicate with a PS3 controller. The biggest trick is the mapping of the received data-block to a nice and easy struct. I made a variable for all buttons, so even the combined bits in a BYTE are mapped to a 'bool'.

The PS3 controller does get recognized by Windows, but before the controller reacts on our request, the following driver should be installed. (Tested under Windows XP and Windows Vista).

Background

Some info I found was using delphi SixAxis on Windows.

Some info I found was mad for accessing a USB temperature device from Cyprus Using the HID class eases the job of writing USB device drivers.

For a big explanation on the USB-HID calls, look at the last link.

Using the Code

When the application is started it will register for device-connection events. When a PS3 controller is connected the 'ThreadPS3' is created. This thread will contiuosly fill a struct of type PS3_data. This struct will contain all buttons. Digital and analog values.

For demo purposes I also made a 'Format' method, which make a output string, to show in the dialog of the current state of the controller.

One nice thing about C is the ability to let the compiler help in splitting up a raw data structure.

C++
typedef struct tagPS3_data
{
    BYTE    ReportID;
    union {
        struct{
            BYTE    LAnalogX;
            BYTE    LAnalogY;
            BYTE    dummy[46];
            bool    Triangle:1;
            bool    Circle:1;
            bool    Cross:1;
            bool    Cube:1;
            bool    L2:1;
            bool    R2:1;
            bool    L1:1;
            bool    R1:1;
        };
        BYTE    data[49];
    };
} PS3_data;

Three of the features used are nameless struct, nameless union and data width settings:

nameless struct
This makes it possible to 'group' a set of variables, while not needing to add the struct name in the variable name. Instead of PS3_data.Report.LAnalogX we can simply use PS3_data.LAnalogX.

A second feature is the abilty to use the struct in a union. So you can map two structs to the same location, without the need to give this struct a name.

nameless union
This makes it possible to let multiple variables be positioned on the same physical memory location. The variable PS3_data.LAnalogX shares the same memory location with PS3_data.data[0].

data width settings
This makes it possible to map a number of bool's to a BYTE. This way we can use PS3_data.Circle instead of (PS3_data.data[48]&0x02)

Why did I use this? Because now it is possible to fill the complete structure using a memcpy to a PS3Data* and then be able to access all requested attributes both by name and by byte offset. The known parts of the struct can be accessed by name. And the unknown parts can be accessed by the direct data[i] member.

Another interesting code snippet is the use of sprintf instead of CString::Format and t += w;

Every call to += results in allocation of a little bit larger memory block and a copy of the complete previous data and a copy of the new data.

C++
iPos += sprintf(&buffer[iPos],"test %d\r\n", 0 );

The sprintf will return the number of the newly added characters in iPos. This variable is used to feed the next call to sprintf with the offset in the original buffer &buffer[iPos]. Only thing to consider is ... the buffer MUST be large enough.

This as results in the following Format method:

C++
void PS3_data::Format ( char* buffer )
{
    int iPos = 0;

    iPos += sprintf(&buffer[iPos],"LeftJoy:%d-%d RightPad:%d %d %d %d\r\n",
        LAnalogX,LAnalogY,Triangle,Circle,Cross,Cube);

    int id=0;
    int idMax=45;
    for ( ; id<=idMax;id++)    iPos += sprintf(&buffer[iPos],"%02d:%d\r\n", id,
        data[id]);
}

Points of Interest

When looking at the code, you will not think of me as a rocket scientist. But I hope you will see a way to include this in your own test applications.

My goal is to add some sort of filter driver, which makes the device identify itself as a DirectX controller. Which it already does, but the motion sensors are not coupled to DirectInput values.

It actually is not a SIX axis, but more like a NINETHEEN axis, since all joypad/firebuttons are all pressure sensitive buttons, so all are actually floating values of 0-255.

History

11 feb. 2008 - Initial version.

14 feb. 2008 - Added some code explanation. Added link to SixAxisDriver.exe

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
ETA
Software Developer (Senior)
Netherlands Netherlands
I'm a 31 year old full-time programmer ('76).
(Currently: Lead Software System Designer)

Comments and Discussions

 
QuestionHID over WiFi Pin
Mehrdad_K20-Aug-18 22:19
professionalMehrdad_K20-Aug-18 22:19 
QuestionWhy does it make an sdf file Pin
Member 1192672322-Aug-15 14:42
Member 1192672322-Aug-15 14:42 
QuestionWindows 7 x64 driver Pin
Member 1071915428-Mar-14 11:38
Member 1071915428-Mar-14 11:38 
QuestionPerfect! - Bluetooth Addr? Pin
Pengatom15-Mar-10 5:50
Pengatom15-Mar-10 5:50 
GeneralCrash [modified] Pin
GoldenKevin18-Jan-10 11:27
GoldenKevin18-Jan-10 11:27 
GeneralRe: Crash Pin
ETA19-Jan-10 1:07
ETA19-Jan-10 1:07 
GeneralRe: Crash Pin
GoldenKevin20-Jan-10 10:32
GoldenKevin20-Jan-10 10:32 
GeneralUnable to build project Pin
Jake Edmonds22-Dec-09 21:45
Jake Edmonds22-Dec-09 21:45 
GeneralRe: Unable to build project Pin
GoldenKevin18-Jan-10 11:26
GoldenKevin18-Jan-10 11:26 
replace afxres.h with windows.h
QuestionPs3 harmonix drum controller Pin
stormydaniels2-Nov-08 6:25
stormydaniels2-Nov-08 6:25 
QuestionSource code for the driver? Pin
Yuval Naveh9-Sep-08 2:48
Yuval Naveh9-Sep-08 2:48 
AnswerRe: Source code for the driver? Pin
ETA9-Sep-08 7:37
ETA9-Sep-08 7:37 
GeneralRe: Source code for the driver? Pin
Yuval Naveh9-Sep-08 7:43
Yuval Naveh9-Sep-08 7:43 
GeneralSixaxisdriver.exe cannot be downloaded. Pin
dededeeded3etteiu4-Sep-08 3:50
dededeeded3etteiu4-Sep-08 3:50 
GeneralRe: Sixaxisdriver.exe cannot be downloaded. Pin
ETA4-Sep-08 10:07
ETA4-Sep-08 10:07 
GeneralRe: Sixaxisdriver.exe cannot be downloaded. [modified] Pin
ipvideo7-Apr-09 10:44
ipvideo7-Apr-09 10:44 
GeneralRe: Sixaxisdriver.exe cannot be downloaded. [modified] Pin
a nonymous6-May-14 13:18
a nonymous6-May-14 13:18 
Questionvar define Pin
klmopa19-Feb-08 19:38
klmopa19-Feb-08 19:38 
GeneralRe: var define Pin
ETA21-Feb-08 7:24
ETA21-Feb-08 7:24 
GeneralRe: var define Pin
klmopa21-Feb-08 18:35
klmopa21-Feb-08 18:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.