Shopping Cart

Posts

PS3 and Wiimote Game Controllers on the Arduino Host Shield: Part 3

Wiimote controller wit USB Host Shield

Wiimote controller wit USB Host Shield

This is the third part of a series of articles written to describe development of interface between Arduino and popular game controllers using USB Host Shield. Previous parts:

Revision 0.4 – 13th January 2010

Part 3. Develop the Bluetooth USB and HCI interface used in the support of the Wiimote and PS3 game controller, and also some utilities needed to analyse and configure these devices.

1. USB Interface
As before, we first look at the descriptors for the USB dongle using the USB_Desc sketch. The result is:

Start
Device descriptor:
Descriptor Length:    12
Descriptor type:      01
USB version:          0110
Device class:         E0
Device Subclass:      01
Device Protocol:      01
Max.packet size:      10
Vendor  ID:           0A12
Product ID:           0001
Revision ID:          0134
Mfg.string index:     00
Prod.string index:    00
Serial number index:  00
Number of conf.:      01
Configuration descriptor:
Total length:         006C
Num.intf:             02
Conf.value:           01
Conf.string:          00
Attr.:                80
Max.pwr:              32
Interface descriptor:
Intf.number:          00
Alt.:                 00
Endpoints:            03
Intf. Class:          E0
Intf. Subclass:       01
Intf. Protocol:       01
Intf.string:          00
Endpoint descriptor:
Endpoint address:     81
Attr.:                03
Max.pkt size:         0010
Polling interval:     01
Endpoint descriptor:
Endpoint address:     82
Attr.:                02
Max.pkt size:         0040
Polling interval:     00
Endpoint descriptor:
Endpoint address:     02
Attr.:                02
Max.pkt size:         0040
Polling interval:     00
Interface descriptor:
Intf.number:          01
Alt.:                 00
Endpoints:            02
Intf. Class:          E0
Intf. Subclass:       01
Intf. Protocol:       01
Intf.string:          00
Endpoint descriptor:
Endpoint address:     83
Attr.:                01
Max.pkt size:         0000
Polling interval:     01
Endpoint descriptor:
Endpoint address:     03
Attr.:                01
Max.pkt size:         0000
Polling interval:     01
Interface descriptor:
Intf.number:          01
Alt.:                 01
Endpoints:            02
Intf. Class:          E0
Intf. Subclass:       01
Intf. Protocol:       01
Intf.string:          00
Endpoint descriptor:
Endpoint address:     83
Attr.:                01
Max.pkt size:         0009
Polling interval:     01
Endpoint descriptor:
Endpoint address:     03
Attr.:                01
Max.pkt size:         0009
Polling interval:     01
Interface descriptor:
Intf.number:          01
Alt.:                 02
Endpoints:            02
Intf. Class:          E0
Intf. Subclass:       01
Intf. Protocol:       01
Intf.string:          00
Endpoint descriptor:
Endpoint address:     83
Attr.:                01
Max.pkt size:         0011
Polling interval:     01
Endpoint descriptor:
Endpoint address:     03
Attr.:                01
Max.pkt size:         0011
Polling interval:     01

The device descriptor is straight forward, but the configuration descriptor shows two interfaces and the second interface has alternate settings. The usage of the different endpoints is described here: Bluetooth Endpoint Usage

The second interface (interface one) is used for isochronous bandwidth related to carrying voice channels and we do not use this for Bluetooth HID, so they will be ignored.

We have four endpoints to consider:

The control endpoint (endpoint 0): This is used to send control messages and HCI commands.

The interrupt endpoint (endpoint 0×81): Where HCI events are received from the USB dongle.

The input endpoint (endpoint 0x 82): The bulk endpoint where ACL reports are received from the connected Bluetooth device.

The output endpoint (endpoint 0×02): The bulk endpoint where ACL reports are sent to the connected Bluetooth device.

These four endpoints discovered are registered as pipes to the USB Host library.

  /* Initialize data structures for endpoints of device 1*/
    ep_record[ CONTROL_PIPE ] = *( Usb.getDevTableEntry( 0,0 ));  //copy endpoint 0 parameters
    ep_record[ EVENT_PIPE ].epAddr = 0x01;    // Bluetooth event endpoint
    ep_record[ EVENT_PIPE ].Attr  = EP_INTERRUPT;
    ep_record[ EVENT_PIPE ].MaxPktSize = INT_MAXPKTSIZE;
    ep_record[ EVENT_PIPE ].Interval  = EP_POLL;
    ep_record[ EVENT_PIPE ].sndToggle = bmSNDTOG0;
    ep_record[ EVENT_PIPE ].rcvToggle = bmRCVTOG0;
    ep_record[ DATAIN_PIPE ].epAddr = 0x02;    // Bluetooth data endpoint
    ep_record[ DATAIN_PIPE ].Attr  = EP_BULK;
    ep_record[ DATAIN_PIPE ].MaxPktSize = BULK_MAXPKTSIZE;
    ep_record[ DATAIN_PIPE ].Interval  = 0;
    ep_record[ DATAIN_PIPE ].sndToggle = bmSNDTOG0;
    ep_record[ DATAIN_PIPE ].rcvToggle = bmRCVTOG0;
    ep_record[ DATAOUT_PIPE ].epAddr = 0x02;    // Bluetooth data endpoint
    ep_record[ DATAOUT_PIPE ].Attr  = EP_BULK;
    ep_record[ DATAOUT_PIPE ].MaxPktSize = BULK_MAXPKTSIZE;
    ep_record[ DATAOUT_PIPE ].Interval  = 0;
    ep_record[ DATAOUT_PIPE ].sndToggle = bmSNDTOG0;
    ep_record[ DATAOUT_PIPE ].rcvToggle = bmRCVTOG0;
    Usb.setDevTableEntry( BT_ADDR, ep_record );

