diff --git a/BTD.cpp b/BTD.cpp index a6b4b423..e59a1bc3 100644 --- a/BTD.cpp +++ b/BTD.cpp @@ -295,7 +295,7 @@ void BTD::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) { uint8_t BTD::Release() { for (uint8_t i=0; iRelease(); // Reset both the L2CAP Channel and the HCI Connection + btService[i]->Reset(); // Reset both the L2CAP Channel and the HCI Connection pUsb->GetAddressPool().FreeAddress(bAddress); bAddress = 0; bPollEnable = false; @@ -560,13 +560,16 @@ void BTD::HCI_task() { Notify(PSTR("\r\nScan Disabled")); #endif hci_event_flag = 0; - hci_state = HCI_DONE_STATE; + hci_state = HCI_DONE_STATE; } break; case HCI_DONE_STATE: - hci_state = HCI_SCANNING_STATE; - connectionClaimed = false; + hci_counter++; + if (hci_counter > 100) { // Wait until we have looped 100 times to make sure that the L2CAP connection has been started + hci_state = HCI_SCANNING_STATE; + l2capConnectionClaimed = false; + } break; case HCI_DISCONNECT_STATE: @@ -591,8 +594,8 @@ void BTD::HCI_task() { } 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 + 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; iPoll(); + btService[i]->Run(); } /************************************************************/ @@ -792,15 +795,16 @@ void BTD::L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf); if(rcode) { + delay(100); // This small delay prevents it from overflowing if it fails #ifdef DEBUG - Notify(PSTR("\r\nError sending L2CAP message: 0x")); + Notify(PSTR("\r\nError sending L2CAP message: 0x")); PrintHex(rcode); Notify(PSTR(" - Channel ID: ")); Serial.print(channelHigh); Notify(PSTR(" ")); Serial.print(channelLow); #endif - } + } } 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 diff --git a/BTD.h b/BTD.h index cba3c020..fb73bf6c 100644 --- a/BTD.h +++ b/BTD.h @@ -115,8 +115,8 @@ class BluetoothService { // All services should include this class public: virtual void ACLData(uint8_t* ACLData); // Used to pass acldata to the services - virtual void Poll(); // Used to run the different state machines - virtual void Release(); // Used to reset the services + virtual void Run(); // Used to run the different state machines + virtual void Reset(); // Used to reset the services virtual void disconnect(); // Used to disconnect both the L2CAP Channel and the HCI Connection }; @@ -152,8 +152,8 @@ public: return 1; // ErrorregisterServiceClass }; - void claimConnection() { connectionClaimed = true; }; // This is used by the service to know when to store the device information - bool connectionClaimed; + void claimConnection() { l2capConnectionClaimed = true; }; // This is used by the service to know when to store the device information + bool l2capConnectionClaimed; const char* btdName; // These are set by the SPP library const char* btdPin; diff --git a/PS3BT.cpp b/PS3BT.cpp index e6311c95..3147c7f9 100644 --- a/PS3BT.cpp +++ b/PS3BT.cpp @@ -58,7 +58,7 @@ pBtd(p) // pointer to USB class instance - mandatory interrupt_dcid[0] = 0x41;//0x0041 interrupt_dcid[1] = 0x00; - Release(); + Reset(); } bool PS3BT::getButton(Button b) { if (l2capinbuf == NULL) @@ -209,7 +209,7 @@ String PS3BT::getStatusString() { return statusOutput; } } -void PS3BT::Release() { +void PS3BT::Reset() { PS3Connected = false; PS3MoveConnected = false; PS3NavigationConnected = false; @@ -233,11 +233,9 @@ void PS3BT::disconnect() { //Use this void to disconnect any of the controllers } void PS3BT::ACLData(uint8_t* ACLData) { - for(uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) - l2capinbuf[i] = ACLData[i]; - if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { - if(((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) || ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_INTR_PSM)) { - if(!pBtd->connectionClaimed && !PS3Connected && !PS3MoveConnected && !PS3NavigationConnected) { + if(!pBtd->l2capConnectionClaimed && !PS3Connected && !PS3MoveConnected && !PS3NavigationConnected) { + if (ACLData[8] == L2CAP_CMD_CONNECTION_REQUEST) { + if(((ACLData[12] | (ACLData[13] << 8)) == HID_CTRL_PSM) || ((ACLData[12] | (ACLData[13] << 8)) == HID_INTR_PSM)) { pBtd->claimConnection(); // Claim that the incoming connection belongs to this service hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection for(uint8_t i = 0; i < 30; i++) @@ -252,7 +250,9 @@ void PS3BT::ACLData(uint8_t* ACLData) { } } } - if (((l2capinbuf[0] | (l2capinbuf[1] << 8)) == (hci_handle | 0x2000))) { //acl_handle_ok + if (((ACLData[0] | (ACLData[1] << 8)) == (hci_handle | 0x2000))) { //acl_handle_ok + for(uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) + l2capinbuf[i] = ACLData[i]; if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { //l2cap_control - Channel ID for ACL-U if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) { #ifdef DEBUG @@ -401,9 +401,10 @@ void PS3BT::ACLData(uint8_t* ACLData) { #endif } } + L2CAP_task(); } } -void PS3BT::Poll() { +void PS3BT::L2CAP_task() { switch (l2cap_state) { case L2CAP_EV_WAIT: if (l2cap_connection_request_control_flag) { @@ -424,7 +425,7 @@ void PS3BT::Poll() { #ifdef DEBUG Notify(PSTR("\r\nHID Control Configuration Request")); #endif - pBtd->l2cap_config_response(hci_handle,identifier, control_scid); + pBtd->l2cap_config_response(hci_handle,identifier, control_scid); l2cap_state = L2CAP_EV_CONTROL_SUCCESS; } break; @@ -442,12 +443,12 @@ void PS3BT::Poll() { #ifdef DEBUG Notify(PSTR("\r\nHID Interrupt Incoming Connection Request")); #endif - pBtd->l2cap_connection_response(hci_handle,identifier, interrupt_dcid, interrupt_scid, PENDING); + pBtd->l2cap_connection_response(hci_handle,identifier, interrupt_dcid, interrupt_scid, PENDING); delay(1); - pBtd->l2cap_connection_response(hci_handle,identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL); + pBtd->l2cap_connection_response(hci_handle,identifier, interrupt_dcid, interrupt_scid, SUCCESSFUL); identifier++; delay(1); - pBtd->l2cap_config_request(hci_handle,identifier, interrupt_scid); + pBtd->l2cap_config_request(hci_handle,identifier, interrupt_scid); l2cap_state = L2CAP_EV_INTERRUPT_REQUEST; } @@ -465,8 +466,8 @@ void PS3BT::Poll() { if (l2cap_config_success_interrupt_flag) { #ifdef DEBUG Notify(PSTR("\r\nHID Interrupt Successfully Configured")); -#endif - if(remote_name[0] == 'M') { // First letter in Motion Controller ('M') +#endif + if(remote_name[0] == 'M') { // First letter in Motion Controller ('M') for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) // Reset l2cap in buffer as it sometimes read it as a button has been pressed l2capinbuf[i] = 0; ButtonState = 0; @@ -478,55 +479,8 @@ void PS3BT::Poll() { timer = millis(); } break; - case L2CAP_EV_HID_ENABLE_SIXAXIS: - if(millis() - timer > 1000) { // loop 1 second before sending the command - for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) // Reset l2cap in buffer as it sometimes read it as a button has been pressed - l2capinbuf[i] = 0; - ButtonState = 0; - OldButtonState = 0; - - enable_sixaxis(); - for (uint8_t i = 15; i < 19; i++) - l2capinbuf[i] = 0x7F; // Set the analog joystick values to center position - l2cap_state = L2CAP_EV_HID_PS3_LED; - timer = millis(); - } - break; - - case L2CAP_EV_HID_PS3_LED: - if(millis() - timer > 1000) { // loop 1 second before sending the command - if (remote_name[0] == 'P') { // First letter in PLAYSTATION(R)3 Controller ('P') - setLedOn(LED1); -#ifdef DEBUG - Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n")); -#endif - PS3Connected = true; - } else if (remote_name[0] == 'N') { // First letter in Navigation Controller ('N') - setLedOn(LED1); // This just turns LED constantly on, on the Navigation controller -#ifdef DEBUG - Notify(PSTR("\r\nNavigation Controller Enabled\r\n")); -#endif - PS3NavigationConnected = true; - } else if(remote_name[0] == 'M') { // First letter in Motion Controller ('M') - moveSetBulb(Red); - timerBulbRumble = millis(); -#ifdef DEBUG - Notify(PSTR("\r\nMotion Controller Enabled\r\n")); -#endif - PS3MoveConnected = true; - } - l2cap_state = L2CAP_EV_DONE; - } - break; - - case L2CAP_EV_DONE: - if (PS3MoveConnected) { //The Bulb and rumble values, has to be send at aproximatly every 5th second for it to stay on - if (millis() - timerBulbRumble > 4000) { //Send at least every 4th second - HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);//The Bulb and rumble values, has to be written again and again, for it to stay turned on - timerBulbRumble = millis(); - } - } - break; + + /* These states are handled in Run() */ case L2CAP_EV_INTERRUPT_DISCONNECT: if (l2cap_disconnect_response_interrupt_flag) { @@ -549,6 +503,59 @@ void PS3BT::Poll() { l2cap_state = L2CAP_EV_WAIT; } break; + } +} +void PS3BT::Run() { + switch (l2cap_state) { + case L2CAP_EV_HID_ENABLE_SIXAXIS: + if(millis() - timer > 1000) { // loop 1 second before sending the command + for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) // Reset l2cap in buffer as it sometimes read it as a button has been pressed + l2capinbuf[i] = 0; + ButtonState = 0; + OldButtonState = 0; + + enable_sixaxis(); + for (uint8_t i = 15; i < 19; i++) + l2capinbuf[i] = 0x7F; // Set the analog joystick values to center position + l2cap_state = L2CAP_EV_HID_PS3_LED; + timer = millis(); + } + break; + + case L2CAP_EV_HID_PS3_LED: + if(millis() - timer > 1000) { // loop 1 second before sending the command + if (remote_name[0] == 'P') { // First letter in PLAYSTATION(R)3 Controller ('P') + setLedOn(LED1); +#ifdef DEBUG + Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n")); +#endif + PS3Connected = true; + } else if (remote_name[0] == 'N') { // First letter in Navigation Controller ('N') + setLedOn(LED1); // This just turns LED constantly on, on the Navigation controller +#ifdef DEBUG + Notify(PSTR("\r\nNavigation Controller Enabled\r\n")); +#endif + PS3NavigationConnected = true; + } else if(remote_name[0] == 'M') { // First letter in Motion Controller ('M') + moveSetBulb(Red); + timerBulbRumble = millis(); +#ifdef DEBUG + Notify(PSTR("\r\nMotion Controller Enabled\r\n")); +#endif + PS3MoveConnected = true; + } + l2cap_state = L2CAP_EV_DONE; + } + break; + + case L2CAP_EV_DONE: + if (PS3MoveConnected) { //The Bulb and rumble values, has to be send at aproximatly every 5th second for it to stay on + if (millis() - timerBulbRumble > 4000) { //Send at least every 4th second + HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);//The Bulb and rumble values, has to be written again and again, for it to stay turned on + timerBulbRumble = millis(); + } + } + break; } } diff --git a/PS3BT.h b/PS3BT.h index 650f6a22..e44083a1 100644 --- a/PS3BT.h +++ b/PS3BT.h @@ -219,8 +219,8 @@ public: // BluetoothService implementation virtual void ACLData(uint8_t* ACLData); // Used to pass acldata to the services - virtual void Poll(); // Used to run the state maschine - virtual void Release(); // Use this to reset the service + 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 /* PS3 Controller Commands */ @@ -258,6 +258,8 @@ private: /* mandatory members */ BTD *pBtd; + void L2CAP_task(); // L2CAP state machine + /* Variables filled from HCI event management */ int16_t hci_handle; uint8_t remote_name[30]; // first 30 chars of remote name diff --git a/SPP.cpp b/SPP.cpp index d1cf3154..605b1dbf 100644 --- a/SPP.cpp +++ b/SPP.cpp @@ -50,17 +50,16 @@ pBtd(p) // Pointer to BTD class instance - mandatory pBtd->btdName = name; pBtd->btdPin = pin; - l2cap_sdp_state = L2CAP_SDP_WAIT; - l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT; - l2cap_event_flag = 0; /* Set device cid for the SDP and RFCOMM channelse */ sdp_dcid[0] = 0x50; // 0x0050 sdp_dcid[1] = 0x00; rfcomm_dcid[0] = 0x51; // 0x0051 rfcomm_dcid[1] = 0x00; + + Reset(); } -void SPP::Release() { +void SPP::Reset() { connected = false; RFCOMMConnected = false; SDPConnected = false; @@ -78,16 +77,18 @@ void SPP::disconnect(){ l2cap_event_flag = 0; // Reset flags l2cap_sdp_state = L2CAP_DISCONNECT_RESPONSE; } -void SPP::ACLData(uint8_t* l2capinbuf) { - if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) { - if(((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM) || ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == RFCOMM_PSM)) { - if(!pBtd->connectionClaimed && !connected && !RFCOMMConnected && !SDPConnected) { +void SPP::ACLData(uint8_t* ACLData) { + if(!pBtd->l2capConnectionClaimed && !connected && !RFCOMMConnected && !SDPConnected) { + if (ACLData[8] == L2CAP_CMD_CONNECTION_REQUEST) { + if(((ACLData[12] | (ACLData[13] << 8)) == SDP_PSM) || ((ACLData[12] | (ACLData[13] << 8)) == RFCOMM_PSM)) { pBtd->claimConnection(); // Claim that the incoming connection belongs to this service hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection } } } - if (((l2capinbuf[0] | (l2capinbuf[1] << 8)) == (hci_handle | 0x2000))) { // acl_handle_ok + if (((ACLData[0] | (ACLData[1] << 8)) == (hci_handle | 0x2000))) { // acl_handle_ok + for(uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) + l2capinbuf[i] = ACLData[i]; if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { //l2cap_control - Channel ID for ACL-U if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) { #ifdef DEBUG @@ -362,9 +363,11 @@ void SPP::ACLData(uint8_t* l2capinbuf) { PrintHex(l2capinbuf[6]); #endif } + SDP_task(); + RFCOMM_task(); } } -void SPP::Poll() { +void SPP::Run() { if(waitForLastCommand && (millis() - timer) > 100) { // We will only wait 100ms and see if the UIH Remote Port Negotiation Command is send, as some deviced don't send it #ifdef DEBUG Notify(PSTR("\r\nRFCOMM Connection is now established - Automatic\r\n")); @@ -372,9 +375,7 @@ void SPP::Poll() { creditSent = false; waitForLastCommand = false; connected = true; // The RFCOMM channel is now established - } - SDP_task(); - RFCOMM_task(); + } } void SPP::SDP_task() { switch (l2cap_sdp_state) @@ -773,7 +774,8 @@ void SPP::println(const __FlashStringHelper *ifsh) { print(buf,size+2); } void SPP::println(void) { - print("\r\n"); + uint8_t buf[2] = {'\r','\n'}; + print(buf,2); } /* These must be used to print numbers */ diff --git a/SPP.h b/SPP.h index 41d8a729..52694d2a 100644 --- a/SPP.h +++ b/SPP.h @@ -99,8 +99,8 @@ public: // BluetoothService implementation virtual void ACLData(uint8_t* ACLData); // Used to pass acldata to the services - virtual void Poll(); // Used to run SDP_task() and RFCOMM_task() - virtual void Release(); // Use this to reset the service + virtual void Run(); // Used to establish the connection automatically + virtual void Reset(); // Use this to reset the service virtual void disconnect(); // Used this void to disconnect the virtual serial port bool connected;// Variable used to indicate if the connection is established @@ -141,6 +141,7 @@ private: uint16_t l2cap_event_flag; // l2cap flags of received bluetooth events uint8_t l2capoutbuf[BULK_MAXPKTSIZE]; // General purpose buffer for l2cap out data + uint8_t l2capinbuf[BULK_MAXPKTSIZE]; // General purpose buffer for l2cap in data uint8_t rfcommbuf[10]; // Buffer for RFCOMM Commands /* L2CAP Channels */