mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
Added support for Wiimote
This commit is contained in:
parent
c8de94a060
commit
a3ad5f2cdd
9 changed files with 816 additions and 43 deletions
211
BTD.cpp
211
BTD.cpp
|
@ -38,7 +38,9 @@ bPollEnable(false) // Don't start polling before dongle is connected
|
|||
}
|
||||
|
||||
if (pUsb) // register in USB subsystem
|
||||
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
|
||||
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
|
||||
|
||||
wiiServiceID = -1;
|
||||
}
|
||||
|
||||
uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
|
@ -325,7 +327,7 @@ void BTD::HCI_event_task() {
|
|||
{
|
||||
switch (hcibuf[0]) //switch on event type
|
||||
{
|
||||
case EV_COMMAND_COMPLETE:
|
||||
case EV_COMMAND_COMPLETE:
|
||||
if (!hcibuf[5]) { // Check if command succeeded
|
||||
hci_event_flag |= HCI_FLAG_CMD_COMPLETE; // set command complete flag
|
||||
if((hcibuf[3] == 0x01) && (hcibuf[4] == 0x10)) { // parameters from read local version information
|
||||
|
@ -352,11 +354,51 @@ void BTD::HCI_event_task() {
|
|||
}
|
||||
break;
|
||||
|
||||
case EV_INQUIRY_COMPLETE: // We don't use this for anything
|
||||
break;
|
||||
|
||||
case EV_INQUIRY_RESULT:
|
||||
if (hcibuf[2]) { // Check that there is more than zero responses
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nNumber of responses: "));
|
||||
Serial.print(hcibuf[2]);
|
||||
#endif
|
||||
for(uint8_t i = 0; i < hcibuf[2]; i++) {
|
||||
if(hcibuf[4+8*hcibuf[2]+3*i] == 0x04 && hcibuf[5+8*hcibuf[2]+3*i] == 0x25 && hcibuf[6+8*hcibuf[2]+3*i] == 0x00) { // See http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html
|
||||
disc_bdaddr[0] = hcibuf[3+6*i];
|
||||
disc_bdaddr[1] = hcibuf[4+6*i];
|
||||
disc_bdaddr[2] = hcibuf[5+6*i];
|
||||
disc_bdaddr[3] = hcibuf[6+6*i];
|
||||
disc_bdaddr[4] = hcibuf[7+6*i];
|
||||
disc_bdaddr[5] = hcibuf[8+6*i];
|
||||
hci_event_flag |= HCI_FLAG_WII_FOUND;
|
||||
break;
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
else {
|
||||
Notify(PSTR("\r\nClass of device: "));
|
||||
PrintHex<uint8_t>(hcibuf[6+8*hcibuf[2]+3*i]);
|
||||
Notify(PSTR(" "));
|
||||
PrintHex<uint8_t>(hcibuf[5+8*hcibuf[2]+3*i]);
|
||||
Notify(PSTR(" "));
|
||||
PrintHex<uint8_t>(hcibuf[4+8*hcibuf[2]+3*i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_CONNECT_COMPLETE:
|
||||
hci_event_flag |= HCI_FLAG_CONNECT_EVENT;
|
||||
if (!hcibuf[2]) { // check if connected OK
|
||||
hci_handle = hcibuf[3] | hcibuf[4] << 8; // store the handle for the ACL connection
|
||||
hci_handle = hcibuf[3] | ((hcibuf[4] & 0x0F) << 8); // store the handle for the ACL connection
|
||||
hci_event_flag |= HCI_FLAG_CONN_COMPLETE; // set connection complete flag
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
else {
|
||||
Notify(PSTR("\r\nConnection Failed"));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case EV_DISCONNECT_COMPLETE:
|
||||
|
@ -479,7 +521,7 @@ void BTD::HCI_task() {
|
|||
Notify(PSTR("\r\nLocal Bluetooth Address: "));
|
||||
for(int8_t i = 5; i > 0;i--) {
|
||||
PrintHex<uint8_t>(my_bdaddr[i]);
|
||||
Serial.print(":");
|
||||
Notify(PSTR(":"));
|
||||
}
|
||||
PrintHex<uint8_t>(my_bdaddr[0]);
|
||||
#endif
|
||||
|
@ -494,7 +536,7 @@ void BTD::HCI_task() {
|
|||
hci_set_local_name(btdName);
|
||||
hci_state = HCI_SET_NAME_STATE;
|
||||
} else
|
||||
hci_state = HCI_SCANNING_STATE;
|
||||
hci_state = HCI_CHECK_WII_SERVICE;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -504,17 +546,82 @@ void BTD::HCI_task() {
|
|||
Notify(PSTR("\r\nThe name is set to: "));
|
||||
Serial.print(btdName);
|
||||
#endif
|
||||
hci_state = HCI_SCANNING_STATE;
|
||||
hci_state = HCI_CHECK_WII_SERVICE;
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_CHECK_WII_SERVICE:
|
||||
if(wiiServiceID != -1) { // Check if it should try to connect to a wiimote
|
||||
if(disc_bdaddr[5] == 0 && disc_bdaddr[4] == 0 && disc_bdaddr[3] == 0 && disc_bdaddr[2] == 0 && disc_bdaddr[1] == 0 && disc_bdaddr[0] == 0) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nStarting inquiry\r\nPress A & B on the Wiimote"));
|
||||
#endif
|
||||
hci_inquiry();
|
||||
hci_state = HCI_INQUIRY_STATE;
|
||||
}
|
||||
else
|
||||
hci_state = HCI_CONNECT_WII_STATE;
|
||||
}
|
||||
else
|
||||
hci_state = HCI_SCANNING_STATE; // Don't try to connect to a Wiimote
|
||||
break;
|
||||
|
||||
case HCI_INQUIRY_STATE:
|
||||
if(hci_wii_found) {
|
||||
hci_inquiry_cancel(); // Stop inquiry
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nWiimote found"));
|
||||
Notify(PSTR("\r\nCreate the instance like so to connect automatically:"));
|
||||
Notify(PSTR("\r\nWII Wii(&Btd,"));
|
||||
for(int8_t i = 5; i>0;i--) {
|
||||
Notify(PSTR("0x"));
|
||||
PrintHex<uint8_t>(disc_bdaddr[i]);
|
||||
Notify(PSTR(","));
|
||||
}
|
||||
Notify(PSTR("0x"));
|
||||
PrintHex<uint8_t>(disc_bdaddr[0]);
|
||||
Notify(PSTR(");"));
|
||||
#endif
|
||||
hci_state = HCI_CONNECT_WII_STATE;
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_CONNECT_WII_STATE:
|
||||
if(!hci_wii_found || hci_cmd_complete) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nConnecting to Wiimote"));
|
||||
#endif
|
||||
hci_connect();
|
||||
hci_state = HCI_CONNECTED_WII_STATE;
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_CONNECTED_WII_STATE:
|
||||
if(hci_connect_event) {
|
||||
if(hci_connect_complete) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nConnected to Wiimote"));
|
||||
#endif
|
||||
connectToWii = true; // Only send the ACL data to the Wii service
|
||||
hci_state = HCI_SCANNING_STATE;
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nTrying to connect one more time..."));
|
||||
#endif
|
||||
hci_connect(); // Try to connect one more time
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_SCANNING_STATE:
|
||||
if(!connectToWii) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nWait For Incoming Connection Request"));
|
||||
Notify(PSTR("\r\nWait For Incoming Connection Request"));
|
||||
#endif
|
||||
hci_write_scan_enable();
|
||||
watingForConnection = true;
|
||||
hci_state = HCI_CONNECT_IN_STATE;
|
||||
hci_write_scan_enable();
|
||||
watingForConnection = true;
|
||||
hci_state = HCI_CONNECT_IN_STATE;
|
||||
}
|
||||
break;
|
||||
|
||||
case HCI_CONNECT_IN_STATE:
|
||||
|
@ -533,8 +640,7 @@ void BTD::HCI_task() {
|
|||
if(hci_remote_name_complete) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nRemote Name: "));
|
||||
for (uint8_t i = 0; i < 30; i++)
|
||||
{
|
||||
for (uint8_t i = 0; i < 30; i++) {
|
||||
if(remote_name[i] == NULL)
|
||||
break;
|
||||
Serial.write(remote_name[i]);
|
||||
|
@ -549,10 +655,9 @@ void BTD::HCI_task() {
|
|||
if (hci_connect_complete) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nConnected to Device: "));
|
||||
for(int8_t i = 5; i>0;i--)
|
||||
{
|
||||
for(int8_t i = 5; i>0;i--) {
|
||||
PrintHex<uint8_t>(disc_bdaddr[i]);
|
||||
Serial.print(":");
|
||||
Notify(PSTR(":"));
|
||||
}
|
||||
PrintHex<uint8_t>(disc_bdaddr[0]);
|
||||
#endif
|
||||
|
@ -604,9 +709,13 @@ void BTD::ACL_event_task() {
|
|||
uint16_t MAX_BUFFER_SIZE = BULK_MAXPKTSIZE;
|
||||
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_DATAIN_PIPE ].epAddr, &MAX_BUFFER_SIZE, l2capinbuf); // input on endpoint 2
|
||||
if(!rcode) { // Check for errors
|
||||
for (uint8_t i=0; i<BTD_NUMSERVICES; i++)
|
||||
if (btService[i])
|
||||
btService[i]->ACLData(l2capinbuf);
|
||||
if(connectToWii) // Only send the data to the Wii service
|
||||
btService[wiiServiceID]->ACLData(l2capinbuf);
|
||||
else {
|
||||
for (uint8_t i=0; i<BTD_NUMSERVICES; i++)
|
||||
if (btService[i])
|
||||
btService[i]->ACLData(l2capinbuf);
|
||||
}
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
else if (rcode != hrNAK) {
|
||||
|
@ -664,6 +773,7 @@ void BTD::hci_read_local_version_information() {
|
|||
HCI_Command(hcibuf, 3);
|
||||
}
|
||||
void BTD::hci_accept_connection() {
|
||||
hci_event_flag &= ~HCI_FLAG_CONN_COMPLETE;
|
||||
hcibuf[0] = 0x09; // HCI OCF = 9
|
||||
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
|
||||
hcibuf[2] = 0x07; // parameter length 7
|
||||
|
@ -706,6 +816,47 @@ void BTD::hci_set_local_name(const char* name) {
|
|||
|
||||
HCI_Command(hcibuf, 4+strlen(name));
|
||||
}
|
||||
void BTD::hci_inquiry() {
|
||||
hci_event_flag &= ~HCI_FLAG_WII_FOUND;
|
||||
hcibuf[0] = 0x01;
|
||||
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
|
||||
hcibuf[2] = 0x05; // Parameter Total Length = 5
|
||||
hcibuf[3] = 0x33; // LAP: Genera/Unlimited Inquiry Access Code (GIAC = 0x9E8B33) - see https://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
|
||||
hcibuf[4] = 0x8B;
|
||||
hcibuf[5] = 0x9E;
|
||||
hcibuf[6] = 0x0A; // Inquiry time = 12.8 sec
|
||||
hcibuf[7] = 0x03; // 3 number of responses
|
||||
|
||||
HCI_Command(hcibuf, 8);
|
||||
}
|
||||
void BTD::hci_inquiry_cancel() {
|
||||
hcibuf[0] = 0x02;
|
||||
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
|
||||
hcibuf[2] = 0x0; // Parameter Total Length = 0
|
||||
|
||||
HCI_Command(hcibuf, 3);
|
||||
}
|
||||
void BTD::hci_connect() {
|
||||
hci_event_flag &= ~(HCI_FLAG_CONN_COMPLETE | HCI_FLAG_CONNECT_EVENT);
|
||||
hcibuf[0] = 0x05;
|
||||
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
|
||||
hcibuf[2] = 0x0D; // parameter Total Length = 13
|
||||
hcibuf[3] = disc_bdaddr[0]; // 6 octet bdaddr
|
||||
hcibuf[4] = disc_bdaddr[1];
|
||||
hcibuf[5] = disc_bdaddr[2];
|
||||
hcibuf[6] = disc_bdaddr[3];
|
||||
hcibuf[7] = disc_bdaddr[4];
|
||||
hcibuf[8] = disc_bdaddr[5];
|
||||
hcibuf[9] = 0x18; // DM1 or DH1 may be used
|
||||
hcibuf[10] = 0xCC; // DM3, DH3, DM5, DH5 may be used
|
||||
hcibuf[11] = 0x01; // Page repetition mode R1
|
||||
hcibuf[12] = 0x00; // Reserved
|
||||
hcibuf[13] = 0x00; // Clock offset
|
||||
hcibuf[14] = 0x00; // Invalid clock offset
|
||||
hcibuf[15] = 0x00; // Do not allow role switch
|
||||
|
||||
HCI_Command(hcibuf, 16);
|
||||
}
|
||||
void BTD::hci_pin_code_request_reply(const char* key) {
|
||||
hcibuf[0] = 0x0D; // HCI OCF = 0D
|
||||
hcibuf[1] = 0x01 << 2; // HCI OGF = 1
|
||||
|
@ -814,6 +965,18 @@ void BTD::L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t
|
|||
#endif
|
||||
}
|
||||
}
|
||||
void BTD::l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm) {
|
||||
l2capoutbuf[0] = L2CAP_CMD_CONNECTION_REQUEST; // Code
|
||||
l2capoutbuf[1] = rxid; // Identifier
|
||||
l2capoutbuf[2] = 0x04; // Length
|
||||
l2capoutbuf[3] = 0x00;
|
||||
l2capoutbuf[4] = (uint8_t)(psm & 0xff); // PSM
|
||||
l2capoutbuf[5] = (uint8_t)(psm >> 8);
|
||||
l2capoutbuf[6] = scid[0]; // Source CID
|
||||
l2capoutbuf[7] = scid[1];
|
||||
|
||||
L2CAP_Command(handle, l2capoutbuf, 8);
|
||||
}
|
||||
void BTD::l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result) {
|
||||
l2capoutbuf[0] = L2CAP_CMD_CONNECTION_RESPONSE; // Code
|
||||
l2capoutbuf[1] = rxid; // Identifier
|
||||
|
@ -856,7 +1019,7 @@ void BTD::l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid) {
|
|||
l2capoutbuf[6] = 0x00; // Flag
|
||||
l2capoutbuf[7] = 0x00;
|
||||
l2capoutbuf[8] = 0x00; // Result
|
||||
l2capoutbuf[9] = 0x00;
|
||||
l2capoutbuf[9] = 0x00;
|
||||
l2capoutbuf[10] = 0x01; // Config
|
||||
l2capoutbuf[11] = 0x02;
|
||||
l2capoutbuf[12] = 0xA0;
|
||||
|
@ -915,10 +1078,9 @@ void BTD::setBdaddr(uint8_t* BDADDR) {
|
|||
pUsb->ctrlReq(bAddress,epInfo[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL);
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nBluetooth Address was set to: "));
|
||||
for(int8_t i = 5; i > 0; i--)
|
||||
{
|
||||
for(int8_t i = 5; i > 0; i--) {
|
||||
PrintHex<uint8_t>(my_bdaddr[i]);
|
||||
Serial.print(":");
|
||||
Notify(PSTR(":"));
|
||||
}
|
||||
PrintHex<uint8_t>(my_bdaddr[0]);
|
||||
#endif
|
||||
|
@ -939,10 +1101,9 @@ void BTD::setMoveBdaddr(uint8_t* BDADDR) {
|
|||
pUsb->ctrlReq(bAddress,epInfo[BTD_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00,11,11, buf, NULL);
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nBluetooth Address was set to: "));
|
||||
for(int8_t i = 5; i > 0; i--)
|
||||
{
|
||||
for(int8_t i = 5; i > 0; i--) {
|
||||
PrintHex<uint8_t>(my_bdaddr[i]);
|
||||
Serial.print(":");
|
||||
Notify(PSTR(":"));
|
||||
}
|
||||
PrintHex<uint8_t>(my_bdaddr[0]);
|
||||
#endif
|
||||
|
|
41
BTD.h
41
BTD.h
|
@ -42,13 +42,19 @@
|
|||
#define HCI_BDADDR_STATE 2
|
||||
#define HCI_LOCAL_VERSION_STATE 3
|
||||
#define HCI_SET_NAME_STATE 4
|
||||
#define HCI_SCANNING_STATE 5
|
||||
#define HCI_CONNECT_IN_STATE 6
|
||||
#define HCI_REMOTE_NAME_STATE 7
|
||||
#define HCI_CONNECTED_STATE 8
|
||||
#define HCI_DISABLE_SCAN_STATE 9
|
||||
#define HCI_DONE_STATE 10
|
||||
#define HCI_DISCONNECT_STATE 11
|
||||
#define HCI_CHECK_WII_SERVICE 5
|
||||
|
||||
#define HCI_INQUIRY_STATE 6 // These three states are only used if it should connect to a Wii controller
|
||||
#define HCI_CONNECT_WII_STATE 7
|
||||
#define HCI_CONNECTED_WII_STATE 8
|
||||
|
||||
#define HCI_SCANNING_STATE 9
|
||||
#define HCI_CONNECT_IN_STATE 10
|
||||
#define HCI_REMOTE_NAME_STATE 11
|
||||
#define HCI_CONNECTED_STATE 12
|
||||
#define HCI_DISABLE_SCAN_STATE 13
|
||||
#define HCI_DONE_STATE 14
|
||||
#define HCI_DISCONNECT_STATE 15
|
||||
|
||||
/* HCI event flags*/
|
||||
#define HCI_FLAG_CMD_COMPLETE 0x01
|
||||
|
@ -58,6 +64,8 @@
|
|||
#define HCI_FLAG_INCOMING_REQUEST 0x10
|
||||
#define HCI_FLAG_READ_BDADDR 0x20
|
||||
#define HCI_FLAG_READ_VERSION 0x40
|
||||
#define HCI_FLAG_WII_FOUND 0x80
|
||||
#define HCI_FLAG_CONNECT_EVENT 0x100
|
||||
|
||||
/*Macros for HCI event flag tests */
|
||||
#define hci_cmd_complete (hci_event_flag & HCI_FLAG_CMD_COMPLETE)
|
||||
|
@ -67,8 +75,12 @@
|
|||
#define hci_incoming_connect_request (hci_event_flag & HCI_FLAG_INCOMING_REQUEST)
|
||||
#define hci_read_bdaddr_complete (hci_event_flag & HCI_FLAG_READ_BDADDR)
|
||||
#define hci_read_version_complete (hci_event_flag & HCI_FLAG_READ_VERSION)
|
||||
#define hci_wii_found (hci_event_flag & HCI_FLAG_WII_FOUND)
|
||||
#define hci_connect_event (hci_event_flag & HCI_FLAG_CONNECT_EVENT)
|
||||
|
||||
/* HCI Events managed */
|
||||
#define EV_INQUIRY_COMPLETE 0x01
|
||||
#define EV_INQUIRY_RESULT 0x02
|
||||
#define EV_CONNECT_COMPLETE 0x03
|
||||
#define EV_INCOMING_CONNECT 0x04
|
||||
#define EV_DISCONNECT_COMPLETE 0x05
|
||||
|
@ -105,6 +117,12 @@
|
|||
#define PENDING 0x01
|
||||
#define SUCCESSFUL 0x00
|
||||
|
||||
/* Bluetooth L2CAP PSM - see http://www.bluetooth.org/Technical/AssignedNumbers/logical_link.htm */
|
||||
#define SDP_PSM 0x01 // Service Discovery Protocol PSM Value
|
||||
#define RFCOMM_PSM 0x03 // RFCOMM PSM Value
|
||||
#define HID_CTRL_PSM 0x11 // HID_Control PSM Value
|
||||
#define HID_INTR_PSM 0x13 // HID_Interrupt PSM Value
|
||||
|
||||
// Used to determine if it is a Bluetooth dongle
|
||||
#define WI_SUBCLASS_RF 0x01 // RF Controller
|
||||
#define WI_PROTOCOL_BT 0x01 // Bluetooth Programming Interface
|
||||
|
@ -163,6 +181,9 @@ public:
|
|||
uint8_t remote_name[30]; // First 30 chars of last remote name
|
||||
uint8_t hci_version;
|
||||
|
||||
int8_t wiiServiceID; // Stores the service ID of the Wii service
|
||||
bool connectToWii; // Used to only send the ACL data to the wiimote
|
||||
|
||||
/* HCI Commands */
|
||||
void HCI_Command(uint8_t* data, uint16_t nbytes);
|
||||
void hci_reset();
|
||||
|
@ -177,9 +198,13 @@ public:
|
|||
void hci_pin_code_request_reply(const char* key);
|
||||
void hci_pin_code_negative_request_reply();
|
||||
void hci_link_key_request_negative_reply();
|
||||
void hci_inquiry();
|
||||
void hci_inquiry_cancel();
|
||||
void hci_connect();
|
||||
|
||||
/* L2CAP Commands */
|
||||
void L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow = 0x01, uint8_t channelHigh = 0x00); // Standard L2CAP header: Channel ID (0x01) for ACL-U
|
||||
void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm);
|
||||
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result);
|
||||
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid);
|
||||
void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid);
|
||||
|
@ -214,7 +239,7 @@ private:
|
|||
uint8_t hci_state; //current state of bluetooth hci connection
|
||||
uint16_t hci_counter; // counter used for bluetooth hci reset loops
|
||||
uint8_t hci_num_reset_loops; // this value indicate how many times it should read before trying to reset
|
||||
uint16_t hci_event_flag; // hci flags of received bluetooth events
|
||||
uint16_t hci_event_flag; // hci flags of received bluetooth events
|
||||
|
||||
uint8_t hcibuf[BULK_MAXPKTSIZE];//General purpose buffer for hci data
|
||||
uint8_t l2capinbuf[BULK_MAXPKTSIZE];//General purpose buffer for l2cap in data
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
The BTD.cpp, BTD.h, SPP.cpp, SPP.h, PS3BT.cpp, PS3BT.h, PS3USB.cpp, PS3USB.h, XBOXUSB.cpp, and XBOXUSB.h is developed by Kristian Lauszus
|
||||
The BTD.cpp, BTD.h, SPP.cpp, SPP.h, PS3BT.cpp, PS3BT.h, Wii.cpp, Wii.h PS3USB.cpp, PS3USB.h, XBOXUSB.cpp, and XBOXUSB.h is developed by Kristian Lauszus
|
||||
|
||||
For more information regarding the PS3 protocol etc. visit my blog at: http://blog.tkjelectronics.dk/ or send me an email at kristianl at tkjelectronics dot dk.
|
||||
You could also visit the official wiki: https://github.com/TKJElectronics/USB_Host_Shield_2.0/wiki for information.
|
||||
|
@ -26,4 +26,7 @@ http://pingus.seul.org/~grumbel/xboxdrv/
|
|||
To implement the RFCOMM protocol I used a bluetooth sniffing tool called PacketLogger developed by Apple.
|
||||
It enables me to see the bluetooth communication between my Mac and any device.
|
||||
|
||||
All the information about the Wii controller is from this site: http://wiibrew.org/wiki/Wiimote
|
||||
And the old Wii library created by Moyuchin: https://github.com/moyuchin/WiiRemote_on_Arduino
|
||||
|
||||
And at last I would like to thank Oleg from http://www.circuitsathome.com/ for making such an awesome shield!
|
4
PS3BT.h
4
PS3BT.h
|
@ -56,10 +56,6 @@
|
|||
#define l2cap_disconnect_response_control_flag (l2cap_event_flag & L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE)
|
||||
#define l2cap_disconnect_response_interrupt_flag (l2cap_event_flag & L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE)
|
||||
|
||||
/* Bluetooth L2CAP PSM */
|
||||
#define HID_CTRL_PSM 0x11 // HID_Control
|
||||
#define HID_INTR_PSM 0x13 // HID_Interrupt
|
||||
|
||||
enum LED {
|
||||
LED1 = 0x01,
|
||||
LED2 = 0x02,
|
||||
|
|
4
SPP.h
4
SPP.h
|
@ -55,10 +55,6 @@
|
|||
#define l2cap_disconnect_request_rfcomm_flag (l2cap_event_flag & L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST)
|
||||
#define l2cap_disconnect_response_flag (l2cap_event_flag & L2CAP_FLAG_DISCONNECT_RESPONSE)
|
||||
|
||||
/* Bluetooth L2CAP PSM */
|
||||
#define SDP_PSM 0x01 // Service Discovery Protocol PSM Value
|
||||
#define RFCOMM_PSM 0x03 // RFCOMM PSM Value
|
||||
|
||||
/* Used for SDP */
|
||||
#define SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST_PDU 0x06 // See the RFCOMM specs
|
||||
#define SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE_PDU 0x07 // See the RFCOMM specs
|
||||
|
|
359
Wii.cpp
Normal file
359
Wii.cpp
Normal file
|
@ -0,0 +1,359 @@
|
|||
/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
|
||||
|
||||
This software may be distributed and modified under the terms of the GNU
|
||||
General Public License version 2 (GPL2) as published by the Free Software
|
||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||
on this software must also be made publicly available under the terms of
|
||||
the GPL2 ("Copyleft").
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Kristian Lauszus, TKJ Electronics
|
||||
Web : http://www.tkjelectronics.com
|
||||
e-mail : kristianl@tkjelectronics.com
|
||||
*/
|
||||
|
||||
#include "Wii.h"
|
||||
#define DEBUG // Uncomment to print data for debugging
|
||||
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
||||
//#define PRINTREPORT // Uncomment to print the report send by the Wiimote
|
||||
|
||||
WII::WII(BTD *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0):
|
||||
pBtd(p) // pointer to USB class instance - mandatory
|
||||
{
|
||||
if (pBtd)
|
||||
pBtd->wiiServiceID = pBtd->registerServiceClass(this); // Register it as a Bluetooth service
|
||||
|
||||
pBtd->disc_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead
|
||||
pBtd->disc_bdaddr[4] = btadr4;
|
||||
pBtd->disc_bdaddr[3] = btadr3;
|
||||
pBtd->disc_bdaddr[2] = btadr2;
|
||||
pBtd->disc_bdaddr[1] = btadr1;
|
||||
pBtd->disc_bdaddr[0] = btadr0;
|
||||
|
||||
HIDBuffer[0] = 0xA2;// HID BT DATA_request (0x50) | Report Type (Output 0x02)
|
||||
|
||||
/* Set device cid for the control and intterrupt channelse - LSB */
|
||||
control_dcid[0] = 0x60;//0x0060
|
||||
control_dcid[1] = 0x00;
|
||||
interrupt_dcid[0] = 0x61;//0x0061
|
||||
interrupt_dcid[1] = 0x00;
|
||||
|
||||
Reset();
|
||||
}
|
||||
void WII::Reset() {
|
||||
connected = false;
|
||||
l2cap_event_flag = 0; // Reset flags
|
||||
l2cap_state = L2CAP_WAIT;
|
||||
}
|
||||
|
||||
void WII::disconnect() { // Use this void to disconnect any of the controllers
|
||||
//First the HID interrupt channel has to be disconencted, then the HID control channel and finally the HCI connection
|
||||
pBtd->l2cap_disconnection_request(hci_handle,0x0A, interrupt_scid, interrupt_dcid);
|
||||
Reset();
|
||||
l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
|
||||
}
|
||||
|
||||
void WII::ACLData(uint8_t* l2capinbuf) {
|
||||
if (((l2capinbuf[0] | (l2capinbuf[1] << 8)) == (hci_handle | 0x2000))) { //acl_handle_ok
|
||||
if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { //l2cap_control - Channel ID for ACL-U
|
||||
if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "));
|
||||
PrintHex<uint8_t>(l2capinbuf[13]);
|
||||
Notify(PSTR(" "));
|
||||
PrintHex<uint8_t>(l2capinbuf[12]);
|
||||
Notify(PSTR(" "));
|
||||
PrintHex<uint8_t>(l2capinbuf[17]);
|
||||
Notify(PSTR(" "));
|
||||
PrintHex<uint8_t>(l2capinbuf[16]);
|
||||
Notify(PSTR(" "));
|
||||
PrintHex<uint8_t>(l2capinbuf[15]);
|
||||
Notify(PSTR(" "));
|
||||
PrintHex<uint8_t>(l2capinbuf[14]);
|
||||
#endif
|
||||
}
|
||||
else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
|
||||
if (((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success
|
||||
if (l2capinbuf[14] == control_dcid[0] && l2capinbuf[15] == control_dcid[1]) { // Success
|
||||
//Serial.print("\r\nHID Control Connection Complete");
|
||||
identifier = l2capinbuf[9];
|
||||
control_scid[0] = l2capinbuf[12];
|
||||
control_scid[1] = l2capinbuf[13];
|
||||
l2cap_event_flag |= L2CAP_FLAG_CONTROL_CONNECTED;
|
||||
}
|
||||
else if (l2capinbuf[14] == interrupt_dcid[0] && l2capinbuf[15] == interrupt_dcid[1]) {
|
||||
//Serial.print("\r\nHID Interrupt Connection Complete");
|
||||
identifier = l2capinbuf[9];
|
||||
interrupt_scid[0] = l2capinbuf[12];
|
||||
interrupt_scid[1] = l2capinbuf[13];
|
||||
l2cap_event_flag |= L2CAP_FLAG_INTERRUPT_CONNECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_RESPONSE) {
|
||||
if ((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) { // Success
|
||||
if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
||||
//Serial.print("\r\nHID Control Configuration Complete");
|
||||
identifier = l2capinbuf[9];
|
||||
l2cap_event_flag |= L2CAP_FLAG_CONFIG_CONTROL_SUCCESS;
|
||||
}
|
||||
else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
|
||||
//Serial.print("\r\nHID Interrupt Configuration Complete");
|
||||
identifier = l2capinbuf[9];
|
||||
l2cap_event_flag |= L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (l2capinbuf[8] == L2CAP_CMD_CONFIG_REQUEST) {
|
||||
if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
||||
//Serial.print("\r\nHID Control Configuration Request");
|
||||
pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], control_scid);
|
||||
}
|
||||
else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
|
||||
//Serial.print("\r\nHID Interrupt Configuration Request");
|
||||
pBtd->l2cap_config_response(hci_handle, l2capinbuf[9], interrupt_scid);
|
||||
}
|
||||
}
|
||||
else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
|
||||
if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nDisconnect Request: Control Channel"));
|
||||
#endif
|
||||
connected = false;
|
||||
identifier = l2capinbuf[9];
|
||||
pBtd->l2cap_disconnection_response(hci_handle,identifier,control_dcid,control_scid);
|
||||
Reset();
|
||||
}
|
||||
else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"));
|
||||
#endif
|
||||
connected = false;
|
||||
identifier = l2capinbuf[9];
|
||||
pBtd->l2cap_disconnection_response(hci_handle,identifier,interrupt_dcid,interrupt_scid);
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_RESPONSE) {
|
||||
if (l2capinbuf[12] == control_scid[0] && l2capinbuf[13] == control_scid[1]) {
|
||||
//Serial.print("\r\nDisconnect Response: Control Channel");
|
||||
identifier = l2capinbuf[9];
|
||||
l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE;
|
||||
}
|
||||
else if (l2capinbuf[12] == interrupt_scid[0] && l2capinbuf[13] == interrupt_scid[1]) {
|
||||
//Serial.print("\r\nDisconnect Response: Interrupt Channel");
|
||||
identifier = l2capinbuf[9];
|
||||
l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE;
|
||||
}
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
else {
|
||||
identifier = l2capinbuf[9];
|
||||
Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "));
|
||||
PrintHex<uint8_t>(l2capinbuf[8]);
|
||||
}
|
||||
#endif
|
||||
} else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
|
||||
//Serial.print("\r\nL2CAP Interrupt");
|
||||
if(connected) {
|
||||
/* Read Report */
|
||||
if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
|
||||
switch (l2capinbuf[9]) {
|
||||
case 0x30: // Core buttons
|
||||
ButtonState = (uint16_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8));
|
||||
ButtonClickState = ButtonState; // Update click state variable
|
||||
|
||||
#ifdef PRINTREPORT
|
||||
Notify(PSTR("ButtonState: "));
|
||||
PrintHex<uint16_t>(ButtonState);
|
||||
Notify(PSTR("\r\n"));
|
||||
#endif
|
||||
|
||||
if(ButtonState != OldButtonState) {
|
||||
buttonChanged = true;
|
||||
if(ButtonState != 0x0000) {
|
||||
buttonPressed = true;
|
||||
buttonReleased = false;
|
||||
} else {
|
||||
buttonPressed = false;
|
||||
buttonReleased = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
buttonChanged = false;
|
||||
buttonPressed = false;
|
||||
buttonReleased = false;
|
||||
}
|
||||
OldButtonState = ButtonState;
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
default:
|
||||
Notify(PSTR("\r\nUnknown Report type: "));
|
||||
Serial.print(l2capinbuf[9],HEX);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
L2CAP_task();
|
||||
}
|
||||
}
|
||||
void WII::L2CAP_task() {
|
||||
switch (l2cap_state) {
|
||||
case L2CAP_CONTROL_CONNECT_REQUEST:
|
||||
if (l2cap_connected_control_flag) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nSend HID Control Config Request"));
|
||||
#endif
|
||||
identifier++;
|
||||
pBtd->l2cap_config_request(hci_handle, identifier, control_scid);
|
||||
l2cap_state = L2CAP_CONTROL_CONFIG_REQUEST;
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_CONTROL_CONFIG_REQUEST:
|
||||
if(l2cap_config_success_control_flag) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nSend HID Interrupt Connection Request"));
|
||||
#endif
|
||||
identifier++;
|
||||
pBtd->l2cap_connection_request(hci_handle,identifier,interrupt_dcid,HID_INTR_PSM);
|
||||
l2cap_state = L2CAP_INTERRUPT_CONNECT_REQUEST;
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_INTERRUPT_CONNECT_REQUEST:
|
||||
if(l2cap_connected_interrupt_flag) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nSend HID Interrupt Config Request"));
|
||||
#endif
|
||||
identifier++;
|
||||
pBtd->l2cap_config_request(hci_handle, identifier, interrupt_scid);
|
||||
l2cap_state = L2CAP_INTERRUPT_CONFIG_REQUEST;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case L2CAP_INTERRUPT_CONFIG_REQUEST:
|
||||
if(l2cap_config_success_interrupt_flag) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nHID Channels Established"));
|
||||
#endif
|
||||
connected = true;
|
||||
pBtd->connectToWii = false;
|
||||
ButtonState = 0;
|
||||
OldButtonState = 0;
|
||||
ButtonClickState = 0;
|
||||
setLedOn(LED1);
|
||||
l2cap_state = L2CAP_DONE;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
case L2CAP_WIIREMOTE_CAL_STATE:
|
||||
//Todo enable support for Motion Plus
|
||||
break;
|
||||
*/
|
||||
case L2CAP_DONE:
|
||||
break;
|
||||
|
||||
case L2CAP_INTERRUPT_DISCONNECT:
|
||||
if (l2cap_disconnect_response_interrupt_flag) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nDisconnected Interrupt Channel"));
|
||||
#endif
|
||||
identifier++;
|
||||
pBtd->l2cap_disconnection_request(hci_handle, identifier, control_scid, control_dcid);
|
||||
l2cap_state = L2CAP_CONTROL_DISCONNECT;
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_CONTROL_DISCONNECT:
|
||||
if (l2cap_disconnect_response_control_flag) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nDisconnected Control Channel"));
|
||||
#endif
|
||||
pBtd->hci_disconnect(hci_handle);
|
||||
l2cap_event_flag = 0; // Reset flags
|
||||
l2cap_state = L2CAP_WAIT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
void WII::Run() {
|
||||
switch (l2cap_state) {
|
||||
case L2CAP_WAIT:
|
||||
if(pBtd->connectToWii) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nSend HID Control Connection Request"));
|
||||
#endif
|
||||
hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
|
||||
l2cap_event_flag = 0; // Reset flags
|
||||
identifier = 0;
|
||||
pBtd->l2cap_connection_request(hci_handle,identifier,control_dcid,HID_CTRL_PSM);
|
||||
l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
/* HID Commands */
|
||||
/************************************************************/
|
||||
void WII::HID_Command(uint8_t* data, uint8_t nbytes) {
|
||||
pBtd->L2CAP_Command(hci_handle,data,nbytes,control_scid[0],control_scid[1]); // Both the Navigation and Dualshock controller sends data via the control channel
|
||||
}
|
||||
void WII::setAllOff() {
|
||||
HIDBuffer[1] = 0x11;
|
||||
HIDBuffer[2] = 0x00;
|
||||
HID_Command(HIDBuffer, 3);
|
||||
}
|
||||
void WII::setRumbleOff() {
|
||||
HIDBuffer[1] = 0x11;
|
||||
HIDBuffer[2] &= ~0x01; // Bit 0 control the rumble
|
||||
HID_Command(HIDBuffer, 3);
|
||||
}
|
||||
void WII::setRumbleOn() {
|
||||
HIDBuffer[1] = 0x11;
|
||||
HIDBuffer[2] |= 0x01; // Bit 0 control the rumble
|
||||
HID_Command(HIDBuffer, 3);
|
||||
}
|
||||
void WII::setRumbleToggle() {
|
||||
HIDBuffer[1] = 0x11;
|
||||
HIDBuffer[2] ^= 0x01; // Bit 0 control the rumble
|
||||
HID_Command(HIDBuffer, 3);
|
||||
}
|
||||
void WII::setLedOff(LED a) {
|
||||
HIDBuffer[1] = 0x11;
|
||||
HIDBuffer[2] &= ~((uint8_t)a);
|
||||
HID_Command(HIDBuffer, 3);
|
||||
}
|
||||
void WII::setLedOn(LED a) {
|
||||
HIDBuffer[1] = 0x11;
|
||||
HIDBuffer[2] |= (uint8_t)a;
|
||||
HID_Command(HIDBuffer, 3);
|
||||
}
|
||||
void WII::setLedToggle(LED a) {
|
||||
HIDBuffer[1] = 0x11;
|
||||
HIDBuffer[2] ^= (uint8_t)a;
|
||||
HID_Command(HIDBuffer, 3);
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
/* WII Commands */
|
||||
/************************************************************/
|
||||
|
||||
bool WII::getButtonPress(Button b) {
|
||||
if(ButtonState & (uint16_t)b)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
bool WII::getButtonClick(Button b) {
|
||||
bool click = ((ButtonClickState & (uint16_t)b) != 0);
|
||||
ButtonClickState &= ~((uint16_t)b); // clear "click" event
|
||||
return click;
|
||||
}
|
138
Wii.h
Normal file
138
Wii.h
Normal file
|
@ -0,0 +1,138 @@
|
|||
/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
|
||||
|
||||
This software may be distributed and modified under the terms of the GNU
|
||||
General Public License version 2 (GPL2) as published by the Free Software
|
||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||
on this software must also be made publicly available under the terms of
|
||||
the GPL2 ("Copyleft").
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Kristian Lauszus, TKJ Electronics
|
||||
Web : http://www.tkjelectronics.com
|
||||
e-mail : kristianl@tkjelectronics.com
|
||||
*/
|
||||
|
||||
#ifndef _wii_h_
|
||||
#define _wii_h_
|
||||
|
||||
#include "BTD.h"
|
||||
|
||||
/* Bluetooth L2CAP states for L2CAP_task() */
|
||||
#define L2CAP_WAIT 0
|
||||
#define L2CAP_CONTROL_CONNECT_REQUEST 1
|
||||
#define L2CAP_CONTROL_CONFIG_REQUEST 2
|
||||
#define L2CAP_INTERRUPT_CONNECT_REQUEST 3
|
||||
#define L2CAP_INTERRUPT_CONFIG_REQUEST 4
|
||||
//#define L2CAP_WIIREMOTE_CAL_STATE 9 /* TODO: Enable support for Motion Plus */
|
||||
#define L2CAP_DONE 5
|
||||
#define L2CAP_INTERRUPT_DISCONNECT 6
|
||||
#define L2CAP_CONTROL_DISCONNECT 7
|
||||
|
||||
/* L2CAP event flags */
|
||||
#define L2CAP_FLAG_CONTROL_CONNECTED 0x01
|
||||
#define L2CAP_FLAG_INTERRUPT_CONNECTED 0x02
|
||||
#define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS 0x04
|
||||
#define L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS 0x08
|
||||
#define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE 0x40
|
||||
#define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE 0x80
|
||||
|
||||
/*Macros for L2CAP event flag tests */
|
||||
#define l2cap_connected_control_flag (l2cap_event_flag & L2CAP_FLAG_CONTROL_CONNECTED)
|
||||
#define l2cap_connected_interrupt_flag (l2cap_event_flag & L2CAP_FLAG_INTERRUPT_CONNECTED)
|
||||
#define l2cap_config_success_control_flag (l2cap_event_flag & L2CAP_FLAG_CONFIG_CONTROL_SUCCESS)
|
||||
#define l2cap_config_success_interrupt_flag (l2cap_event_flag & L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS)
|
||||
#define l2cap_disconnect_response_control_flag (l2cap_event_flag & L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE)
|
||||
#define l2cap_disconnect_response_interrupt_flag (l2cap_event_flag & L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE)
|
||||
|
||||
enum LED {
|
||||
LED1 = 0x10,
|
||||
LED2 = 0x20,
|
||||
LED3 = 0x40,
|
||||
LED4 = 0x80,
|
||||
|
||||
LED5 = 0x90,
|
||||
LED6 = 0xA0,
|
||||
LED7 = 0xC0,
|
||||
LED8 = 0xD0,
|
||||
LED9 = 0xE0,
|
||||
LED10 = 0xF0,
|
||||
};
|
||||
|
||||
enum Button {
|
||||
LEFT = 0x0001,
|
||||
RIGHT = 0x0002,
|
||||
DOWN = 0x0004,
|
||||
UP = 0x0008,
|
||||
PLUS = 0x0010,
|
||||
|
||||
TWO = 0x0100,
|
||||
ONE = 0x0200,
|
||||
B = 0x0400,
|
||||
A = 0x0800,
|
||||
MINUS = 0x1000,
|
||||
HOME = 0x8000,
|
||||
};
|
||||
|
||||
class WII : public BluetoothService {
|
||||
public:
|
||||
WII(BTD *pBtd, uint8_t btadr5=0, uint8_t btadr4=0, uint8_t btadr3=0, uint8_t btadr2=0, uint8_t btadr1=0, uint8_t btadr0=0);
|
||||
|
||||
// BluetoothService implementation
|
||||
virtual void ACLData(uint8_t* ACLData); // Used to pass acldata to the services
|
||||
virtual void Run(); // Used to run part of the state maschine
|
||||
virtual void Reset(); // Use this to reset the service
|
||||
virtual void disconnect(); // Use this void to disconnect any of the controllers
|
||||
|
||||
bool getButtonPress(Button b); // This will read true as long as the button is held down
|
||||
bool getButtonClick(Button b); // This will only be true when the button is clicked the first time
|
||||
/*
|
||||
TODO: Enable support for Motion Plus
|
||||
int16_t getSensor(Sensor a);
|
||||
double getAngle(Angle a);
|
||||
*/
|
||||
void setAllOff(); // Turn both rumble and all LEDs off
|
||||
void setRumbleOff();
|
||||
void setRumbleOn();
|
||||
void setRumbleToggle();
|
||||
void setLedOff(LED a);
|
||||
void setLedOn(LED a);
|
||||
void setLedToggle(LED a);
|
||||
|
||||
bool connected;// Variable used to indicate if a Wiimote is connected
|
||||
bool buttonChanged;//Indicate if a button has been changed
|
||||
bool buttonPressed;//Indicate if a button has been pressed
|
||||
bool buttonReleased;//Indicate if a button has been released
|
||||
|
||||
private:
|
||||
/* Mandatory members */
|
||||
BTD *pBtd;
|
||||
|
||||
void L2CAP_task(); // L2CAP state machine
|
||||
|
||||
/* Variables filled from HCI event management */
|
||||
uint16_t hci_handle;
|
||||
|
||||
/* variables used by high level L2CAP task */
|
||||
uint8_t l2cap_state;
|
||||
uint16_t l2cap_event_flag;// l2cap flags of received bluetooth events
|
||||
|
||||
uint16_t ButtonState;
|
||||
uint16_t OldButtonState;
|
||||
uint16_t ButtonClickState;
|
||||
|
||||
uint8_t HIDBuffer[3];// Used to store HID commands
|
||||
|
||||
/* L2CAP Channels */
|
||||
uint8_t control_scid[2];// L2CAP source CID for HID_Control
|
||||
uint8_t control_dcid[2];//0x0060
|
||||
uint8_t interrupt_scid[2];// L2CAP source CID for HID_Interrupt
|
||||
uint8_t interrupt_dcid[2];//0x0061
|
||||
uint8_t identifier;//Identifier for connection
|
||||
|
||||
/* HID Commands */
|
||||
void HID_Command(uint8_t* data, uint8_t nbytes);
|
||||
};
|
||||
#endif
|
77
examples/Bluetooth/Wiimote/Wiimote.ino
Normal file
77
examples/Bluetooth/Wiimote/Wiimote.ino
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
Example sketch for the Wiimote Bluetooth library - developed by Kristian Lauszus
|
||||
For more information visit my blog: http://blog.tkjelectronics.dk/ or
|
||||
send me an e-mail: kristianl@tkjelectronics.com
|
||||
*/
|
||||
|
||||
#include <Wii.h>
|
||||
USB Usb;
|
||||
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
|
||||
/* You can create the instance of the class in two ways */
|
||||
WII Wii(&Btd); // This will start inquiry which will connect to any Wiimote
|
||||
//WII Wii(&Btd,0x00,0x26,0x59,0x48,0xFF,0xFB); // This will connect to the Wiimote with that specific Bluetooth Address
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
if (Usb.Init() == -1) {
|
||||
Serial.print(F("\r\nOSC did not start"));
|
||||
while(1); //halt
|
||||
}
|
||||
Serial.print(F("\r\nWiimote Bluetooth Library Started"));
|
||||
}
|
||||
void loop() {
|
||||
Usb.Task();
|
||||
if(Wii.connected) {
|
||||
if(Wii.buttonPressed) {
|
||||
if(Wii.getButtonClick(HOME)) { // You can use getButtonPress to see if the button is held down
|
||||
Serial.print(F("\r\nHOME"));
|
||||
Wii.disconnect(); // If you disconnect you have to reset the Arduino to establish the connection again
|
||||
}
|
||||
else {
|
||||
if(Wii.getButtonClick(LEFT)) {
|
||||
Wii.setAllOff();
|
||||
Wii.setLedOn(LED1);
|
||||
Serial.print(F("\r\nLeft"));
|
||||
}
|
||||
if(Wii.getButtonClick(RIGHT)) {
|
||||
Wii.setAllOff();
|
||||
Wii.setLedOn(LED3);
|
||||
Serial.print(F("\r\nRight"));
|
||||
}
|
||||
if(Wii.getButtonClick(DOWN)) {
|
||||
Wii.setAllOff();
|
||||
Wii.setLedOn(LED4);
|
||||
Serial.print(F("\r\nDown"));
|
||||
}
|
||||
if(Wii.getButtonClick(UP)) {
|
||||
Wii.setAllOff();
|
||||
Wii.setLedOn(LED2);
|
||||
Serial.print(F("\r\nUp"));
|
||||
}
|
||||
|
||||
if(Wii.getButtonClick(PLUS)) {
|
||||
Serial.print(F("\r\nPlus"));
|
||||
}
|
||||
if(Wii.getButtonClick(MINUS)) {
|
||||
Serial.print(F("\r\nMinus"));
|
||||
}
|
||||
|
||||
if(Wii.getButtonClick(ONE)) {
|
||||
Serial.print(F("\r\nOne"));
|
||||
}
|
||||
if(Wii.getButtonClick(TWO)) {
|
||||
Serial.print(F("\r\nTwo"));
|
||||
}
|
||||
|
||||
if(Wii.getButtonClick(A)) {
|
||||
Serial.print(F("\r\nA"));
|
||||
}
|
||||
if(Wii.getButtonClick(B)) {
|
||||
Wii.setRumbleToggle();
|
||||
Serial.print(F("\r\nB"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
20
keywords.txt
20
keywords.txt
|
@ -201,4 +201,22 @@ SPP KEYWORD1
|
|||
|
||||
connected KEYWORD2
|
||||
printNumber KEYWORD2
|
||||
printNumberln KEYWORD2
|
||||
printNumberln KEYWORD2
|
||||
|
||||
####################################################
|
||||
# Syntax Coloring Map For Wiimote Library
|
||||
####################################################
|
||||
|
||||
####################################################
|
||||
# Datatypes (KEYWORD1)
|
||||
####################################################
|
||||
|
||||
WII KEYWORD1
|
||||
|
||||
####################################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
####################################################
|
||||
|
||||
getButtonPress KEYWORD2
|
||||
getButtonClick KEYWORD2
|
||||
setRumbleToggle KEYWORD2
|
Loading…
Reference in a new issue