The VID and the PID of the Bluetooth dongle should be checked to ensure compatibility. The CSR is the only dongle currently supported, but others have been found compatible and may be added later.
The device is configured and the interface 0 then set. At this stage we have communication with the Bluetooth dongle and can now start to communicate over Bluetooth.

2. Listen while we talk
We are now in a position to send HCI commands to the Bluetooth dongle over the control pipe, but first need to set up a process to read the interrupt pipe regularly. The events received on the interrupt pipe may not be directly related to the commands sent, so they must be processed as they arrive. As the USB host, we control the data transfers; we do not have to buffer large amounts of data, we only pull over the pipe what we can handle at any time. Also in the spirit of our “reduced host” for both USB and Bluetooth, we do no have to process all of the 36 possible events in the Bluetooth specification; we process only the ones we need for each application and ignore the rest. Significant events are communicated to the higher level routines through a set of flags.
We also commence reading the ACL input endpoint in case ACL events are ready there too. These are ignored until connection is made, but are read in case they block HCI events.
At this stage we handle only these HCI events:

#define EV_COMMAND_COMPLETE  0x0e
#define EV_COMMAND_STATUS    0x0f
#define EV_CONNECT_COMPLETE  0x03
#define EV_DISCONNECT_COMPLETE 0x05
#define EV_NUM_COMPLETE_PKT  0x13
#define EV_INQUIRY_COMPLETE  0x01
#define EV_INQUIRY_RESULT    0x02
#define EV_REMOTE_NAME_COMPLETE  0x07
#define EV_INCOMING_CONNECT  0x04
#define EV_ROLE_CHANGED  0x12

And we use these flags:

/* HCI event flags*/
#define HCI_FLAG_CMD_COMPLETE 0x01
#define HCI_FLAG_CMD_STATUS 0x02
#define HCI_FLAG_CONN_COMPLETE 0x04
#define HCI_FLAG_DISCONN_COMPLETE 0x08
#define HCI_FLAG_CONNECT_OK 0x10
#define HCI_FLAG_INQUIRY_COMPLETE 0x20
#define HCI_FLAG_REMOTE_NAME_COMPLETE 0x40
#define HCI_FLAG_INCOMING_REQUEST 0x80
 
//Macros for event flag tests
#define hci_cmd_complete (hci_event_flag & HCI_FLAG_CMD_COMPLETE)
#define hci_cmd_status (hci_event_flag & HCI_FLAG_CMD_STATUS)
#define hci_connect_complete (hci_event_flag & HCI_FLAG_CONN_COMPLETE)
#define hci_disconnect_complete (hci_event_flag & HCI_FLAG_DISCONN_COMPLETE)
#define hci_connect_ok (hci_event_flag & HCI_FLAG_CONNECT_OK)
#define hci_inquiry_complete (hci_event_flag & HCI_FLAG_INQUIRY_COMPLETE)
#define hci_remote_name_complete (hci_event_flag & HCI_FLAG_REMOTE_NAME_COMPLETE)
#define hci_incoming_connect_request (hci_event_flag & HCI_FLAG_INCOMING_REQUEST)

3. Sending HCI Commands

To send HCI commands such as HCI reset we send a class specific output via the control pipe

// used in control endpoint header for HCI Commands
#define bmREQ_HCI_OUT  USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
#define HCI_COMMAND_REQ    0  
void hci_reset(void)
{
   hci_event_flag = 0; // clear all the flags
   buf[0] = 0x03;
   buf[1] = 0x0c;
   buf[2] = 0x00;
   HCI_Command(3 , buf);
  return;
}
//perform HCI Command
byte HCI_Command( unsigned int nbytes, char* dataptr ) {
    hci_command_packets--; 
    hci_event_flag &= ~HCI_FLAG_CMD_COMPLETE;
    return( Usb.ctrlReq( BT_ADDR, ep_record[ CONTROL_PIPE ].epAddr, bmREQ_HCI_OUT, HCI_COMMAND_REQ, 0x00, 0x00 ,0, nbytes, dataptr ));
}

