Merge branch 'master' of github.com:felis/USB_Host_Shield_2.0

This commit is contained in:
Oleg Mazurov 2012-05-08 14:38:56 -06:00
commit c16a160243
5 changed files with 837 additions and 711 deletions

564
PS3BT.cpp
View file

@ -17,10 +17,14 @@
#include "PS3BT.h" #include "PS3BT.h"
#define DEBUG // Uncomment to print data for debugging #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 PS3 Controllers //#define PRINTREPORT // Uncomment to print the report send by the PS3 Controllers
prog_char OUTPUT_REPORT_BUFFER[] PROGMEM = const uint8_t PS3BT::BTD_EVENT_PIPE = 1;
{ const uint8_t PS3BT::BTD_DATAIN_PIPE = 2;
const uint8_t PS3BT::BTD_DATAOUT_PIPE = 3;
prog_char OUTPUT_REPORT_BUFFER[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10, 0x00, 0x32,
@ -32,9 +36,11 @@ prog_char OUTPUT_REPORT_BUFFER[] PROGMEM =
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}; };
PS3BT::PS3BT(USB *p): PS3BT::PS3BT(USB *p, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0):
pUsb(p), // pointer to USB class instance - mandatory pUsb(p), // pointer to USB class instance - mandatory
bAddress(0), // device address - mandatory bAddress(0), // device address - mandatory
bNumEP(1), // if config descriptor needs to be parsed
qNextPollTime(0),
bPollEnable(false) // don't start polling before dongle is connected bPollEnable(false) // don't start polling before dongle is connected
{ {
for(uint8_t i=0; i<PS3_MAX_ENDPOINTS; i++) for(uint8_t i=0; i<PS3_MAX_ENDPOINTS; i++)
@ -42,36 +48,54 @@ PS3BT::PS3BT(USB *p):
epInfo[i].epAddr = 0; epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8; epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0; epInfo[i].epAttribs = 0;
if (!i) epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
epInfo[i].bmNakPower = USB_NAK_DEFAULT;
} }
if (pUsb) // register in USB subsystem if (pUsb) // register in USB subsystem
pUsb->RegisterDeviceClass(this); //set devConfig[] entry pUsb->RegisterDeviceClass(this); //set devConfig[] entry
my_bdaddr[5] = 0x00;//Change to your dongle's Bluetooth address instead my_bdaddr[5] = btadr5; // Change to your dongle's Bluetooth address instead
my_bdaddr[4] = 0x1F; my_bdaddr[4] = btadr4;
my_bdaddr[3] = 0x81; my_bdaddr[3] = btadr3;
my_bdaddr[2] = 0x00; my_bdaddr[2] = btadr2;
my_bdaddr[1] = 0x08; my_bdaddr[1] = btadr1;
my_bdaddr[0] = 0x30; my_bdaddr[0] = btadr0;
}
PS3BT::PS3BT(USB *p):
pUsb(p), // pointer to USB class instance - mandatory
bAddress(0), // device address - mandatory
bNumEP(1), // if config descriptor needs to be parsed
qNextPollTime(0),
bPollEnable(false) // don't start polling before dongle is connected
{
for(uint8_t i=0; i<PS3_MAX_ENDPOINTS; i++)
{
epInfo[i].epAddr = 0;
epInfo[i].maxPktSize = (i) ? 0 : 8;
epInfo[i].epAttribs = 0;
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
}
if (pUsb) // register in USB subsystem
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
} }
uint8_t PS3BT::Init(uint8_t parent, uint8_t port, bool lowspeed) uint8_t PS3BT::Init(uint8_t parent, uint8_t port, bool lowspeed)
{ {
const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR); uint8_t buf[sizeof(USB_DEVICE_DESCRIPTOR)];
uint8_t buf[constBufSize];
uint8_t rcode; uint8_t rcode;
UsbDevice *p = NULL; UsbDevice *p = NULL;
EpInfo *oldep_ptr = NULL; EpInfo *oldep_ptr = NULL;
uint8_t num_of_conf; // number of configurations
uint16_t PID; uint16_t PID;
uint16_t VID; uint16_t VID;
// get memory address of USB device address pool // get memory address of USB device address pool
AddressPool &addrPool = pUsb->GetAddressPool(); AddressPool &addrPool = pUsb->GetAddressPool();
#ifdef EXTRADEBUG
//Notify(PSTR("\r\nPS3BT Init"); Notify(PSTR("\r\nPS3BT Init"));
#endif
// check if address has already been assigned to an instance // check if address has already been assigned to an instance
if (bAddress) if (bAddress)
{ {
@ -109,14 +133,13 @@ uint8_t PS3BT::Init(uint8_t parent, uint8_t port, bool lowspeed)
p->lowspeed = lowspeed; p->lowspeed = lowspeed;
// Get device descriptor // Get device descriptor
rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);// Get device descriptor - addr, ep, nbytes, data rcode = pUsb->getDevDescr(0, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);// Get device descriptor - addr, ep, nbytes, data
// Restore p->epinfo // Restore p->epinfo
p->epinfo = oldep_ptr; p->epinfo = oldep_ptr;
if( rcode ){ if(rcode)
goto FailGetDevDescr; goto FailGetDevDescr;
}
// Allocate new address according to device class // Allocate new address according to device class
bAddress = addrPool.AllocAddress(parent, false, port); bAddress = addrPool.AllocAddress(parent, false, port);
@ -140,94 +163,33 @@ uint8_t PS3BT::Init(uint8_t parent, uint8_t port, bool lowspeed)
PrintHex<uint8_t>(rcode); PrintHex<uint8_t>(rcode);
return rcode; return rcode;
} }
//Notify(PSTR("\r\nAddr: ")); #ifdef EXTRADEBUG
//PrintHex<uint8_t>(bAddress); Notify(PSTR("\r\nAddr: "));
PrintHex<uint8_t>(bAddress);
#endif
p->lowspeed = false; p->lowspeed = false;
//get pointer to assigned address record //get pointer to assigned address record
p = addrPool.GetUsbDevicePtr(bAddress); p = addrPool.GetUsbDevicePtr(bAddress);
if (!p) if (!p)
{
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
}
p->lowspeed = lowspeed; p->lowspeed = lowspeed;
// Assign epInfo to epinfo pointer - only EP0 is known // Assign epInfo to epinfo pointer - only EP0 is known
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
if (rcode) if (rcode)
{
goto FailSetDevTblEntry; goto FailSetDevTblEntry;
}
num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations;
VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor; VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct; PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
if(VID == CSR_VID && PID == CSR_PID) if(VID == PS3_VID && (PID == PS3_PID || PID == PS3NAVIGATION_PID || PID == PS3MOVE_PID)) {
{ /* The application will work in reduced host mode, so we can save program and data
#ifdef DEBUG memory space. After verifying the PID and VID we will use known values for the
Notify(PSTR("\r\nBluetooth Dongle Connected")); configuration values for device, interface, endpoints and HID for the PS3 Controllers */
#endif
//Needed for PS3 Dualshock Controller commands to work via bluetooth
for (uint8_t i = 0; i < OUTPUT_REPORT_BUFFER_SIZE; i++)
HIDBuffer[i + 2] = pgm_read_byte(&OUTPUT_REPORT_BUFFER[i]);//First two bytes reserved for report type and ID
HIDBuffer[0] = 0x52;// HID BT Set_report (0x50) | Report Type (Output 0x02)
HIDBuffer[1] = 0x01;// Report ID
//Needed for PS3 Move Controller commands to work via bluetooth
HIDMoveBuffer[0] = 0xA2;// HID BT DATA_request (0xA0) | Report Type (Output 0x02)
HIDMoveBuffer[1] = 0x02;// Report ID
/* Set device cid for the control and intterrupt channelse - LSB */
control_dcid[0] = 0x40;//0x0040
control_dcid[1] = 0x00;
interrupt_dcid[0] = 0x41;//0x0041
interrupt_dcid[1] = 0x00;
/* Initialize data structures for endpoints of device */
epInfo[ CSR_EVENT_PIPE ].epAddr = 0x01; // Bluetooth event endpoint
epInfo[ CSR_EVENT_PIPE ].epAttribs = EP_INTERRUPT;
epInfo[ CSR_EVENT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
epInfo[ CSR_EVENT_PIPE ].maxPktSize = INT_MAXPKTSIZE;
epInfo[ CSR_EVENT_PIPE ].bmSndToggle = bmSNDTOG0;
epInfo[ CSR_EVENT_PIPE ].bmRcvToggle = bmRCVTOG0;
epInfo[ CSR_DATAIN_PIPE ].epAddr = 0x02; // Bluetoth data endpoint
epInfo[ CSR_DATAIN_PIPE ].epAttribs = EP_BULK;
epInfo[ CSR_DATAIN_PIPE ].bmNakPower = USB_NAK_NOWAIT;
epInfo[ CSR_DATAIN_PIPE ].maxPktSize = BULK_MAXPKTSIZE;
epInfo[ CSR_DATAIN_PIPE ].bmSndToggle = bmSNDTOG0;
epInfo[ CSR_DATAIN_PIPE ].bmRcvToggle = bmRCVTOG0;
epInfo[ CSR_DATAOUT_PIPE ].epAddr = 0x02; // Bluetooth data endpoint
epInfo[ CSR_DATAOUT_PIPE ].epAttribs = EP_BULK;
epInfo[ CSR_DATAOUT_PIPE ].bmNakPower = USB_NAK_NOWAIT;
epInfo[ CSR_DATAOUT_PIPE ].maxPktSize = BULK_MAXPKTSIZE;
epInfo[ CSR_DATAOUT_PIPE ].bmSndToggle = bmSNDTOG0;
epInfo[ CSR_DATAOUT_PIPE ].bmRcvToggle = bmRCVTOG0;
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
if( rcode )
goto FailSetDevTblEntry;
delay(200);//Give time for address change
rcode = pUsb->setConf(bAddress, epInfo[ CSR_CONTROL_PIPE ].epAddr, bConfigurationValue);//bConfigurationValue = 0x01
if( rcode )
goto FailSetConf;
hci_state = HCI_INIT_STATE;
hci_counter = 0;
l2cap_state = L2CAP_EV_WAIT;
#ifdef DEBUG
Notify(PSTR("\r\nCSR Initialized"));
#endif
delay(200);
bPollEnable = true;
}
else if((VID == PS3_VID || VID == PS3NAVIGATION_VID || VID == PS3MOVE_VID) && (PID == PS3_PID || PID == PS3NAVIGATION_PID || PID == PS3MOVE_PID))
{
/* Initialize data structures for endpoints of device */ /* Initialize data structures for endpoints of device */
epInfo[ PS3_OUTPUT_PIPE ].epAddr = 0x02; // PS3 output endpoint epInfo[ PS3_OUTPUT_PIPE ].epAddr = 0x02; // PS3 output endpoint
epInfo[ PS3_OUTPUT_PIPE ].epAttribs = EP_INTERRUPT; epInfo[ PS3_OUTPUT_PIPE ].epAttribs = EP_INTERRUPT;
@ -242,21 +204,19 @@ uint8_t PS3BT::Init(uint8_t parent, uint8_t port, bool lowspeed)
epInfo[ PS3_INPUT_PIPE ].bmSndToggle = bmSNDTOG0; epInfo[ PS3_INPUT_PIPE ].bmSndToggle = bmSNDTOG0;
epInfo[ PS3_INPUT_PIPE ].bmRcvToggle = bmRCVTOG0; epInfo[ PS3_INPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo); rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
if( rcode ) if( rcode )
goto FailSetDevTblEntry; goto FailSetDevTblEntry;
delay(200);//Give time for address change delay(200);//Give time for address change
rcode = pUsb->setConf(bAddress, epInfo[ PS3_CONTROL_PIPE ].epAddr, 1);
rcode = pUsb->setConf(bAddress, epInfo[ PS3_CONTROL_PIPE ].epAddr, bConfigurationValue);//bConfigurationValue = 0x01
if( rcode ) if( rcode )
goto FailSetConf; goto FailSetConf;
if((VID == PS3_VID || VID == PS3NAVIGATION_VID) && (PID == PS3_PID || PID == PS3NAVIGATION_PID)) if(PID == PS3_PID || PID == PS3NAVIGATION_PID)
{ {
if(VID == PS3_VID && PID == PS3_PID) { if(PID == PS3_PID) {
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nDualshock 3 Controller Connected")); Notify(PSTR("\r\nDualshock 3 Controller Connected"));
#endif #endif
@ -277,8 +237,64 @@ uint8_t PS3BT::Init(uint8_t parent, uint8_t port, bool lowspeed)
} }
} }
else else
{
//check if attached device is a Bluetooth dongle and fill endpoint data structure
//first interface in the configuration must have Bluetooth assigned Class/Subclass/Protocol
//and 3 endpoints - interrupt-IN, bulk-IN, bulk-OUT,
//not necessarily in this order
for (uint8_t i=0; i<num_of_conf; i++) {
ConfigDescParser<USB_CLASS_WIRELESS_CTRL, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this);
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
if(rcode)
goto FailGetConfDescr;
if(bNumEP > 3) //all endpoints extracted
break;
} // for (uint8_t i=0; i<num_of_conf; i++...
if (bNumEP < PS3_MAX_ENDPOINTS)
goto FailUnknownDevice; goto FailUnknownDevice;
// Assign epInfo to epinfo pointer - this time all 3 endpoins
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
if(rcode)
goto FailSetDevTblEntry;
delay(200); // Give time for address change
// Set Configuration Value
rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bConfNum);
if(rcode)
goto FailSetConf;
//Needed for PS3 Dualshock Controller commands to work via bluetooth
for (uint8_t i = 0; i < OUTPUT_REPORT_BUFFER_SIZE; i++)
HIDBuffer[i + 2] = pgm_read_byte(&OUTPUT_REPORT_BUFFER[i]);//First two bytes reserved for report type and ID
HIDBuffer[0] = 0x52;// HID BT Set_report (0x50) | Report Type (Output 0x02)
HIDBuffer[1] = 0x01;// Report ID
//Needed for PS3 Move Controller commands to work via bluetooth
HIDMoveBuffer[0] = 0xA2;// HID BT DATA_request (0xA0) | Report Type (Output 0x02)
HIDMoveBuffer[1] = 0x02;// Report ID
/* Set device cid for the control and intterrupt channelse - LSB */
control_dcid[0] = 0x40;//0x0040
control_dcid[1] = 0x00;
interrupt_dcid[0] = 0x41;//0x0041
interrupt_dcid[1] = 0x00;
hci_num_reset_loops = 10; // only loop 10 times before trying to send the hci reset command
hci_state = HCI_INIT_STATE;
hci_counter = 0;
l2cap_state = L2CAP_EV_WAIT;
#ifdef DEBUG
Notify(PSTR("\r\nBluetooth Dongle Initialized"));
#endif
watingForConnection = false;
bPollEnable = true;
}
return 0; //successful configuration return 0; //successful configuration
/* diagnostic messages */ /* diagnostic messages */
@ -292,6 +308,11 @@ uint8_t PS3BT::Init(uint8_t parent, uint8_t port, bool lowspeed)
Notify(PSTR("\r\nsetDevTblEn:")); Notify(PSTR("\r\nsetDevTblEn:"));
#endif #endif
goto Fail; goto Fail;
FailGetConfDescr:
#ifdef DEBUG
Notify(PSTR("\r\ngetConf:"));
#endif
goto Fail;
FailSetConf: FailSetConf:
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nsetConf:")); Notify(PSTR("\r\nsetConf:"));
@ -313,6 +334,56 @@ uint8_t PS3BT::Init(uint8_t parent, uint8_t port, bool lowspeed)
Release(); Release();
return rcode; return rcode;
} }
/* Extracts interrupt-IN, bulk-IN, bulk-OUT endpoint information from config descriptor */
void PS3BT::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep)
{
//ErrorMessage<uint8_t>(PSTR("Conf.Val"),conf);
//ErrorMessage<uint8_t>(PSTR("Iface Num"),iface);
//ErrorMessage<uint8_t>(PSTR("Alt.Set"),alt);
if(alt) // wrong interface - by BT spec, no alt setting
return;
bConfNum = conf;
uint8_t index;
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) //Interrupt In endpoint found
index = BTD_EVENT_PIPE;
else {
if ((pep->bmAttributes & 0x02) == 2) //bulk endpoint found
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? BTD_DATAIN_PIPE : BTD_DATAOUT_PIPE;
else
return;
}
//Fill the rest of endpoint data structure
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
#ifdef EXTRADEBUG
PrintEndpointDescriptor(pep);
#endif
if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
pollInterval = pep->bInterval;
bNumEP++;
return;
}
void PS3BT::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr )
{
Notify(PSTR("\r\nEndpoint descriptor:"));
Notify(PSTR("\r\nLength:\t\t"));
PrintHex<uint8_t>(ep_ptr->bLength);
Notify(PSTR("\r\nType:\t\t"));
PrintHex<uint8_t>(ep_ptr->bDescriptorType);
Notify(PSTR("\r\nAddress:\t"));
PrintHex<uint8_t>(ep_ptr->bEndpointAddress);
Notify(PSTR("\r\nAttributes:\t"));
PrintHex<uint8_t>(ep_ptr->bmAttributes);
Notify(PSTR("\r\nMaxPktSize:\t"));
PrintHex<uint16_t>(ep_ptr->wMaxPacketSize);
Notify(PSTR("\r\nPoll Intrv:\t"));
PrintHex<uint8_t>(ep_ptr->bInterval);
}
/* Performs a cleanup after failed Init() attempt */ /* Performs a cleanup after failed Init() attempt */
uint8_t PS3BT::Release() uint8_t PS3BT::Release()
@ -320,16 +391,18 @@ uint8_t PS3BT::Release()
pUsb->GetAddressPool().FreeAddress(bAddress); pUsb->GetAddressPool().FreeAddress(bAddress);
bAddress = 0; bAddress = 0;
bPollEnable = false; bPollEnable = false;
bNumEP = 1; // must have to be reset to 1
return 0; return 0;
} }
uint8_t PS3BT::Poll() uint8_t PS3BT::Poll()
{ {
if (!bPollEnable) if (!bPollEnable)
return 0; return 0;
if (qNextPollTime <= millis()) { // Don't poll if shorter than polling interval
HCI_event_task(); // poll the HCI event pipe HCI_event_task(); // poll the HCI event pipe
ACL_event_task(); // start polling the ACL input pipe too, though discard data until connected ACL_event_task(); // start polling the ACL input pipe too, though discard data until connected
}
qNextPollTime = millis() + pollInterval; // Poll time
return 0; return 0;
} }
void PS3BT::setBdaddr(uint8_t* BDADDR) void PS3BT::setBdaddr(uint8_t* BDADDR)
@ -346,7 +419,7 @@ void PS3BT::setBdaddr(uint8_t* BDADDR)
buf[i+2] = my_bdaddr[5 - i];//Copy into buffer, has to be written reversed buf[i+2] = my_bdaddr[5 - i];//Copy into buffer, has to be written reversed
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data) //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0xF5), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL); pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0xF5, 0x03, 0x00, 8, 8, buf, NULL);
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nBluetooth Address was set to: ")); Notify(PSTR("\r\nBluetooth Address was set to: "));
for(int8_t i = 5; i > 0; i--) for(int8_t i = 5; i > 0; i--)
@ -376,7 +449,7 @@ void PS3BT::setMoveBdaddr(uint8_t* BDADDR)
buf[i + 1] = my_bdaddr[i]; buf[i + 1] = my_bdaddr[i];
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data) //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data)
pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00,11,11, buf, NULL); pUsb->ctrlReq(bAddress,epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00,11,11, buf, NULL);
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nBluetooth Address was set to: ")); Notify(PSTR("\r\nBluetooth Address was set to: "));
for(int8_t i = 5; i > 0; i--) for(int8_t i = 5; i > 0; i--)
@ -409,19 +482,15 @@ uint8_t PS3BT::getAnalogHat(AnalogHat a)
return 0; return 0;
return (uint8_t)(l2capinbuf[(uint16_t)a]); return (uint8_t)(l2capinbuf[(uint16_t)a]);
} }
uint32_t PS3BT::getSensor(Sensor a) int32_t PS3BT::getSensor(Sensor a)
{
if (a == aX || a == aY || a == aZ || a == gZ)
{ {
if (l2capinbuf == NULL) if (l2capinbuf == NULL)
return 0; return 0;
if (a == aX || a == aY || a == aZ || a == gZ)
return ((l2capinbuf[(uint16_t)a] << 8) | l2capinbuf[(uint16_t)a + 1]); return ((l2capinbuf[(uint16_t)a] << 8) | l2capinbuf[(uint16_t)a + 1]);
}
else if (a == mXmove || a == mYmove || a == mZmove) else if (a == mXmove || a == mYmove || a == mZmove)
{ {
// Might not be correct, haven't tested it yet // Might not be correct, haven't tested it yet
if (l2capinbuf == NULL)
return 0;
if (a == mXmove) if (a == mXmove)
return ((l2capinbuf[(uint16_t)a + 1] << 0x04) | (l2capinbuf[(uint16_t)a] << 0x0C)); return ((l2capinbuf[(uint16_t)a + 1] << 0x04) | (l2capinbuf[(uint16_t)a] << 0x0C));
//return (((unsigned char)l2capinbuf[(unsigned int)a + 1]) | (((unsigned char)l2capinbuf[(unsigned int)a] & 0x0F)) << 8); //return (((unsigned char)l2capinbuf[(unsigned int)a + 1]) | (((unsigned char)l2capinbuf[(unsigned int)a] & 0x0F)) << 8);
@ -435,84 +504,63 @@ uint32_t PS3BT::getSensor(Sensor a)
return 0; return 0;
} }
else if (a == tempMove) else if (a == tempMove)
{
if (l2capinbuf == NULL)
return 0;
return (((l2capinbuf[(uint16_t)a + 1] & 0xF0) >> 4) | (l2capinbuf[(uint16_t)a] << 4)); return (((l2capinbuf[(uint16_t)a + 1] & 0xF0) >> 4) | (l2capinbuf[(uint16_t)a] << 4));
else // aXmove, aYmove, aZmove, gXmove, gYmove and gZmove
return ((l2capinbuf[(uint16_t)a + 1] << 8) | l2capinbuf[(uint16_t)a]);
} }
else double PS3BT::getAngle(Angle a) {
{
if (l2capinbuf == NULL)
return 0;
return (((l2capinbuf[(uint16_t)a + 1] << 8) | l2capinbuf[(uint16_t)a]) - 0x8000);
}
}
double PS3BT::getAngle(Angle a, boolean resolution)//Boolean indicate if 360-degrees resolution is used or not - set false if you want to use both axis
{
double accXin;
double accXval; double accXval;
double Pitch;
double accYin;
double accYval; double accYval;
double Roll;
double accZin;
double accZval; double accZval;
//Data for the Kionix KXPC4 used in DualShock 3 if(PS3BTConnected) {
// Data for the Kionix KXPC4 used in the DualShock 3
double sensivity = 204.6; // 0.66/3.3*1023 (660mV/g) double sensivity = 204.6; // 0.66/3.3*1023 (660mV/g)
double zeroG = 511.5; // 1.65/3.3*1023 (1,65V) double zeroG = 511.5; // 1.65/3.3*1023 (1,65V)
double R;//force vector accXval = ((double)getSensor(aX)-zeroG) / sensivity; // Convert to g's
accXin = getSensor(aX);
accXval = (zeroG - accXin) / sensivity;//Convert to g's
accXval *= 2; accXval *= 2;
accYval = ((double)getSensor(aY)-zeroG) / sensivity; // Convert to g's
accYin = getSensor(aY);
accYval = (zeroG - accYin) / sensivity;//Convert to g's
accYval *= 2; accYval *= 2;
accZval = ((double)getSensor(aZ)-zeroG) / sensivity; // Convert to g's
accZin = getSensor(aZ);
accZval = (zeroG - accZin) / sensivity;//Convert to g's
accZval *= 2; accZval *= 2;
} else if(PS3MoveBTConnected) {
// It's a Kionix KXSC4 inside the Motion controller
const uint16_t sensivity = 28285; // Find by experimenting
accXval = (double)getSensor(aXmove)/sensivity;
accYval = (double)getSensor(aYmove)/sensivity;
accZval = (double)getSensor(aZmove)/sensivity;
R = sqrt(pow(accXval, 2) + pow(accYval, 2) + pow(accZval, 2)); if(accXval < -1) // Convert to g's
accXval = ((1+accXval)-(1-1.15))*(-1/0.15);
else if(accXval > 1)
accXval = ((1+accXval)-(1+1.15))*(-1/0.15);
if (a == Pitch) if(accYval < -1) // Convert to g's
{ accYval = ((1+accYval)-(1-1.15))*(-1/0.15);
//the result will come out as radians, so it is multiplied by 180/pi, to convert to degrees else if(accYval > 1)
//In the end it is minus by 90, so its 0 degrees when in horizontal postion accYval = ((1+accYval)-(1+1.15))*(-1/0.15);
Pitch = acos(accXval / R) * 180 / PI - 90;
if(resolution)
{
if (accZval < 0)//Convert to 360 degrees resolution - set resolution false if you need both pitch and roll
{
if (Pitch < 0)
Pitch = -180 - Pitch;
else
Pitch = 180 - Pitch;
}
}
return Pitch;
if(accZval < -1) // Convert to g's
accZval = ((1+accZval)-(1-1.15))*(-1/0.15);
else if(accZval > 1)
accZval = ((1+accZval)-(1+1.15))*(-1/0.15);
} }
else
{ double R = sqrt(accXval*accXval + accYval*accYval + accZval*accZval); // Calculate the length of the force vector
//the result will come out as radians, so it is multiplied by 180/pi, to convert to degrees // Normalize vectors
//In the end it is minus by 90, so its 0 degrees when in horizontal postion accXval = accXval/R;
Roll = acos(accYval / R) * 180 / PI - 90; accYval = accYval/R;
if(resolution) accZval = accZval/R;
{
if (accZval < 0)//Convert to 360 degrees resolution - set resolution false if you need both pitch and roll // Convert to 360 degrees resolution
{ // atan2 outputs the value of -π to π (radians)
if (Roll < 0) // We are then converting it to 0 to 2π and then to degrees
Roll = -180 - Roll; if (a == Pitch) {
else double angle = (atan2(-accYval,-accZval)+PI)*RAD_TO_DEG;
Roll = 180 - Roll; return angle;
} } else {
} double angle = (atan2(-accXval,-accZval)+PI)*RAD_TO_DEG;
return Roll; return angle;
} }
} }
bool PS3BT::getStatus(Status c) bool PS3BT::getStatus(Status c)
@ -592,8 +640,10 @@ void PS3BT::disconnect()//Use this void to disconnect any of the controllers
void PS3BT::HCI_event_task() void PS3BT::HCI_event_task()
{ {
/* check the event pipe*/ /* check the event pipe*/
uint16_t MAX_BUFFER_SIZE = BULK_MAXPKTSIZE; uint16_t MAX_BUFFER_SIZE = BULK_MAXPKTSIZE; // Request more than 16 bytes anyway, the inTransfer routine will take care of this
pUsb->inTransfer(bAddress, epInfo[ CSR_EVENT_PIPE ].epAddr, &MAX_BUFFER_SIZE, hcibuf); // input on endpoint 1 uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_EVENT_PIPE ].epAddr, &MAX_BUFFER_SIZE, hcibuf); // input on endpoint 1
if(!rcode || rcode == hrNAK) // Check for errors
{
switch (hcibuf[0]) //switch on event type switch (hcibuf[0]) //switch on event type
{ {
case EV_COMMAND_COMPLETE: case EV_COMMAND_COMPLETE:
@ -606,8 +656,6 @@ void PS3BT::HCI_event_task()
break; break;
case EV_COMMAND_STATUS: case EV_COMMAND_STATUS:
//hci_command_packets = hcibuf[3]; // update flow control
hci_event_flag |= HCI_FLAG_CMD_STATUS; //set status flag
if(hcibuf[2]) // show status on serial if not OK if(hcibuf[2]) // show status on serial if not OK
{ {
#ifdef DEBUG #ifdef DEBUG
@ -622,26 +670,31 @@ void PS3BT::HCI_event_task()
break; break;
case EV_CONNECT_COMPLETE: case EV_CONNECT_COMPLETE:
hci_event_flag |= HCI_FLAG_CONN_COMPLETE; // set connection complete flag
if (!hcibuf[2]) // check if connected OK 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] << 8; //store the handle for the ACL connection
hci_event_flag |= HCI_FLAG_CONNECT_OK; //set connection OK flag hci_event_flag |= HCI_FLAG_CONN_COMPLETE; // set connection complete flag
} }
break; break;
case EV_DISCONNECT_COMPLETE: case EV_DISCONNECT_COMPLETE:
hci_event_flag |= HCI_FLAG_DISCONN_COMPLETE; //set disconnect commend complete flag
if (!hcibuf[2]) // check if disconnected OK if (!hcibuf[2]) // check if disconnected OK
hci_event_flag &= ~(HCI_FLAG_CONNECT_OK); //clear connection OK flag {
hci_event_flag |= HCI_FLAG_DISCONN_COMPLETE; //set disconnect commend complete flag
hci_event_flag &= ~HCI_FLAG_CONN_COMPLETE; // clear connection complete flag
}
break; break;
case EV_NUM_COMPLETE_PKT: case EV_NUM_COMPLETE_PKT:
break; break;
case EV_REMOTE_NAME_COMPLETE: case EV_REMOTE_NAME_COMPLETE:
if (!hcibuf[2]) // check if reading is OK
{
for (uint8_t i = 0; i < 30; i++) for (uint8_t i = 0; i < 30; i++)
remote_name[i] = hcibuf[9 + i]; //store first 30 bytes remote_name[i] = hcibuf[9 + i]; //store first 30 bytes
hci_event_flag |= HCI_FLAG_REMOTE_NAME_COMPLETE; hci_event_flag |= HCI_FLAG_REMOTE_NAME_COMPLETE;
}
break; break;
case EV_INCOMING_CONNECT: case EV_INCOMING_CONNECT:
@ -654,27 +707,44 @@ void PS3BT::HCI_event_task()
hci_event_flag |= HCI_FLAG_INCOMING_REQUEST; hci_event_flag |= HCI_FLAG_INCOMING_REQUEST;
break; break;
/* We will just ignore the following events */
case EV_ROLE_CHANGED: case EV_ROLE_CHANGED:
/*
#ifdef DEBUG
Notify(PSTR("\r\nRole Changed"));
#endif
*/
break; break;
case EV_PAGE_SCAN_REP_MODE:
break;
case EV_LOOPBACK_COMMAND:
break;
case EV_DATA_BUFFER_OVERFLOW:
break;
case EV_CHANGE_CONNECTION_LINK:
break;
case EV_AUTHENTICATION_COMPLETE:
break;
default: default:
/* #ifdef EXTRADEBUG
#ifdef DEBUG
if(hcibuf[0] != 0x00) if(hcibuf[0] != 0x00)
{ {
Notify(PSTR("\r\nUnmanaged Event: ")); Notify(PSTR("\r\nUnmanaged Event: "));
PrintHex<uint8_t>(hcibuf[0]); PrintHex<uint8_t>(hcibuf[0]);
} }
#endif #endif
*/
break; break;
} // switch } // switch
HCI_task(); HCI_task();
} }
else {
#ifdef EXTRADEBUG
Notify(PSTR("\r\nHCI event error: "));
PrintHex<uint8_t>(rcode);
#endif
}
}
/* Poll Bluetooth and print result */ /* Poll Bluetooth and print result */
void PS3BT::HCI_task() void PS3BT::HCI_task()
@ -682,7 +752,7 @@ void PS3BT::HCI_task()
switch (hci_state){ switch (hci_state){
case HCI_INIT_STATE: case HCI_INIT_STATE:
hci_counter++; hci_counter++;
if (hci_counter > 1000) // wait until we have looped 1000 times to clear any old events if (hci_counter > hci_num_reset_loops) // wait until we have looped x times to clear any old events
{ {
hci_reset(); hci_reset();
hci_state = HCI_RESET_STATE; hci_state = HCI_RESET_STATE;
@ -700,8 +770,11 @@ void PS3BT::HCI_task()
hci_state = HCI_BDADDR_STATE; hci_state = HCI_BDADDR_STATE;
hci_read_bdaddr(); hci_read_bdaddr();
} }
else if (hci_counter > 1000) else if (hci_counter > hci_num_reset_loops)
{ {
hci_num_reset_loops *= 10;
if(hci_num_reset_loops > 2000)
hci_num_reset_loops = 2000;
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nNo response to HCI Reset")); Notify(PSTR("\r\nNo response to HCI Reset"));
#endif #endif
@ -729,12 +802,14 @@ void PS3BT::HCI_task()
Notify(PSTR("\r\nWait For Incoming Connection Request")); Notify(PSTR("\r\nWait For Incoming Connection Request"));
#endif #endif
hci_write_scan_enable(); hci_write_scan_enable();
watingForConnection = true;
hci_state = HCI_CONNECT_IN_STATE; hci_state = HCI_CONNECT_IN_STATE;
break; break;
case HCI_CONNECT_IN_STATE: case HCI_CONNECT_IN_STATE:
if(hci_incoming_connect_request) if(hci_incoming_connect_request)
{ {
watingForConnection = false;
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nIncoming Request")); Notify(PSTR("\r\nIncoming Request"));
#endif #endif
@ -819,8 +894,8 @@ void PS3BT::HCI_task()
for (uint8_t i = 0; i < OUTPUT_REPORT_BUFFER_SIZE; i++) for (uint8_t i = 0; i < OUTPUT_REPORT_BUFFER_SIZE; i++)
HIDBuffer[i + 2] = pgm_read_byte(&OUTPUT_REPORT_BUFFER[i]); // First two bytes reserved for report type and ID HIDBuffer[i + 2] = pgm_read_byte(&OUTPUT_REPORT_BUFFER[i]); // First two bytes reserved for report type and ID
for (uint8_t i = 2; i < HIDMOVEBUFFERSIZE; i++) for (uint8_t i = 0; i < OUTPUT_REPORT_BUFFER_SIZE; i++)
HIDMoveBuffer[i] = 0; HIDMoveBuffer[i + 2] = 0; // First two bytes reserved for report type and ID
l2cap_state = L2CAP_EV_WAIT; l2cap_state = L2CAP_EV_WAIT;
hci_state = HCI_SCANNING_STATE; hci_state = HCI_SCANNING_STATE;
@ -834,7 +909,9 @@ void PS3BT::HCI_task()
void PS3BT::ACL_event_task() void PS3BT::ACL_event_task()
{ {
uint16_t MAX_BUFFER_SIZE = BULK_MAXPKTSIZE; uint16_t MAX_BUFFER_SIZE = BULK_MAXPKTSIZE;
pUsb->inTransfer(bAddress, epInfo[ CSR_DATAIN_PIPE ].epAddr, &MAX_BUFFER_SIZE, l2capinbuf); // input on endpoint 2 uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_DATAIN_PIPE ].epAddr, &MAX_BUFFER_SIZE, l2capinbuf); // input on endpoint 2
if(!rcode || rcode == hrNAK) // Check for errors
{
if (((l2capinbuf[0] | (l2capinbuf[1] << 8)) == (hci_handle | 0x2000)))//acl_handle_ok 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[6] | (l2capinbuf[7] << 8)) == 0x0001)//l2cap_control - Channel ID for ACL-U
@ -866,7 +943,7 @@ void PS3BT::ACL_event_task()
else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST)
{ {
/* /*
Notify(PSTR("\r\nPSM: ")); Notify(PSTR("\r\nL2CAP Connection Request - PSM: "));
PrintHex<uint8_t>(l2capinbuf[13]); PrintHex<uint8_t>(l2capinbuf[13]);
Serial.print(" "); Serial.print(" ");
PrintHex<uint8_t>(l2capinbuf[12]); PrintHex<uint8_t>(l2capinbuf[12]);
@ -978,6 +1055,13 @@ void PS3BT::ACL_event_task()
L2CAP_task(); L2CAP_task();
} }
} }
else {
#ifdef EXTRADEBUG
Notify(PSTR("\r\nACL data in error: "));
PrintHex<uint8_t>(rcode);
#endif
}
}
void PS3BT::L2CAP_task() void PS3BT::L2CAP_task()
{ {
switch (l2cap_state) switch (l2cap_state)
@ -1051,57 +1135,57 @@ void PS3BT::L2CAP_task()
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nHID Interrupt Successfully Configured")); Notify(PSTR("\r\nHID Interrupt Successfully Configured"));
#endif #endif
l2cap_state = L2CAP_EV_HID_ENABLE_SIXAXIS; if(remote_name[0] == 'M') { // First letter in Motion Controller ('M')
}
break;
case L2CAP_EV_HID_ENABLE_SIXAXIS:
delay(1000);//There has to be a delay before sending the commands
for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) // Reset l2cap in buffer as it sometimes read it as a button has been pressed 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; l2capinbuf[i] = 0;
ButtonState = 0; ButtonState = 0;
OldButtonState = 0; OldButtonState = 0;
if (remote_name[0] == 'P')//First letter in PLAYSTATION(R)3 Controller ('P') - 0x50 l2cap_state = L2CAP_EV_HID_PS3_LED;
{ } else
enable_sixaxis(); l2cap_state = L2CAP_EV_HID_ENABLE_SIXAXIS;
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++) for (uint8_t i = 15; i < 19; i++)
l2capinbuf[i] = 0x7F; // Set the analog joystick values to center position l2capinbuf[i] = 0x7F; // Set the analog joystick values to center position
l2cap_state = L2CAP_EV_HID_PS3_LED;
timer = millis();
}
break;
delay(1000);//There has to be a delay before data can be read 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); setLedOn(LED1);
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n")); Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n"));
#endif #endif
PS3BTConnected = true; PS3BTConnected = true;
} } else if (remote_name[0] == 'N') { // First letter in Navigation Controller ('N')
else if (remote_name[0] == 'N')//First letter in Navigation Controller ('N') - 0x4E
{
enable_sixaxis();
for (uint8_t i = 15; i < 19; i++)
l2capinbuf[i] = 0x7F;//Set the analog joystick values to center
delay(1000);//There has to be a delay before data can be read
setLedOn(LED1); // This just turns LED constantly on, on the Navigation controller setLedOn(LED1); // This just turns LED constantly on, on the Navigation controller
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nNavigation Controller Enabled\r\n")); Notify(PSTR("\r\nNavigation Controller Enabled\r\n"));
#endif #endif
PS3NavigationBTConnected = true; PS3NavigationBTConnected = true;
} } else if(remote_name[0] == 'M') { // First letter in Motion Controller ('M')
else if (remote_name[0] == 'M')//First letter in Motion Controller ('M') - 0x4D
{
delay(1000);//There has to be a delay before data can be read
moveSetBulb(Red); moveSetBulb(Red);
timerBulbRumble = millis();
#ifdef DEBUG #ifdef DEBUG
Notify(PSTR("\r\nMotion Controller Enabled\r\n")); Notify(PSTR("\r\nMotion Controller Enabled\r\n"));
#endif #endif
PS3MoveBTConnected = true; PS3MoveBTConnected = true;
timerBulbRumble = millis();
} }
l2cap_state = L2CAP_EV_L2CAP_DONE; l2cap_state = L2CAP_EV_L2CAP_DONE;
}
break; break;
case L2CAP_EV_L2CAP_DONE: case L2CAP_EV_L2CAP_DONE:
@ -1110,7 +1194,7 @@ void PS3BT::L2CAP_task()
dtimeBulbRumble = millis() - timerBulbRumble; dtimeBulbRumble = millis() - timerBulbRumble;
if (dtimeBulbRumble > 4000)//Send at least every 4th second if (dtimeBulbRumble > 4000)//Send at least every 4th second
{ {
HIDMove_Command(HIDMoveBuffer, HIDMOVEBUFFERSIZE);//The Bulb and rumble values, has to be written again and again, for it to stay turned on 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(); timerBulbRumble = millis();
} }
} }
@ -1159,17 +1243,21 @@ void PS3BT::readReport()
if(ButtonState != OldButtonState) if(ButtonState != OldButtonState)
{ {
ButtonChanged = true; buttonChanged = true;
if(ButtonState != 0x00) if(ButtonState != 0x00) {
ButtonPressed = true; buttonPressed = true;
else buttonReleased = false;
ButtonPressed = false; } else {
buttonPressed = false;
buttonReleased = true;
}
} }
else else
{ {
ButtonChanged = false; buttonChanged = false;
ButtonPressed = false; buttonPressed = false;
buttonReleased = false;
} }
OldButtonState = ButtonState; OldButtonState = ButtonState;
@ -1197,7 +1285,7 @@ void PS3BT::printReport() //Uncomment "#define PRINTREPORT" to print the report
void PS3BT::HCI_Command(uint8_t* data, uint16_t nbytes) void PS3BT::HCI_Command(uint8_t* data, uint16_t nbytes)
{ {
hci_event_flag &= ~HCI_FLAG_CMD_COMPLETE; hci_event_flag &= ~HCI_FLAG_CMD_COMPLETE;
pUsb->ctrlReq(bAddress, epInfo[ CSR_CONTROL_PIPE ].epAddr, bmREQ_HCI_OUT, 0x00, 0x00, 0x00 ,0x00, nbytes, nbytes, data, NULL); pUsb->ctrlReq(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, bmREQ_HCI_OUT, 0x00, 0x00, 0x00 ,0x00, nbytes, nbytes, data, NULL);
} }
void PS3BT::hci_reset() void PS3BT::hci_reset()
@ -1210,6 +1298,7 @@ void PS3BT::hci_reset()
} }
void PS3BT::hci_write_scan_enable() void PS3BT::hci_write_scan_enable()
{ {
hci_event_flag &= ~HCI_FLAG_INCOMING_REQUEST;
hcibuf[0] = 0x1A; // HCI OCF = 1A hcibuf[0] = 0x1A; // HCI OCF = 1A
hcibuf[1] = 0x03 << 2; // HCI OGF = 3 hcibuf[1] = 0x03 << 2; // HCI OGF = 3
hcibuf[2] = 0x01;// parameter length = 1 hcibuf[2] = 0x01;// parameter length = 1
@ -1233,9 +1322,6 @@ void PS3BT::hci_read_bdaddr()
} }
void PS3BT::hci_accept_connection() void PS3BT::hci_accept_connection()
{ {
hci_event_flag |= HCI_FLAG_CONNECT_OK;
hci_event_flag &= ~(HCI_FLAG_INCOMING_REQUEST);
hcibuf[0] = 0x09; // HCI OCF = 9 hcibuf[0] = 0x09; // HCI OCF = 9
hcibuf[1] = 0x01 << 2; // HCI OGF = 1 hcibuf[1] = 0x01 << 2; // HCI OGF = 1
hcibuf[2] = 0x07; // parameter length 7 hcibuf[2] = 0x07; // parameter length 7
@ -1251,7 +1337,7 @@ void PS3BT::hci_accept_connection()
} }
void PS3BT::hci_remote_name() void PS3BT::hci_remote_name()
{ {
hci_event_flag &= ~(HCI_FLAG_REMOTE_NAME_COMPLETE); hci_event_flag &= ~HCI_FLAG_REMOTE_NAME_COMPLETE;
hcibuf[0] = 0x19; // HCI OCF = 19 hcibuf[0] = 0x19; // HCI OCF = 19
hcibuf[1] = 0x01 << 2; // HCI OGF = 1 hcibuf[1] = 0x01 << 2; // HCI OGF = 1
hcibuf[2] = 0x0A; // parameter length = 10 hcibuf[2] = 0x0A; // parameter length = 10
@ -1298,7 +1384,7 @@ void PS3BT::L2CAP_Command(uint8_t* data, uint16_t nbytes)
for (uint16_t i = 0; i < nbytes; i++)//L2CAP C-frame for (uint16_t i = 0; i < nbytes; i++)//L2CAP C-frame
buf[8 + i] = data[i]; buf[8 + i] = data[i];
uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ CSR_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf); uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf);
if(rcode) if(rcode)
{ {
#ifdef DEBUG #ifdef DEBUG
@ -1432,7 +1518,7 @@ void PS3BT::HID_Command(uint8_t* data, uint16_t nbytes)
if (dtimeHID <= 250)// Check if is has been more than 250ms since last command if (dtimeHID <= 250)// Check if is has been more than 250ms since last command
delay((uint32_t)(250 - dtimeHID));//There have to be a delay between commands delay((uint32_t)(250 - dtimeHID));//There have to be a delay between commands
pUsb->outTransfer(bAddress, epInfo[ CSR_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf); pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf);
timerHID = millis(); timerHID = millis();
} }
@ -1441,7 +1527,7 @@ void PS3BT::setAllOff()
for (uint8_t i = 0; i < OUTPUT_REPORT_BUFFER_SIZE; i++) for (uint8_t i = 0; i < OUTPUT_REPORT_BUFFER_SIZE; i++)
HIDBuffer[i + 2] = pgm_read_byte(&OUTPUT_REPORT_BUFFER[i]);//First two bytes reserved for report type and ID HIDBuffer[i + 2] = pgm_read_byte(&OUTPUT_REPORT_BUFFER[i]);//First two bytes reserved for report type and ID
HID_Command(HIDBuffer, OUTPUT_REPORT_BUFFER_SIZE + 2); HID_Command(HIDBuffer, HID_BUFFERSIZE);
} }
void PS3BT::setRumbleOff() void PS3BT::setRumbleOff()
{ {
@ -1450,7 +1536,7 @@ void PS3BT::setRumbleOff()
HIDBuffer[5] = 0x00; HIDBuffer[5] = 0x00;
HIDBuffer[6] = 0x00;//high mode off HIDBuffer[6] = 0x00;//high mode off
HID_Command(HIDBuffer, OUTPUT_REPORT_BUFFER_SIZE + 2); HID_Command(HIDBuffer, HID_BUFFERSIZE);
} }
void PS3BT::setRumbleOn(Rumble mode) void PS3BT::setRumbleOn(Rumble mode)
{ {
@ -1476,7 +1562,7 @@ void PS3BT::setRumbleOn(Rumble mode)
HIDBuffer[6] = 0;//high mode off HIDBuffer[6] = 0;//high mode off
} }
HID_Command(HIDBuffer, OUTPUT_REPORT_BUFFER_SIZE + 2); HID_Command(HIDBuffer, HID_BUFFERSIZE);
} }
} }
void PS3BT::setLedOff(LED a) void PS3BT::setLedOff(LED a)
@ -1487,18 +1573,18 @@ void PS3BT::setLedOff(LED a)
//set the LED into the write buffer //set the LED into the write buffer
HIDBuffer[11] = (uint8_t)((uint8_t)(((uint16_t)a & 0x0f) << 1) ^ HIDBuffer[11]); HIDBuffer[11] = (uint8_t)((uint8_t)(((uint16_t)a & 0x0f) << 1) ^ HIDBuffer[11]);
HID_Command(HIDBuffer, OUTPUT_REPORT_BUFFER_SIZE + 2); HID_Command(HIDBuffer, HID_BUFFERSIZE);
} }
} }
void PS3BT::setLedOn(LED a) void PS3BT::setLedOn(LED a)
{ {
HIDBuffer[11] = (uint8_t)((uint8_t)(((uint16_t)a & 0x0f) << 1) | HIDBuffer[11]); HIDBuffer[11] = (uint8_t)((uint8_t)(((uint16_t)a & 0x0f) << 1) | HIDBuffer[11]);
HID_Command(HIDBuffer, OUTPUT_REPORT_BUFFER_SIZE + 2); HID_Command(HIDBuffer, HID_BUFFERSIZE);
} }
void PS3BT::enable_sixaxis()//Command used to enable the Dualshock 3 and Navigation controller to send data via USB void PS3BT::enable_sixaxis()//Command used to enable the Dualshock 3 and Navigation controller to send data via USB
{ {
uint8_t cmd_buf[12]; uint8_t cmd_buf[6];
cmd_buf[0] = 0x53;// HID BT Set_report (0x50) | Report Type (Feature 0x03) cmd_buf[0] = 0x53;// HID BT Set_report (0x50) | Report Type (Feature 0x03)
cmd_buf[1] = 0xF4;// Report ID cmd_buf[1] = 0xF4;// Report ID
cmd_buf[2] = 0x42;// Special PS3 Controller enable commands cmd_buf[2] = 0x42;// Special PS3 Controller enable commands
@ -1530,7 +1616,7 @@ void PS3BT::HIDMove_Command(uint8_t* data,uint16_t nbytes)
if (dtimeHID <= 250)// Check if is has been less than 200ms since last command if (dtimeHID <= 250)// Check if is has been less than 200ms since last command
delay((uint32_t)(250 - dtimeHID));//There have to be a delay between commands delay((uint32_t)(250 - dtimeHID));//There have to be a delay between commands
pUsb->outTransfer(bAddress, epInfo[ CSR_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf); pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf);
timerHID = millis(); timerHID = millis();
} }
@ -1541,7 +1627,7 @@ void PS3BT::moveSetBulb(uint8_t r, uint8_t g, uint8_t b)//Use this to set the Co
HIDMoveBuffer[4] = g; HIDMoveBuffer[4] = g;
HIDMoveBuffer[5] = b; HIDMoveBuffer[5] = b;
HIDMove_Command(HIDMoveBuffer, HIDMOVEBUFFERSIZE); HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);
} }
void PS3BT::moveSetBulb(Colors color)//Use this to set the Color using the predefined colors in "enums.h" void PS3BT::moveSetBulb(Colors color)//Use this to set the Color using the predefined colors in "enums.h"
{ {
@ -1550,12 +1636,12 @@ void PS3BT::moveSetBulb(Colors color)//Use this to set the Color using the prede
HIDMoveBuffer[4] = (uint8_t)(color >> 8); HIDMoveBuffer[4] = (uint8_t)(color >> 8);
HIDMoveBuffer[5] = (uint8_t)(color); HIDMoveBuffer[5] = (uint8_t)(color);
HIDMove_Command(HIDMoveBuffer, HIDMOVEBUFFERSIZE); HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);
} }
void PS3BT::moveSetRumble(uint8_t rumble) void PS3BT::moveSetRumble(uint8_t rumble)
{ {
//set the rumble value into the write buffer //set the rumble value into the write buffer
HIDMoveBuffer[7] = rumble; HIDMoveBuffer[7] = rumble;
HIDMove_Command(HIDMoveBuffer, HIDMOVEBUFFERSIZE); HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);
} }

92
PS3BT.h
View file

@ -25,10 +25,7 @@
#endif #endif
#include "Usb.h" #include "Usb.h"
#include "confdescparser.h"
/*The application will work in reduced host mode, so we can save program and data
memory space. After verifying the PID and VID we will use known values for the
configuration values for device, interface, endpoints and HID */
/* CSR Bluetooth data taken from descriptors */ /* CSR Bluetooth data taken from descriptors */
#define INT_MAXPKTSIZE 16 // max size for HCI data #define INT_MAXPKTSIZE 16 // max size for HCI data
@ -39,35 +36,26 @@
/* Endpoint types */ /* Endpoint types */
#define EP_INTERRUPT 0x03 #define EP_INTERRUPT 0x03
#define EP_BULK 0x02
#define CSR_CONTROL_PIPE 0 // names we give to the 4 pipes /* Names we give to the 3 ps3 pipes - this is only used for setting the bluetooth address into the ps3 controllers */
#define CSR_EVENT_PIPE 1 #define PS3_CONTROL_PIPE 0
#define CSR_DATAIN_PIPE 2
#define CSR_DATAOUT_PIPE 3
#define PS3_CONTROL_PIPE 0 // names we give to the 3 pipes
#define PS3_OUTPUT_PIPE 1 #define PS3_OUTPUT_PIPE 1
#define PS3_INPUT_PIPE 2 #define PS3_INPUT_PIPE 2
//PID and VID of the different devices //PID and VID of the different devices
#define CSR_VID 0x0A12 //Cambridge Silicon Radio Ltd.
#define CSR_PID 0x0001 //Bluetooth HCI Device
#define PS3_VID 0x054C // Sony Corporation #define PS3_VID 0x054C // Sony Corporation
#define PS3_PID 0x0268 // PS3 Controller DualShock 3 #define PS3_PID 0x0268 // PS3 Controller DualShock 3
#define PS3NAVIGATION_VID 0x054C //Sony Corporation
#define PS3NAVIGATION_PID 0x042F // Navigation controller #define PS3NAVIGATION_PID 0x042F // Navigation controller
#define PS3MOVE_VID 0x054C //Sony Corporation
#define PS3MOVE_PID 0x03D5 // Motion controller #define PS3MOVE_PID 0x03D5 // Motion controller
#define HIDMOVEBUFFERSIZE 50 // size of the buffer for the Playstation Motion Controller #define HID_BUFFERSIZE 50 // size of the buffer for the Playstation Motion Controller
#define OUTPUT_REPORT_BUFFER_SIZE 48 //Size of the output report buffer for the controllers #define OUTPUT_REPORT_BUFFER_SIZE 48 //Size of the output report buffer for the controllers
// used in control endpoint header for HCI Commands // 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 bmREQ_HCI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
// used in control endpoint header for HID Commands // used in control endpoint header for HID Commands
#define bmREQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE #define bmREQ_HID_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
#define HID_REQUEST_SET_REPORT 0x09 #define HID_REQUEST_SET_REPORT 0x09
/* Bluetooth HCI states for hci_task() */ /* Bluetooth HCI states for hci_task() */
@ -84,19 +72,15 @@
/* HCI event flags*/ /* HCI event flags*/
#define HCI_FLAG_CMD_COMPLETE 0x01 #define HCI_FLAG_CMD_COMPLETE 0x01
#define HCI_FLAG_CMD_STATUS 0x02 #define HCI_FLAG_CONN_COMPLETE 0x02
#define HCI_FLAG_CONN_COMPLETE 0x04 #define HCI_FLAG_DISCONN_COMPLETE 0x04
#define HCI_FLAG_DISCONN_COMPLETE 0x08 #define HCI_FLAG_REMOTE_NAME_COMPLETE 0x08
#define HCI_FLAG_CONNECT_OK 0x10 #define HCI_FLAG_INCOMING_REQUEST 0x10
#define HCI_FLAG_REMOTE_NAME_COMPLETE 0x20
#define HCI_FLAG_INCOMING_REQUEST 0x40
/*Macros for HCI event flag tests */ /*Macros for HCI event flag tests */
#define hci_cmd_complete (hci_event_flag & HCI_FLAG_CMD_COMPLETE) #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_connect_complete (hci_event_flag & HCI_FLAG_CONN_COMPLETE)
#define hci_disconnect_complete (hci_event_flag & HCI_FLAG_DISCONN_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_remote_name_complete (hci_event_flag & HCI_FLAG_REMOTE_NAME_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) #define hci_incoming_connect_request (hci_event_flag & HCI_FLAG_INCOMING_REQUEST)
@ -111,6 +95,11 @@
#define EV_REMOTE_NAME_COMPLETE 0x07 #define EV_REMOTE_NAME_COMPLETE 0x07
#define EV_INCOMING_CONNECT 0x04 #define EV_INCOMING_CONNECT 0x04
#define EV_ROLE_CHANGED 0x12 #define EV_ROLE_CHANGED 0x12
#define EV_PAGE_SCAN_REP_MODE 0x20
#define EV_DATA_BUFFER_OVERFLOW 0x1A
#define EV_LOOPBACK_COMMAND 0x19
#define EV_CHANGE_CONNECTION_LINK 0x09
#define EV_AUTHENTICATION_COMPLETE 0x06
/* Bluetooth L2CAP states for L2CAP_task() */ /* Bluetooth L2CAP states for L2CAP_task() */
#define L2CAP_EV_WAIT 0 #define L2CAP_EV_WAIT 0
@ -121,9 +110,10 @@
#define L2CAP_EV_INTERRUPT_REQUEST 5 #define L2CAP_EV_INTERRUPT_REQUEST 5
#define L2CAP_EV_INTERRUPT_SUCCESS 6 #define L2CAP_EV_INTERRUPT_SUCCESS 6
#define L2CAP_EV_HID_ENABLE_SIXAXIS 7 #define L2CAP_EV_HID_ENABLE_SIXAXIS 7
#define L2CAP_EV_L2CAP_DONE 8 #define L2CAP_EV_HID_PS3_LED 8
#define L2CAP_EV_INTERRUPT_DISCONNECT 9 #define L2CAP_EV_L2CAP_DONE 9
#define L2CAP_EV_CONTROL_DISCONNECT 10 #define L2CAP_EV_INTERRUPT_DISCONNECT 10
#define L2CAP_EV_CONTROL_DISCONNECT 11
/* L2CAP event flags */ /* L2CAP event flags */
#define L2CAP_EV_CONTROL_CONNECTION_REQUEST 0x01 #define L2CAP_EV_CONTROL_CONNECTION_REQUEST 0x01
@ -162,7 +152,9 @@
#define PENDING 0x01 #define PENDING 0x01
#define SUCCESSFUL 0x00 #define SUCCESSFUL 0x00
#define bConfigurationValue 0x01 // Used to set configuration // Used to determine if it is a Bluetooth dongle
#define WI_SUBCLASS_RF 0x01
#define WI_PROTOCOL_BT 0x01
#define PS3_MAX_ENDPOINTS 4 #define PS3_MAX_ENDPOINTS 4
@ -321,9 +313,10 @@ enum Rumble
RumbleLow = 0x20, RumbleLow = 0x20,
}; };
class PS3BT : public USBDeviceConfig class PS3BT : public USBDeviceConfig, public UsbConfigXtracter
{ {
public: public:
PS3BT(USB *pUsb, uint8_t btadr5, uint8_t btadr4, uint8_t btadr3, uint8_t btadr2, uint8_t btadr1, uint8_t btadr0);
PS3BT(USB *pUsb); PS3BT(USB *pUsb);
// USBDeviceConfig implementation // USBDeviceConfig implementation
@ -331,6 +324,12 @@ public:
virtual uint8_t Release(); virtual uint8_t Release();
virtual uint8_t Poll(); virtual uint8_t Poll();
virtual uint8_t GetAddress() { return bAddress; }; virtual uint8_t GetAddress() { return bAddress; };
virtual bool isReady() { return bPollEnable; };
// UsbConfigXtracter implementation
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
bool isWatingForConnection() { return watingForConnection; }; // Use this to indicate when it is ready for a incoming connection
void setBdaddr(uint8_t* BDADDR); void setBdaddr(uint8_t* BDADDR);
void setMoveBdaddr(uint8_t* BDADDR); void setMoveBdaddr(uint8_t* BDADDR);
@ -339,8 +338,8 @@ public:
bool getButton(Button b); bool getButton(Button b);
uint8_t getAnalogButton(AnalogButton a); uint8_t getAnalogButton(AnalogButton a);
uint8_t getAnalogHat(AnalogHat a); uint8_t getAnalogHat(AnalogHat a);
uint32_t getSensor(Sensor a); int32_t getSensor(Sensor a);
double getAngle(Angle a, boolean resolution); double getAngle(Angle a);
bool getStatus(Status c); bool getStatus(Status c);
String getStatusString(); String getStatusString();
void disconnect(); // use this void to disconnect any of the controllers void disconnect(); // use this void to disconnect any of the controllers
@ -360,32 +359,49 @@ public:
bool PS3BTConnected;// Variable used to indicate if the normal playstation controller is successfully connected bool PS3BTConnected;// Variable used to indicate if the normal playstation controller is successfully connected
bool PS3MoveBTConnected;// Variable used to indicate if the move controller is successfully connected bool PS3MoveBTConnected;// Variable used to indicate if the move controller is successfully connected
bool PS3NavigationBTConnected;// Variable used to indicate if the navigation controller is successfully connected bool PS3NavigationBTConnected;// Variable used to indicate if the navigation controller is successfully connected
bool ButtonChanged;//Indicate if a button has been changed bool buttonChanged;//Indicate if a button has been changed
bool ButtonPressed;//Indicate if a button has been pressed bool buttonPressed;//Indicate if a button has been pressed
bool buttonReleased;//Indicate if a button has been pressed
protected: protected:
/* mandatory members */ /* mandatory members */
USB *pUsb; USB *pUsb;
uint8_t bAddress; uint8_t bAddress; // device address
EpInfo epInfo[PS3_MAX_ENDPOINTS]; //endpoint info structure EpInfo epInfo[PS3_MAX_ENDPOINTS]; //endpoint info structure
uint8_t bConfNum; // configuration number
uint8_t bNumEP; // total number of endpoints in the configuration
uint32_t qNextPollTime; // next poll time
#define BTD_CONTROL_PIPE 0 // Bluetooth dongles control endpoint
static const uint8_t BTD_EVENT_PIPE; // HCI event endpoint index
static const uint8_t BTD_DATAIN_PIPE; // ACL In endpoint index
static const uint8_t BTD_DATAOUT_PIPE; // ACL Out endpoint index
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
private: private:
bool bPollEnable; bool bPollEnable;
uint8_t pollInterval;
bool watingForConnection;
/*variables filled from HCI event management */ /*variables filled from HCI event management */
int16_t hci_handle; int16_t hci_handle;
uint8_t disc_bdaddr[6]; // maximum of three discovered devices uint8_t disc_bdaddr[6]; // the bluetooth address is always 6 bytes
uint8_t remote_name[30]; // first 30 chars of remote name uint8_t remote_name[30]; // first 30 chars of remote name
/* variables used by high level HCI task */ /* variables used by high level HCI task */
uint8_t hci_state; //current state of bluetooth hci connection uint8_t hci_state; //current state of bluetooth hci connection
uint16_t hci_counter; // counter used for bluetooth hci reset loops 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
/* variables used by high level L2CAP task */ /* variables used by high level L2CAP task */
uint8_t l2cap_state; uint8_t l2cap_state;
uint16_t l2cap_event_flag;// l2cap flags of received bluetooth events uint16_t l2cap_event_flag;// l2cap flags of received bluetooth events
unsigned long timer;
uint32_t ButtonState; uint32_t ButtonState;
uint32_t OldButtonState; uint32_t OldButtonState;
uint32_t timerHID;// timer used see if there has to be a delay before a new HID command uint32_t timerHID;// timer used see if there has to be a delay before a new HID command
@ -397,8 +413,8 @@ private:
uint8_t hcibuf[BULK_MAXPKTSIZE];//General purpose buffer for hci data uint8_t hcibuf[BULK_MAXPKTSIZE];//General purpose buffer for hci data
uint8_t l2capinbuf[BULK_MAXPKTSIZE];//General purpose buffer for l2cap in data uint8_t l2capinbuf[BULK_MAXPKTSIZE];//General purpose buffer for l2cap in data
uint8_t l2capoutbuf[BULK_MAXPKTSIZE];//General purpose buffer for l2cap out data uint8_t l2capoutbuf[BULK_MAXPKTSIZE];//General purpose buffer for l2cap out data
uint8_t HIDBuffer[BULK_MAXPKTSIZE];// Used to store HID commands uint8_t HIDBuffer[HID_BUFFERSIZE];// Used to store HID commands
uint8_t HIDMoveBuffer[HIDMOVEBUFFERSIZE];// Used to store HID commands for the Move controller uint8_t HIDMoveBuffer[HID_BUFFERSIZE];// Used to store HID commands for the Move controller
/* L2CAP Channels */ /* L2CAP Channels */
uint8_t control_scid[2];// L2CAP source CID for HID_Control uint8_t control_scid[2];// L2CAP source CID for HID_Control

View file

@ -6,9 +6,12 @@
#include <PS3BT.h> #include <PS3BT.h>
USB Usb; USB Usb;
PS3BT BT(&Usb); /* You can create the instance of the class in two ways */
PS3BT BT(&Usb); // This will just create the instance
//PS3BT BT(&Usb,0x00,0x15,0x83,0x3D,0x0A,0x57); // This will also store the bluetooth address - this can be obtained from the dongle when running the sketch
boolean printTemperature; boolean printTemperature;
boolean printAngle;
void setup() void setup()
{ {
@ -28,19 +31,19 @@ void loop()
if(BT.getAnalogHat(LeftHatX) > 137 || BT.getAnalogHat(LeftHatX) < 117 || BT.getAnalogHat(LeftHatY) > 137 || BT.getAnalogHat(LeftHatY) < 117 || BT.getAnalogHat(RightHatX) > 137 || BT.getAnalogHat(RightHatX) < 117 || BT.getAnalogHat(RightHatY) > 137 || BT.getAnalogHat(RightHatY) < 117) { if(BT.getAnalogHat(LeftHatX) > 137 || BT.getAnalogHat(LeftHatX) < 117 || BT.getAnalogHat(LeftHatY) > 137 || BT.getAnalogHat(LeftHatY) < 117 || BT.getAnalogHat(RightHatX) > 137 || BT.getAnalogHat(RightHatX) < 117 || BT.getAnalogHat(RightHatY) > 137 || BT.getAnalogHat(RightHatY) < 117) {
if(BT.getAnalogHat(LeftHatX) > 137 || BT.getAnalogHat(LeftHatX) < 117) { if(BT.getAnalogHat(LeftHatX) > 137 || BT.getAnalogHat(LeftHatX) < 117) {
Serial.print(F("LeftHatX: ")); Serial.print(F("LeftHatX: "));
Serial.print(BT.getAnalogHat(LeftHatX), DEC); Serial.print(BT.getAnalogHat(LeftHatX));
Serial.print("\t"); Serial.print("\t");
} if(BT.getAnalogHat(LeftHatY) > 137 || BT.getAnalogHat(LeftHatY) < 117) { } if(BT.getAnalogHat(LeftHatY) > 137 || BT.getAnalogHat(LeftHatY) < 117) {
Serial.print(F("LeftHatY: ")); Serial.print(F("LeftHatY: "));
Serial.print(BT.getAnalogHat(LeftHatY), DEC); Serial.print(BT.getAnalogHat(LeftHatY));
Serial.print("\t"); Serial.print("\t");
} if(BT.getAnalogHat(RightHatX) > 137 || BT.getAnalogHat(RightHatX) < 117) { } if(BT.getAnalogHat(RightHatX) > 137 || BT.getAnalogHat(RightHatX) < 117) {
Serial.print(F("RightHatX: ")); Serial.print(F("RightHatX: "));
Serial.print(BT.getAnalogHat(RightHatX), DEC); Serial.print(BT.getAnalogHat(RightHatX));
Serial.print("\t"); Serial.print("\t");
} if(BT.getAnalogHat(RightHatY) > 137 || BT.getAnalogHat(RightHatY) < 117) { } if(BT.getAnalogHat(RightHatY) > 137 || BT.getAnalogHat(RightHatY) < 117) {
Serial.print(F("RightHatY: ")); Serial.print(F("RightHatY: "));
Serial.print(BT.getAnalogHat(RightHatY), DEC); Serial.print(BT.getAnalogHat(RightHatY));
} }
Serial.println(""); Serial.println("");
} }
@ -49,16 +52,16 @@ void loop()
if(BT.getAnalogButton(L2_ANALOG) > 0 || BT.getAnalogButton(R2_ANALOG) > 0) { if(BT.getAnalogButton(L2_ANALOG) > 0 || BT.getAnalogButton(R2_ANALOG) > 0) {
if(BT.getAnalogButton(L2_ANALOG) > 0) { if(BT.getAnalogButton(L2_ANALOG) > 0) {
Serial.print(F("L2: ")); Serial.print(F("L2: "));
Serial.print(BT.getAnalogButton(L2_ANALOG), DEC); Serial.print(BT.getAnalogButton(L2_ANALOG));
Serial.print("\t"); Serial.print("\t");
} if(BT.getAnalogButton(R2_ANALOG) > 0) { } if(BT.getAnalogButton(R2_ANALOG) > 0) {
Serial.print(F("R2: ")); Serial.print(F("R2: "));
Serial.print(BT.getAnalogButton(R2_ANALOG), DEC); Serial.print(BT.getAnalogButton(R2_ANALOG));
} }
Serial.println(""); Serial.println("");
} }
if(BT.ButtonPressed) if(BT.buttonPressed)
{ {
Serial.print(F("PS3 Controller")); Serial.print(F("PS3 Controller"));
@ -109,19 +112,28 @@ void loop()
if(BT.getButton(SELECT)) { if(BT.getButton(SELECT)) {
Serial.print(F(" - Select - ")); Serial.print(F(" - Select - "));
Serial.print(BT.getStatusString()); Serial.print(BT.getStatusString());
} if(BT.getButton(START)) } if(BT.getButton(START)) {
Serial.print(F(" - Start")); Serial.print(F(" - Start"));
printAngle = !printAngle;
while(BT.getButton(START))
Usb.Task();
}
Serial.println(""); Serial.println("");
} }
} }
if(printAngle) {
Serial.print(F("Pitch: "));
Serial.print(BT.getAngle(Pitch));
Serial.print(F("\tRoll: "));
Serial.println(BT.getAngle(Roll));
}
} }
else if(BT.PS3MoveBTConnected) else if(BT.PS3MoveBTConnected)
{ {
if(BT.getAnalogButton(T_MOVE_ANALOG) > 0) { if(BT.getAnalogButton(T_MOVE_ANALOG) > 0) {
Serial.print(F("T: ")); Serial.print(F("T: "));
Serial.println(BT.getAnalogButton(T_MOVE_ANALOG), DEC); Serial.println(BT.getAnalogButton(T_MOVE_ANALOG));
} if(BT.ButtonPressed) { } if(BT.buttonPressed) {
Serial.print(F("PS3 Move Controller")); Serial.print(F("PS3 Move Controller"));
if(BT.getButton(PS_MOVE)) { if(BT.getButton(PS_MOVE)) {
@ -130,10 +142,14 @@ void loop()
} else { } else {
if(BT.getButton(SELECT_MOVE)) { if(BT.getButton(SELECT_MOVE)) {
Serial.print(F(" - Select")); Serial.print(F(" - Select"));
printTemperature = false; printTemperature = !printTemperature;
while(BT.getButton(SELECT_MOVE))
Usb.Task();
} if(BT.getButton(START_MOVE)) { } if(BT.getButton(START_MOVE)) {
Serial.print(F(" - Start")); Serial.print(F(" - Start"));
printTemperature = true; printAngle = !printAngle;
while(BT.getButton(START_MOVE))
Usb.Task();
} if(BT.getButton(TRIANGLE_MOVE)) { } if(BT.getButton(TRIANGLE_MOVE)) {
Serial.print(F(" - Triangle")); Serial.print(F(" - Triangle"));
BT.moveSetBulb(Red); BT.moveSetBulb(Red);
@ -158,10 +174,16 @@ void loop()
Serial.println(""); Serial.println("");
} }
} }
if(printTemperature) { if(printAngle) {
Serial.print(F("Pitch: "));
Serial.print(BT.getAngle(Pitch));
Serial.print(F("\tRoll: "));
Serial.println(BT.getAngle(Roll));
}
else if(printTemperature) {
String templow; String templow;
String temphigh; String temphigh;
String input = String(BT.getSensor(tempMove), DEC); String input = String(BT.getSensor(tempMove));
if (input.length() > 3) { if (input.length() > 3) {
temphigh = input.substring(0, 2); temphigh = input.substring(0, 2);

View file

@ -12,7 +12,7 @@ ADK adk(&Usb,"TKJElectronics", // Manufacturer Name
"http://www.tkjelectronics.dk/uploads/ArduinoBlinkLED.apk", // URL (web page to visit if no installed apps support the accessory) "http://www.tkjelectronics.dk/uploads/ArduinoBlinkLED.apk", // URL (web page to visit if no installed apps support the accessory)
"123456789"); // Serial Number (optional) "123456789"); // Serial Number (optional)
#define LED_RED 13 // Pin 13 is occupied by the SCK pin on a normal Arduino (Uno, Duemilanove etc.), so use a different pin #define LED 13 // Pin 13 is occupied by the SCK pin on a normal Arduino (Uno, Duemilanove etc.), so use a different pin
void setup() void setup()
{ {
@ -22,7 +22,7 @@ void setup()
Serial.print("\r\nOSCOKIRQ failed to assert"); Serial.print("\r\nOSCOKIRQ failed to assert");
while(1); //halt while(1); //halt
} }
pinMode(LED_RED, OUTPUT); pinMode(LED, OUTPUT);
} }
void loop() void loop()
@ -37,10 +37,9 @@ void loop()
if(len > 0) { if(len > 0) {
Serial.print(F("\r\nData Packet: ")); Serial.print(F("\r\nData Packet: "));
Serial.print(msg[0]); Serial.print(msg[0]);
digitalWrite(LED_RED,msg[0] ? HIGH : LOW); digitalWrite(LED,msg[0] ? HIGH : LOW);
} }
} }
else else
digitalWrite(LED_RED, LOW); digitalWrite(LED, LOW);
delay(10);
} }

View file

@ -34,8 +34,11 @@ moveSetRumble KEYWORD2
PS3BTConnected KEYWORD2 PS3BTConnected KEYWORD2
PS3MoveBTConnected KEYWORD2 PS3MoveBTConnected KEYWORD2
PS3NavigationBTConnected KEYWORD2 PS3NavigationBTConnected KEYWORD2
ButtonChanged KEYWORD2 buttonChanged KEYWORD2
ButtonPressed KEYWORD2 buttonPressed KEYWORD2
buttonReleased KEYWORD2
isWatingForConnection KEYWORD2
################################################ ################################################
# Constants and enums (LITERAL1) # Constants and enums (LITERAL1)