4. Bluetooth HCI Utility
Our first sketch to access the Bluetooth dongle will be a utility to gather data from the Bluetooth dongle itself and also to make Bluetooth inquires and connections. The sketch is structured as a state machine to maintain non blocking behavior and so enable the event task to run regularly. The blueutils sketch is loaded into the Arduino, and a CSR bluetooth dongle connected to the USB shield. Running the sketch returns the following over the serial port:

freeMemory() reports:   1513
CSR Initialized
HCI Reset complete
ACL Data Packet Length: 672
SCO Data Packet Length: 48
Total ACL Data Packets: 4
Total SCO Data Packets: 1
HCI Version:            3
HCI Revision:           3164
LMP Version:            3
Manufacturer Id:        10
LMP Subversion:         3164
Local Name:
Local Bluetooth Address:  00158316C075
Search for devices
Search complete
Devices Found :         0
Wait for Incoming Connect Request

This confirms we are talking to the dongle and gives useful information especially the bluetooth address hardcoded into the dongle.

5. Connecting Wiimote Game Controller
The connection process is different for the Wiimote and the PS3, so we will look at these in turn.

The wiimote has two methods of connection know as soft connect and hard connect. We look at the soft connect mode here. In soft connect mode a connection is made from the Arduino to the Wiimote, and to enable this the Bluetooth address of the wiimote must be discovered.

The blueutils sketch is run again, and when the message comes on the serial port of “Search for devices”, the “1″ and “2″ buttons on the Wiimote are pressed simultaneously. The search will take about 10 seconds and at the end return something similar to:

freeMemory() reports: 1513
CSR Initialized
HCI Reset complete
ACL Data Packet Length: 672
SCO Data Packet Length: 48
Total ACL Data Packets: 4
Total SCO Data Packets: 1
HCI Version:            3
HCI Revision:           3164
LMP Version:            3
Manufacturer Id:        10
LMP Subversion:         3164
Local Name:
Local Bluetooth Address:  00158316C075
Search for devices
Search complete
Devices Found :         1
Found BDADDR: 0022AA8A06A3  Class:  042500  Mode: 1 Offset: 69C9 

Remote Name:  0 Nintendo RVL-CNT-01
Connected to device

Here the Arduino has found the Wiimote and used the discovered Bluetooth Address to make a connection to it.

6. Connecting PS3 Game Controller
The PS3 Game Controller connection process is the other way round. The PS3 controller make the connection to the Arduino. The PS3 controller does not respond to requests for inquiry or connection.

To initate the connection the PS3 controller needs to know the Bluetooth Address of the Arduino. MotioninJoy can be used to set a USB dongle address into the PS3 contoller or alternatively sixpair.c under linux. These read the USB dongle bluetooth address and set this into the PS3 controller.

Since we know the Arduino Bluetooth address from the utility above “Local Bluetooth Address: 00158316C075″ and we have ability using PS3LCD or the PS3 library to set the host Bluetooth Address, we can also use that method.

When the PS3 is programmed with the correct USB dongle Bluetooth address, the following is dsplayed when the “PS” buuton on the PS3 Game Controler is pressed at the “Wait for Incoming Connect Request” prompt.

freeMemory() reports:   1513
CSR Initialized
HCI Reset complete
ACL Data Packet Length: 672
SCO Data Packet Length: 48
Total ACL Data Packets: 4
Total SCO Data Packets: 1
HCI Version:            3
HCI Revision:           3164
LMP Version:            3
Manufacturer Id:        10
LMP Subversion:         3164
Local Name:
Local Bluetooth Address:  00158316C075
Search for devices
Search complete
Devices Found :         0
Wait for Incoming Connect Request
Connected to device

Related posts:

  1. PS3 and Wiimote Game Controllers on the Arduino Host Shield: Part 2
  2. PS3 and Wiimote Game Controllers on the Arduino Host Shield: Part 1
  3. Hook up PS3 controller to USB Host shield
  4. Arduino USB Host – Peripherals.
  5. Arduino USB Host Shield build log. Part 4.
  6. Arduino USB Host Shield build log. Part 3.
  7. Arduino USB Host Shield build log. Part 2.
  8. Arduino USB Host Shield build log. Part 1.
  9. USB Host Shield for Arduino – first prototype.
  10. Arduino USB Host – USB Descriptors.

2 comments to PS3 and Wiimote Game Controllers on the Arduino Host Shield: Part 3

  • Rui

    Absolutely fantastic articles! When will parts 4 and 5 be avaiable? Great work! :)

  • Sam

    Hi. I’m in my school’s robotics club and we’re following these guides to try and sync up a PS3 controller to an arduino board to control our robot. We have got the PS3LCD sketch to compile (finally) and now have absolutely no idea where to connect the pins? Is there a clear picture of how to connect it all up? We really need to know just what pins to plug into where from where and all that.

    Any help would be incredibly appreciated. :)
    Thanks so much and keep up the good work.
    Sam.

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">