mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
Merge branch 'xxxajk' of github.com:felis/USB_Host_Shield_2.0 into xxxajk
This commit is contained in:
commit
0acad810b2
36 changed files with 1483 additions and 211 deletions
56
BTD.cpp
56
BTD.cpp
|
@ -36,7 +36,7 @@ qNextPollTime(0), // Reset NextPollTime
|
||||||
pollInterval(0),
|
pollInterval(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 < BTD_NUMSERVICES; i++)
|
for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
|
||||||
btService[i] = NULL;
|
btService[i] = NULL;
|
||||||
|
|
||||||
Initialize(); // Set all variables, endpoint structs etc. to default values
|
Initialize(); // Set all variables, endpoint structs etc. to default values
|
||||||
|
@ -293,7 +293,7 @@ void BTD::Initialize() {
|
||||||
epInfo[i].epAttribs = 0;
|
epInfo[i].epAttribs = 0;
|
||||||
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
||||||
}
|
}
|
||||||
for(i = 0; i < BTD_NUMSERVICES; i++) {
|
for(i = 0; i < BTD_NUM_SERVICES; i++) {
|
||||||
if(btService[i])
|
if(btService[i])
|
||||||
btService[i]->Reset(); // Reset all Bluetooth services
|
btService[i]->Reset(); // Reset all Bluetooth services
|
||||||
}
|
}
|
||||||
|
@ -302,6 +302,7 @@ void BTD::Initialize() {
|
||||||
incomingWii = false;
|
incomingWii = false;
|
||||||
connectToHIDDevice = false;
|
connectToHIDDevice = false;
|
||||||
incomingHIDDevice = false;
|
incomingHIDDevice = false;
|
||||||
|
incomingPS4 = false;
|
||||||
bAddress = 0; // Clear device address
|
bAddress = 0; // Clear device address
|
||||||
bNumEP = 1; // Must have to be reset to 1
|
bNumEP = 1; // Must have to be reset to 1
|
||||||
qNextPollTime = 0; // Reset next poll time
|
qNextPollTime = 0; // Reset next poll time
|
||||||
|
@ -434,7 +435,6 @@ void BTD::HCI_event_task() {
|
||||||
#endif
|
#endif
|
||||||
for(uint8_t i = 0; i < hcibuf[2]; i++) {
|
for(uint8_t i = 0; i < hcibuf[2]; i++) {
|
||||||
uint8_t offset = 8 * hcibuf[2] + 3 * i;
|
uint8_t offset = 8 * hcibuf[2] + 3 * i;
|
||||||
uint8_t classOfDevice[3];
|
|
||||||
|
|
||||||
for(uint8_t j = 0; j < 3; j++)
|
for(uint8_t j = 0; j < 3; j++)
|
||||||
classOfDevice[j] = hcibuf[j + 4 + offset];
|
classOfDevice[j] = hcibuf[j + 4 + offset];
|
||||||
|
@ -450,12 +450,14 @@ void BTD::HCI_event_task() {
|
||||||
|
|
||||||
hci_set_flag(HCI_FLAG_DEVICE_FOUND);
|
hci_set_flag(HCI_FLAG_DEVICE_FOUND);
|
||||||
break;
|
break;
|
||||||
} else if(pairWithHIDDevice && (classOfDevice[1] & 0x05) && (classOfDevice[0] & 0xC0)) { // Check if it is a mouse or keyboard - see: http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html
|
} else if(pairWithHIDDevice && (classOfDevice[1] & 0x05) && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad - see: http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
if(classOfDevice[0] & 0x80)
|
if(classOfDevice[0] & 0x80)
|
||||||
Notify(PSTR("\r\nMouse found"), 0x80);
|
Notify(PSTR("\r\nMouse found"), 0x80);
|
||||||
if(classOfDevice[0] & 0x40)
|
if(classOfDevice[0] & 0x40)
|
||||||
Notify(PSTR("\r\nKeyboard found"), 0x80);
|
Notify(PSTR("\r\nKeyboard found"), 0x80);
|
||||||
|
if(classOfDevice[0] & 0x08)
|
||||||
|
Notify(PSTR("\r\nGamepad found"), 0x80);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for(uint8_t j = 0; j < 6; j++)
|
for(uint8_t j = 0; j < 6; j++)
|
||||||
|
@ -516,23 +518,28 @@ void BTD::HCI_event_task() {
|
||||||
for(uint8_t i = 0; i < 6; i++)
|
for(uint8_t i = 0; i < 6; i++)
|
||||||
disc_bdaddr[i] = hcibuf[i + 2];
|
disc_bdaddr[i] = hcibuf[i + 2];
|
||||||
|
|
||||||
if((hcibuf[9] & 0x05) && (hcibuf[8] & 0xC0)) { // Check if it is a mouse or keyboard
|
for(uint8_t i = 0; i < 3; i++)
|
||||||
|
classOfDevice[i] = hcibuf[i + 8];
|
||||||
|
|
||||||
|
if((classOfDevice[1] & 0x05) && (classOfDevice[0] & 0xC8)) { // Check if it is a mouse, keyboard or a gamepad
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
if(hcibuf[8] & 0x80)
|
if(classOfDevice[0] & 0x80)
|
||||||
Notify(PSTR("\r\nMouse is connecting"), 0x80);
|
Notify(PSTR("\r\nMouse is connecting"), 0x80);
|
||||||
if(hcibuf[8] & 0x40)
|
if(classOfDevice[0] & 0x40)
|
||||||
Notify(PSTR("\r\nKeyboard is connecting"), 0x80);
|
Notify(PSTR("\r\nKeyboard is connecting"), 0x80);
|
||||||
|
if(classOfDevice[0] & 0x08)
|
||||||
|
Notify(PSTR("\r\nGamepad is connecting"), 0x80);
|
||||||
#endif
|
#endif
|
||||||
incomingHIDDevice = true;
|
incomingHIDDevice = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EXTRADEBUG
|
#ifdef EXTRADEBUG
|
||||||
Notify(PSTR("\r\nClass of device: "), 0x80);
|
Notify(PSTR("\r\nClass of device: "), 0x80);
|
||||||
D_PrintHex<uint8_t > (hcibuf[10], 0x80);
|
D_PrintHex<uint8_t > (classOfDevice[2], 0x80);
|
||||||
Notify(PSTR(" "), 0x80);
|
Notify(PSTR(" "), 0x80);
|
||||||
D_PrintHex<uint8_t > (hcibuf[9], 0x80);
|
D_PrintHex<uint8_t > (classOfDevice[1], 0x80);
|
||||||
Notify(PSTR(" "), 0x80);
|
Notify(PSTR(" "), 0x80);
|
||||||
D_PrintHex<uint8_t > (hcibuf[8], 0x80);
|
D_PrintHex<uint8_t > (classOfDevice[0], 0x80);
|
||||||
#endif
|
#endif
|
||||||
hci_set_flag(HCI_FLAG_INCOMING_REQUEST);
|
hci_set_flag(HCI_FLAG_INCOMING_REQUEST);
|
||||||
break;
|
break;
|
||||||
|
@ -789,11 +796,8 @@ void BTD::HCI_task() {
|
||||||
if(hci_check_flag(HCI_FLAG_REMOTE_NAME_COMPLETE)) {
|
if(hci_check_flag(HCI_FLAG_REMOTE_NAME_COMPLETE)) {
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef DEBUG_USB_HOST
|
||||||
Notify(PSTR("\r\nRemote Name: "), 0x80);
|
Notify(PSTR("\r\nRemote Name: "), 0x80);
|
||||||
for(uint8_t i = 0; i < 30; i++) {
|
for(uint8_t i = 0; i < strlen(remote_name); i++)
|
||||||
if(remote_name[i] == '\0') // End of string
|
|
||||||
break;
|
|
||||||
Notifyc(remote_name[i], 0x80);
|
Notifyc(remote_name[i], 0x80);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
if(strncmp((const char*)remote_name, "Nintendo", 8) == 0) {
|
if(strncmp((const char*)remote_name, "Nintendo", 8) == 0) {
|
||||||
incomingWii = true;
|
incomingWii = true;
|
||||||
|
@ -816,6 +820,12 @@ void BTD::HCI_task() {
|
||||||
wiiUProController = false;
|
wiiUProController = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(classOfDevice[2] == 0 && classOfDevice[1] == 0x25 && classOfDevice[0] == 0x08 && strncmp((const char*)remote_name, "Wireless Controller", 19) == 0) {
|
||||||
|
#ifdef DEBUG_USB_HOST
|
||||||
|
Notify(PSTR("\r\nPS4 controller is connecting"), 0x80);
|
||||||
|
#endif
|
||||||
|
incomingPS4 = true;
|
||||||
|
}
|
||||||
if(pairWithWii && motionPlusInside)
|
if(pairWithWii && motionPlusInside)
|
||||||
hci_state = HCI_CONNECT_DEVICE_STATE;
|
hci_state = HCI_CONNECT_DEVICE_STATE;
|
||||||
else {
|
else {
|
||||||
|
@ -835,6 +845,9 @@ void BTD::HCI_task() {
|
||||||
}
|
}
|
||||||
D_PrintHex<uint8_t > (disc_bdaddr[0], 0x80);
|
D_PrintHex<uint8_t > (disc_bdaddr[0], 0x80);
|
||||||
#endif
|
#endif
|
||||||
|
if(incomingPS4)
|
||||||
|
connectToHIDDevice = true; // We should always connect to the PS4 controller
|
||||||
|
|
||||||
// Clear these flags for a new connection
|
// Clear these flags for a new connection
|
||||||
l2capConnectionClaimed = false;
|
l2capConnectionClaimed = false;
|
||||||
sdpConnectionClaimed = false;
|
sdpConnectionClaimed = false;
|
||||||
|
@ -866,6 +879,7 @@ void BTD::HCI_task() {
|
||||||
|
|
||||||
connectToWii = incomingWii = pairWithWii = false;
|
connectToWii = incomingWii = pairWithWii = false;
|
||||||
connectToHIDDevice = incomingHIDDevice = pairWithHIDDevice = false;
|
connectToHIDDevice = incomingHIDDevice = pairWithHIDDevice = false;
|
||||||
|
incomingPS4 = false;
|
||||||
|
|
||||||
hci_state = HCI_SCANNING_STATE;
|
hci_state = HCI_SCANNING_STATE;
|
||||||
}
|
}
|
||||||
|
@ -881,7 +895,7 @@ void BTD::ACL_event_task() {
|
||||||
|
|
||||||
if(!rcode) { // Check for errors
|
if(!rcode) { // Check for errors
|
||||||
if(length > 0) { // Check if any data was read
|
if(length > 0) { // Check if any data was read
|
||||||
for(uint8_t i = 0; i < BTD_NUMSERVICES; i++) {
|
for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) {
|
||||||
if(btService[i])
|
if(btService[i])
|
||||||
btService[i]->ACLData(l2capinbuf);
|
btService[i]->ACLData(l2capinbuf);
|
||||||
}
|
}
|
||||||
|
@ -893,7 +907,7 @@ void BTD::ACL_event_task() {
|
||||||
D_PrintHex<uint8_t > (rcode, 0x80);
|
D_PrintHex<uint8_t > (rcode, 0x80);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
for(uint8_t i = 0; i < BTD_NUMSERVICES; i++)
|
for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
|
||||||
if(btService[i])
|
if(btService[i])
|
||||||
btService[i]->Run();
|
btService[i]->Run();
|
||||||
}
|
}
|
||||||
|
@ -967,7 +981,7 @@ void BTD::hci_accept_connection() {
|
||||||
hcibuf[6] = disc_bdaddr[3];
|
hcibuf[6] = disc_bdaddr[3];
|
||||||
hcibuf[7] = disc_bdaddr[4];
|
hcibuf[7] = disc_bdaddr[4];
|
||||||
hcibuf[8] = disc_bdaddr[5];
|
hcibuf[8] = disc_bdaddr[5];
|
||||||
hcibuf[9] = 0x00; //switch role to master
|
hcibuf[9] = 0x00; // Switch role to master
|
||||||
|
|
||||||
HCI_Command(hcibuf, 10);
|
HCI_Command(hcibuf, 10);
|
||||||
}
|
}
|
||||||
|
@ -983,10 +997,10 @@ void BTD::hci_remote_name() {
|
||||||
hcibuf[6] = disc_bdaddr[3];
|
hcibuf[6] = disc_bdaddr[3];
|
||||||
hcibuf[7] = disc_bdaddr[4];
|
hcibuf[7] = disc_bdaddr[4];
|
||||||
hcibuf[8] = disc_bdaddr[5];
|
hcibuf[8] = disc_bdaddr[5];
|
||||||
hcibuf[9] = 0x01; //Page Scan Repetition Mode
|
hcibuf[9] = 0x01; // Page Scan Repetition Mode
|
||||||
hcibuf[10] = 0x00; //Reserved
|
hcibuf[10] = 0x00; // Reserved
|
||||||
hcibuf[11] = 0x00; //Clock offset - low byte
|
hcibuf[11] = 0x00; // Clock offset - low byte
|
||||||
hcibuf[12] = 0x00; //Clock offset - high byte
|
hcibuf[12] = 0x00; // Clock offset - high byte
|
||||||
|
|
||||||
HCI_Command(hcibuf, 13);
|
HCI_Command(hcibuf, 13);
|
||||||
}
|
}
|
||||||
|
|
39
BTD.h
39
BTD.h
|
@ -187,7 +187,7 @@
|
||||||
#define WI_PROTOCOL_BT 0x01 // Bluetooth Programming Interface
|
#define WI_PROTOCOL_BT 0x01 // Bluetooth Programming Interface
|
||||||
|
|
||||||
#define BTD_MAX_ENDPOINTS 4
|
#define BTD_MAX_ENDPOINTS 4
|
||||||
#define BTD_NUMSERVICES 4 // Max number of Bluetooth services - if you need more than 4 simply increase this number
|
#define BTD_NUM_SERVICES 4 // Max number of Bluetooth services - if you need more than 4 simply increase this number
|
||||||
|
|
||||||
#define PAIR 1
|
#define PAIR 1
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ public:
|
||||||
|
|
||||||
/** @name USBDeviceConfig implementation */
|
/** @name USBDeviceConfig implementation */
|
||||||
/**
|
/**
|
||||||
* Address assignment and basic initilization is done here.
|
* Address assignment and basic initialization is done here.
|
||||||
* @param parent Hub number.
|
* @param parent Hub number.
|
||||||
* @param port Port number on the hub.
|
* @param port Port number on the hub.
|
||||||
* @param lowspeed Speed of the device.
|
* @param lowspeed Speed of the device.
|
||||||
|
@ -258,7 +258,7 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual uint8_t Release();
|
virtual uint8_t Release();
|
||||||
/**
|
/**
|
||||||
* Poll the USB Input endpoins and run the state machines.
|
* Poll the USB Input endpoints and run the state machines.
|
||||||
* @return 0 on success.
|
* @return 0 on success.
|
||||||
*/
|
*/
|
||||||
virtual uint8_t Poll();
|
virtual uint8_t Poll();
|
||||||
|
@ -320,18 +320,18 @@ public:
|
||||||
|
|
||||||
/** Disconnects both the L2CAP Channel and the HCI Connection for all Bluetooth services. */
|
/** Disconnects both the L2CAP Channel and the HCI Connection for all Bluetooth services. */
|
||||||
void disconnect() {
|
void disconnect() {
|
||||||
for(uint8_t i = 0; i < BTD_NUMSERVICES; i++)
|
for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++)
|
||||||
if(btService[i])
|
if(btService[i])
|
||||||
btService[i]->disconnect();
|
btService[i]->disconnect();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register bluetooth dongle members/services.
|
* Register Bluetooth dongle members/services.
|
||||||
* @param pService Pointer to BluetoothService class instance.
|
* @param pService Pointer to BluetoothService class instance.
|
||||||
* @return The serice ID on succes or -1 on fail.
|
* @return The service ID on success or -1 on fail.
|
||||||
*/
|
*/
|
||||||
int8_t registerServiceClass(BluetoothService *pService) {
|
int8_t registerServiceClass(BluetoothService *pService) {
|
||||||
for(uint8_t i = 0; i < BTD_NUMSERVICES; i++) {
|
for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) {
|
||||||
if(!btService[i]) {
|
if(!btService[i]) {
|
||||||
btService[i] = pService;
|
btService[i] = pService;
|
||||||
return i; // Return ID
|
return i; // Return ID
|
||||||
|
@ -488,7 +488,7 @@ public:
|
||||||
/** Last incoming devices Bluetooth address. */
|
/** Last incoming devices Bluetooth address. */
|
||||||
uint8_t disc_bdaddr[6];
|
uint8_t disc_bdaddr[6];
|
||||||
/** First 30 chars of last remote name. */
|
/** First 30 chars of last remote name. */
|
||||||
uint8_t remote_name[30];
|
char remote_name[30];
|
||||||
/**
|
/**
|
||||||
* The supported HCI Version read from the Bluetooth dongle.
|
* The supported HCI Version read from the Bluetooth dongle.
|
||||||
* Used by the PS3BT library to check the HCI Version of the Bluetooth dongle,
|
* Used by the PS3BT library to check the HCI Version of the Bluetooth dongle,
|
||||||
|
@ -501,7 +501,7 @@ public:
|
||||||
pairWithWii = true;
|
pairWithWii = true;
|
||||||
hci_state = HCI_CHECK_DEVICE_SERVICE;
|
hci_state = HCI_CHECK_DEVICE_SERVICE;
|
||||||
};
|
};
|
||||||
/** Used to only send the ACL data to the wiimote. */
|
/** Used to only send the ACL data to the Wiimote. */
|
||||||
bool connectToWii;
|
bool connectToWii;
|
||||||
/** True if a Wiimote is connecting. */
|
/** True if a Wiimote is connecting. */
|
||||||
bool incomingWii;
|
bool incomingWii;
|
||||||
|
@ -517,7 +517,7 @@ public:
|
||||||
pairWithHIDDevice = true;
|
pairWithHIDDevice = true;
|
||||||
hci_state = HCI_CHECK_DEVICE_SERVICE;
|
hci_state = HCI_CHECK_DEVICE_SERVICE;
|
||||||
};
|
};
|
||||||
/** Used to only send the ACL data to the wiimote. */
|
/** Used to only send the ACL data to the Wiimote. */
|
||||||
bool connectToHIDDevice;
|
bool connectToHIDDevice;
|
||||||
/** True if a Wiimote is connecting. */
|
/** True if a Wiimote is connecting. */
|
||||||
bool incomingHIDDevice;
|
bool incomingHIDDevice;
|
||||||
|
@ -564,23 +564,26 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Initialize(); // Set all variables, endpoint structs etc. to default values
|
void Initialize(); // Set all variables, endpoint structs etc. to default values
|
||||||
BluetoothService* btService[BTD_NUMSERVICES];
|
BluetoothService *btService[BTD_NUM_SERVICES];
|
||||||
|
|
||||||
uint16_t PID, VID; // PID and VID of device connected
|
uint16_t PID, VID; // PID and VID of device connected
|
||||||
|
|
||||||
uint8_t pollInterval;
|
uint8_t pollInterval;
|
||||||
bool bPollEnable;
|
bool bPollEnable;
|
||||||
|
|
||||||
|
bool incomingPS4; // True if a PS4 controller is connecting
|
||||||
|
uint8_t classOfDevice[3]; // Class of device of last device
|
||||||
|
|
||||||
/* 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
|
||||||
uint16_t hci_num_reset_loops; // this value indicate how many times it should read before trying to reset
|
uint16_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 inquiry_counter;
|
uint8_t inquiry_counter;
|
||||||
|
|
||||||
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[14]; //General purpose buffer for l2cap out data
|
uint8_t l2capoutbuf[14]; // General purpose buffer for L2CAP out data
|
||||||
|
|
||||||
/* State machines */
|
/* State machines */
|
||||||
void HCI_event_task(); // Poll the HCI event pipe
|
void HCI_event_task(); // Poll the HCI event pipe
|
||||||
|
|
20
BTHID.cpp
20
BTHID.cpp
|
@ -46,6 +46,7 @@ void BTHID::Reset() {
|
||||||
activeConnection = false;
|
activeConnection = false;
|
||||||
l2cap_event_flag = 0; // Reset flags
|
l2cap_event_flag = 0; // Reset flags
|
||||||
l2cap_state = L2CAP_WAIT;
|
l2cap_state = L2CAP_WAIT;
|
||||||
|
ResetBTHID();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BTHID::disconnect() { // Use this void to disconnect the device
|
void BTHID::disconnect() { // Use this void to disconnect the device
|
||||||
|
@ -188,21 +189,20 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
|
if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
|
||||||
switch(l2capinbuf[9]) {
|
|
||||||
case 0x01: // Keyboard events
|
|
||||||
if(pRptParser[KEYBOARD_PARSER_ID]) {
|
|
||||||
uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
|
uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
|
||||||
pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast<HID *>(this), 0, (uint8_t)length, &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
|
ParseBTHIDData((uint8_t)(length - 1), &l2capinbuf[9]);
|
||||||
}
|
|
||||||
|
switch(l2capinbuf[9]) {
|
||||||
|
case 0x01: // Keyboard or Joystick events
|
||||||
|
if(pRptParser[KEYBOARD_PARSER_ID])
|
||||||
|
pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast<HID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x02: // Mouse events
|
case 0x02: // Mouse events
|
||||||
if(pRptParser[MOUSE_PARSER_ID]) {
|
if(pRptParser[MOUSE_PARSER_ID])
|
||||||
uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
|
pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast<HID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
|
||||||
pRptParser[MOUSE_PARSER_ID]->Parse(reinterpret_cast<HID *>(this), 0, (uint8_t)length, &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
#ifdef DEBUG_USB_HOST
|
#ifdef EXTRADEBUG
|
||||||
default:
|
default:
|
||||||
Notify(PSTR("\r\nUnknown Report type: "), 0x80);
|
Notify(PSTR("\r\nUnknown Report type: "), 0x80);
|
||||||
D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
|
D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
|
||||||
|
|
53
BTHID.h
53
BTHID.h
|
@ -25,7 +25,7 @@
|
||||||
#define MOUSE_PARSER_ID 1
|
#define MOUSE_PARSER_ID 1
|
||||||
#define NUM_PARSERS 2
|
#define NUM_PARSERS 2
|
||||||
|
|
||||||
/** This BluetoothService class implements support for the HID keyboard and mice. */
|
/** This BluetoothService class implements support for Bluetooth HID devices. */
|
||||||
class BTHID : public BluetoothService {
|
class BTHID : public BluetoothService {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -48,7 +48,6 @@ public:
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
/** Used this to disconnect the devices. */
|
/** Used this to disconnect the devices. */
|
||||||
virtual void disconnect();
|
virtual void disconnect();
|
||||||
|
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,9 +105,40 @@ public:
|
||||||
pFuncOnInit = funcOnInit;
|
pFuncOnInit = funcOnInit;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
BTD *pBtd; // Pointer to BTD instance
|
/** @name Overridable functions */
|
||||||
|
/**
|
||||||
|
* Used to parse Bluetooth HID data to any class that inherits this class.
|
||||||
|
* @param len The length of the incoming data.
|
||||||
|
* @param buf Pointer to the data buffer.
|
||||||
|
*/
|
||||||
|
virtual void ParseBTHIDData(uint8_t len, uint8_t *buf) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
/** Called when a device is connected */
|
||||||
|
virtual void OnInitBTHID() {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
/** Used to reset any buffers in the class that inherits this */
|
||||||
|
virtual void ResetBTHID() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
/** Pointer to BTD instance */
|
||||||
|
BTD *pBtd;
|
||||||
|
|
||||||
|
/** HCI Handle for connection */
|
||||||
|
uint16_t hci_handle;
|
||||||
|
|
||||||
|
/** L2CAP source CID for HID_Control */
|
||||||
|
|
||||||
|
uint8_t control_scid[2];
|
||||||
|
|
||||||
|
/** L2CAP source CID for HID_Interrupt */
|
||||||
|
uint8_t interrupt_scid[2];
|
||||||
|
|
||||||
|
private:
|
||||||
HIDReportParser *pRptParser[NUM_PARSERS]; // Pointer to HIDReportParsers.
|
HIDReportParser *pRptParser[NUM_PARSERS]; // Pointer to HIDReportParsers.
|
||||||
|
|
||||||
/** Set report protocol. */
|
/** Set report protocol. */
|
||||||
|
@ -123,24 +153,19 @@ private:
|
||||||
void onInit() {
|
void onInit() {
|
||||||
if(pFuncOnInit)
|
if(pFuncOnInit)
|
||||||
pFuncOnInit(); // Call the user function
|
pFuncOnInit(); // Call the user function
|
||||||
|
OnInitBTHID();
|
||||||
};
|
};
|
||||||
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
|
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
|
||||||
|
|
||||||
void L2CAP_task(); // L2CAP state machine
|
void L2CAP_task(); // L2CAP state machine
|
||||||
|
|
||||||
/* Variables filled from HCI event management */
|
|
||||||
uint16_t hci_handle;
|
|
||||||
bool activeConnection; // Used to indicate if it already has established a connection
|
bool activeConnection; // Used to indicate if it already has established a connection
|
||||||
|
|
||||||
/* Variables used by high level L2CAP task */
|
/* Variables used for L2CAP communication */
|
||||||
|
uint8_t control_dcid[2]; // L2CAP device CID for HID_Control - Always 0x0070
|
||||||
|
uint8_t interrupt_dcid[2]; // L2CAP device CID for HID_Interrupt - Always 0x0071
|
||||||
|
uint8_t identifier; // Identifier for connection
|
||||||
uint8_t l2cap_state;
|
uint8_t l2cap_state;
|
||||||
uint32_t l2cap_event_flag; // l2cap flags of received Bluetooth events
|
uint32_t l2cap_event_flag; // l2cap flags of received Bluetooth events
|
||||||
|
|
||||||
/* L2CAP Channels */
|
|
||||||
uint8_t control_scid[2]; // L2CAP source CID for HID_Control
|
|
||||||
uint8_t control_dcid[2]; // 0x0070
|
|
||||||
uint8_t interrupt_scid[2]; // L2CAP source CID for HID_Interrupt
|
|
||||||
uint8_t interrupt_dcid[2]; // 0x0071
|
|
||||||
uint8_t identifier; // Identifier for connection
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -201,7 +201,7 @@ void PS3BT::printStatusString() {
|
||||||
} else
|
} else
|
||||||
strcpy_P(statusOutput, PSTR("Error"));
|
strcpy_P(statusOutput, PSTR("Error"));
|
||||||
|
|
||||||
USB_HOST_SERIAL.write((uint8_t*)statusOutput, strlen(statusOutput));
|
USB_HOST_SERIAL.write(statusOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PS3BT::Reset() {
|
void PS3BT::Reset() {
|
||||||
|
@ -343,6 +343,8 @@ void PS3BT::ACLData(uint8_t* ACLData) {
|
||||||
if(PS3Connected || PS3MoveConnected || PS3NavigationConnected) {
|
if(PS3Connected || PS3MoveConnected || PS3NavigationConnected) {
|
||||||
/* Read Report */
|
/* Read Report */
|
||||||
if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
|
if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
|
||||||
|
lastMessageTime = millis(); // Store the last message time
|
||||||
|
|
||||||
if(PS3Connected || PS3NavigationConnected)
|
if(PS3Connected || PS3NavigationConnected)
|
||||||
ButtonState = (uint32_t)(l2capinbuf[11] | ((uint16_t)l2capinbuf[12] << 8) | ((uint32_t)l2capinbuf[13] << 16));
|
ButtonState = (uint32_t)(l2capinbuf[11] | ((uint16_t)l2capinbuf[12] << 8) | ((uint32_t)l2capinbuf[13] << 16));
|
||||||
else if(PS3MoveConnected)
|
else if(PS3MoveConnected)
|
||||||
|
|
9
PS3BT.h
9
PS3BT.h
|
@ -179,6 +179,11 @@ public:
|
||||||
*/
|
*/
|
||||||
void moveSetRumble(uint8_t rumble);
|
void moveSetRumble(uint8_t rumble);
|
||||||
|
|
||||||
|
/** Used to get the millis() of the last message */
|
||||||
|
uint32_t getLastMessageTime() {
|
||||||
|
return lastMessageTime;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to call your own function when the controller is successfully initialized.
|
* Used to call your own function when the controller is successfully initialized.
|
||||||
* @param funcOnInit Function to call.
|
* @param funcOnInit Function to call.
|
||||||
|
@ -214,10 +219,12 @@ private:
|
||||||
uint8_t remote_name[30]; // First 30 chars of remote name
|
uint8_t remote_name[30]; // First 30 chars of remote name
|
||||||
bool activeConnection; // Used to indicate if it's already has established a connection
|
bool activeConnection; // Used to indicate if it's already has established a connection
|
||||||
|
|
||||||
/* variables used by high level L2CAP task */
|
/* Variables used by high level L2CAP task */
|
||||||
uint8_t l2cap_state;
|
uint8_t l2cap_state;
|
||||||
uint32_t l2cap_event_flag; // L2CAP flags of received Bluetooth events
|
uint32_t l2cap_event_flag; // L2CAP flags of received Bluetooth events
|
||||||
|
|
||||||
|
uint32_t lastMessageTime; // Variable used to store the millis value of the last message.
|
||||||
|
|
||||||
unsigned long timer;
|
unsigned long timer;
|
||||||
|
|
||||||
uint32_t ButtonState;
|
uint32_t ButtonState;
|
||||||
|
|
79
PS3Enums.h
79
PS3Enums.h
|
@ -56,8 +56,7 @@ const uint8_t PS3_LEDS[] PROGMEM = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buttons on the controllers
|
* Buttons on the controllers.
|
||||||
*
|
|
||||||
* <B>Note:</B> that the location is shifted 9 when it's connected via USB.
|
* <B>Note:</B> that the location is shifted 9 when it's connected via USB.
|
||||||
*/
|
*/
|
||||||
const uint32_t PS3_BUTTONS[] PROGMEM = {
|
const uint32_t PS3_BUTTONS[] PROGMEM = {
|
||||||
|
@ -87,8 +86,7 @@ const uint32_t PS3_BUTTONS[] PROGMEM = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analog buttons on the controllers
|
* Analog buttons on the controllers.
|
||||||
*
|
|
||||||
* <B>Note:</B> that the location is shifted 9 when it's connected via USB.
|
* <B>Note:</B> that the location is shifted 9 when it's connected via USB.
|
||||||
*/
|
*/
|
||||||
const uint8_t PS3_ANALOG_BUTTONS[] PROGMEM = {
|
const uint8_t PS3_ANALOG_BUTTONS[] PROGMEM = {
|
||||||
|
@ -112,74 +110,6 @@ const uint8_t PS3_ANALOG_BUTTONS[] PROGMEM = {
|
||||||
15, // T_ANALOG - Both at byte 14 (last reading) and byte 15 (current reading)
|
15, // T_ANALOG - Both at byte 14 (last reading) and byte 15 (current reading)
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Used to set the colors of the move controller. */
|
|
||||||
enum ColorsEnum {
|
|
||||||
/** r = 255, g = 0, b = 0 */
|
|
||||||
Red = 0xFF0000,
|
|
||||||
/** r = 0, g = 255, b = 0 */
|
|
||||||
Green = 0xFF00,
|
|
||||||
/** r = 0, g = 0, b = 255 */
|
|
||||||
Blue = 0xFF,
|
|
||||||
|
|
||||||
/** r = 255, g = 235, b = 4 */
|
|
||||||
Yellow = 0xFFEB04,
|
|
||||||
/** r = 0, g = 255, b = 255 */
|
|
||||||
Lightblue = 0xFFFF,
|
|
||||||
/** r = 255, g = 0, b = 255 */
|
|
||||||
Purble = 0xFF00FF,
|
|
||||||
|
|
||||||
/** r = 255, g = 255, b = 255 */
|
|
||||||
White = 0xFFFFFF,
|
|
||||||
/** r = 0, g = 0, b = 0 */
|
|
||||||
Off = 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sensors inside the Sixaxis Dualshock 3 and Move controller.
|
|
||||||
*
|
|
||||||
* <B>Note:</B> that the location is shifted 9 when it's connected via USB.
|
|
||||||
*/
|
|
||||||
enum SensorEnum {
|
|
||||||
/** Accelerometer x-axis */
|
|
||||||
aX = 50,
|
|
||||||
/** Accelerometer y-axis */
|
|
||||||
aY = 52,
|
|
||||||
/** Accelerometer z-axis */
|
|
||||||
aZ = 54,
|
|
||||||
/** Gyro z-axis */
|
|
||||||
gZ = 56,
|
|
||||||
|
|
||||||
/** Accelerometer x-axis */
|
|
||||||
aXmove = 28,
|
|
||||||
/** Accelerometer z-axis */
|
|
||||||
aZmove = 30,
|
|
||||||
/** Accelerometer y-axis */
|
|
||||||
aYmove = 32,
|
|
||||||
|
|
||||||
/** Gyro x-axis */
|
|
||||||
gXmove = 40,
|
|
||||||
/** Gyro z-axis */
|
|
||||||
gZmove = 42,
|
|
||||||
/** Gyro y-axis */
|
|
||||||
gYmove = 44,
|
|
||||||
|
|
||||||
/** Temperature sensor */
|
|
||||||
tempMove = 46,
|
|
||||||
|
|
||||||
/** Magnetometer x-axis */
|
|
||||||
mXmove = 47,
|
|
||||||
/** Magnetometer z-axis */
|
|
||||||
mZmove = 49,
|
|
||||||
/** Magnetometer y-axis */
|
|
||||||
mYmove = 50,
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Used to get the angle calculated using the accelerometer. */
|
|
||||||
enum AngleEnum {
|
|
||||||
Pitch = 0x01,
|
|
||||||
Roll = 0x02,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum StatusEnum {
|
enum StatusEnum {
|
||||||
// Note that the location is shifted 9 when it's connected via USB
|
// Note that the location is shifted 9 when it's connected via USB
|
||||||
// Byte location | bit location
|
// Byte location | bit location
|
||||||
|
@ -208,9 +138,4 @@ enum StatusEnum {
|
||||||
Bluetooth = (40 << 8) | 0x16, // Operating by Bluetooth and rumble is turned off
|
Bluetooth = (40 << 8) | 0x16, // Operating by Bluetooth and rumble is turned off
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RumbleEnum {
|
|
||||||
RumbleHigh = 0x10,
|
|
||||||
RumbleLow = 0x20,
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -392,7 +392,7 @@ void PS3USB::printStatusString() {
|
||||||
} else
|
} else
|
||||||
strcpy_P(statusOutput, PSTR("Error"));
|
strcpy_P(statusOutput, PSTR("Error"));
|
||||||
|
|
||||||
USB_HOST_SERIAL.write((uint8_t*)statusOutput, strlen(statusOutput));
|
USB_HOST_SERIAL.write(statusOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Playstation Sixaxis Dualshock and Navigation Controller commands */
|
/* Playstation Sixaxis Dualshock and Navigation Controller commands */
|
||||||
|
|
132
PS4BT.h
Normal file
132
PS4BT.h
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
/* Copyright (C) 2014 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 _ps4bt_h_
|
||||||
|
#define _ps4bt_h_
|
||||||
|
|
||||||
|
#include "BTHID.h"
|
||||||
|
#include "PS4Parser.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements support for the PS4 controller via Bluetooth.
|
||||||
|
* It uses the BTHID class for all the Bluetooth communication.
|
||||||
|
*/
|
||||||
|
class PS4BT : public BTHID, public PS4Parser {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor for the PS4BT class.
|
||||||
|
* @param p Pointer to the BTD class instance.
|
||||||
|
* @param pair Set this to true in order to pair with the device. If the argument is omitted then it will not pair with it. One can use ::PAIR to set it to true.
|
||||||
|
* @param pin Write the pin to BTD#btdPin. If argument is omitted, then "0000" will be used.
|
||||||
|
*/
|
||||||
|
PS4BT(BTD *p, bool pair = false, const char *pin = "0000") :
|
||||||
|
BTHID(p, pair, pin) {
|
||||||
|
PS4Parser::Reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to check if a PS4 controller is connected.
|
||||||
|
* @return Returns true if it is connected.
|
||||||
|
*/
|
||||||
|
bool connected() {
|
||||||
|
return BTHID::connected;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to call your own function when the device is successfully initialized.
|
||||||
|
* @param funcOnInit Function to call.
|
||||||
|
*/
|
||||||
|
void attachOnInit(void (*funcOnInit)(void)) {
|
||||||
|
pFuncOnInit = funcOnInit;
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** @name BTHID implementation */
|
||||||
|
/**
|
||||||
|
* Used to parse Bluetooth HID data.
|
||||||
|
* @param bthid Pointer to the BTHID class.
|
||||||
|
* @param len The length of the incoming data.
|
||||||
|
* @param buf Pointer to the data buffer.
|
||||||
|
*/
|
||||||
|
virtual void ParseBTHIDData(uint8_t len, uint8_t *buf) {
|
||||||
|
PS4Parser::Parse(len, buf);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a device is successfully initialized.
|
||||||
|
* Use attachOnInit(void (*funcOnInit)(void)) to call your own function.
|
||||||
|
* This is useful for instance if you want to set the LEDs in a specific way.
|
||||||
|
*/
|
||||||
|
virtual void OnInitBTHID() {
|
||||||
|
PS4Parser::Reset();
|
||||||
|
enable_sixaxis(); // Make the controller send out the entire output report
|
||||||
|
if (pFuncOnInit)
|
||||||
|
pFuncOnInit(); // Call the user function
|
||||||
|
else
|
||||||
|
setLed(Blue);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Used to reset the different buffers to there default values */
|
||||||
|
virtual void ResetBTHID() {
|
||||||
|
PS4Parser::Reset();
|
||||||
|
};
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
/** @name PS4Parser implementation */
|
||||||
|
virtual void sendOutputReport(PS4Output *output) { // Source: https://github.com/chrippa/ds4drv
|
||||||
|
uint8_t buf[79];
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
|
buf[0] = 0x52; // HID BT Set_report (0x50) | Report Type (Output 0x02)
|
||||||
|
buf[1] = 0x11; // Report ID
|
||||||
|
buf[2] = 0x80;
|
||||||
|
buf[4]= 0xFF;
|
||||||
|
|
||||||
|
buf[7] = output->smallRumble; // Small Rumble
|
||||||
|
buf[8] = output->bigRumble; // Big rumble
|
||||||
|
|
||||||
|
buf[9] = output->r; // Red
|
||||||
|
buf[10] = output->g; // Green
|
||||||
|
buf[11] = output->b; // Blue
|
||||||
|
|
||||||
|
buf[12] = output->flashOn; // Time to flash bright (255 = 2.5 seconds)
|
||||||
|
buf[13] = output->flashOff; // Time to flash dark (255 = 2.5 seconds)
|
||||||
|
|
||||||
|
output->reportChanged = false;
|
||||||
|
|
||||||
|
// The PS4 console actually set the four last bytes to a CRC32 checksum, but it seems like it is actually not needed
|
||||||
|
|
||||||
|
HID_Command(buf, sizeof(buf));
|
||||||
|
};
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
private:
|
||||||
|
void enable_sixaxis() { // Command used to make the PS4 controller send out the entire output report
|
||||||
|
uint8_t buf[2];
|
||||||
|
buf[0] = 0x43; // HID BT Get_report (0x40) | Report Type (Feature 0x03)
|
||||||
|
buf[1] = 0x02; // Report ID
|
||||||
|
|
||||||
|
HID_Command(buf, 2);
|
||||||
|
};
|
||||||
|
|
||||||
|
void HID_Command(uint8_t *data, uint8_t nbytes) {
|
||||||
|
pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]);
|
||||||
|
};
|
||||||
|
|
||||||
|
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
|
||||||
|
};
|
||||||
|
#endif
|
109
PS4Parser.cpp
Normal file
109
PS4Parser.cpp
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
/* Copyright (C) 2014 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 "PS4Parser.h"
|
||||||
|
|
||||||
|
// To enable serial debugging see "settings.h"
|
||||||
|
//#define PRINTREPORT // Uncomment to print the report send by the PS4 Controller
|
||||||
|
|
||||||
|
bool PS4Parser::checkDpad(ButtonEnum b) {
|
||||||
|
switch (b) {
|
||||||
|
case UP:
|
||||||
|
return ps4Data.btn.dpad == DPAD_LEFT_UP || ps4Data.btn.dpad == DPAD_UP || ps4Data.btn.dpad == DPAD_UP_RIGHT;
|
||||||
|
case RIGHT:
|
||||||
|
return ps4Data.btn.dpad == DPAD_UP_RIGHT || ps4Data.btn.dpad == DPAD_RIGHT || ps4Data.btn.dpad == DPAD_RIGHT_DOWN;
|
||||||
|
case DOWN:
|
||||||
|
return ps4Data.btn.dpad == DPAD_RIGHT_DOWN || ps4Data.btn.dpad == DPAD_DOWN || ps4Data.btn.dpad == DPAD_DOWN_LEFT;
|
||||||
|
case LEFT:
|
||||||
|
return ps4Data.btn.dpad == DPAD_DOWN_LEFT || ps4Data.btn.dpad == DPAD_LEFT || ps4Data.btn.dpad == DPAD_LEFT_UP;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PS4Parser::getButtonPress(ButtonEnum b) {
|
||||||
|
if (b <= LEFT) // Dpad
|
||||||
|
return checkDpad(b);
|
||||||
|
else
|
||||||
|
return ps4Data.btn.val & (1UL << pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PS4Parser::getButtonClick(ButtonEnum b) {
|
||||||
|
uint32_t mask = 1UL << pgm_read_byte(&PS4_BUTTONS[(uint8_t)b]);
|
||||||
|
bool click = buttonClickState.val & mask;
|
||||||
|
buttonClickState.val &= ~mask; // Clear "click" event
|
||||||
|
return click;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t PS4Parser::getAnalogButton(ButtonEnum b) {
|
||||||
|
if (b == L2) // These are the only analog buttons on the controller
|
||||||
|
return ps4Data.trigger[0];
|
||||||
|
else if (b == R2)
|
||||||
|
return ps4Data.trigger[1];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t PS4Parser::getAnalogHat(AnalogHatEnum a) {
|
||||||
|
return ps4Data.hatValue[(uint8_t)a];
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS4Parser::Parse(uint8_t len, uint8_t *buf) {
|
||||||
|
if (len > 0 && buf) {
|
||||||
|
#ifdef PRINTREPORT
|
||||||
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
|
D_PrintHex<uint8_t > (buf[i], 0x80);
|
||||||
|
Notify(PSTR(" "), 0x80);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (buf[0] == 0x01) // Check report ID
|
||||||
|
memcpy(&ps4Data, buf + 1, min(len - 1, sizeof(ps4Data)));
|
||||||
|
else if (buf[0] == 0x11) // This report is send via Bluetooth, it has an offset of 2 compared to the USB data
|
||||||
|
memcpy(&ps4Data, buf + 3, min(len - 3, sizeof(ps4Data)));
|
||||||
|
else {
|
||||||
|
#ifdef DEBUG_USB_HOST
|
||||||
|
Notify(PSTR("\r\nUnknown report id: "), 0x80);
|
||||||
|
D_PrintHex<uint8_t > (buf[0], 0x80);
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps4Data.btn.val != oldButtonState.val) { // Check if anything has changed
|
||||||
|
buttonClickState.val = ps4Data.btn.val & ~oldButtonState.val; // Update click state variable
|
||||||
|
oldButtonState.val = ps4Data.btn.val;
|
||||||
|
|
||||||
|
// The DPAD buttons does not set the different bits, but set a value corresponding to the buttons pressed, we will simply set the bits ourself
|
||||||
|
uint8_t newDpad = 0;
|
||||||
|
if (checkDpad(UP))
|
||||||
|
newDpad |= 1 << UP;
|
||||||
|
if (checkDpad(RIGHT))
|
||||||
|
newDpad |= 1 << RIGHT;
|
||||||
|
if (checkDpad(DOWN))
|
||||||
|
newDpad |= 1 << DOWN;
|
||||||
|
if (checkDpad(LEFT))
|
||||||
|
newDpad |= 1 << LEFT;
|
||||||
|
if (newDpad != oldDpad) {
|
||||||
|
buttonClickState.dpad = newDpad & ~oldDpad; // Override values
|
||||||
|
oldDpad = newDpad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps4Output.reportChanged)
|
||||||
|
sendOutputReport(&ps4Output); // Send output report
|
||||||
|
}
|
364
PS4Parser.h
Normal file
364
PS4Parser.h
Normal file
|
@ -0,0 +1,364 @@
|
||||||
|
/* Copyright (C) 2014 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 _ps4parser_h_
|
||||||
|
#define _ps4parser_h_
|
||||||
|
|
||||||
|
#include "Usb.h"
|
||||||
|
#include "controllerEnums.h"
|
||||||
|
|
||||||
|
/** Buttons on the controller */
|
||||||
|
const uint8_t PS4_BUTTONS[] PROGMEM = {
|
||||||
|
UP, // UP
|
||||||
|
RIGHT, // RIGHT
|
||||||
|
DOWN, // DOWN
|
||||||
|
LEFT, // LEFT
|
||||||
|
|
||||||
|
0x0C, // SHARE
|
||||||
|
0x0D, // OPTIONS
|
||||||
|
0x0E, // L3
|
||||||
|
0x0F, // R3
|
||||||
|
|
||||||
|
0x0A, // L2
|
||||||
|
0x0B, // R2
|
||||||
|
0x08, // L1
|
||||||
|
0x09, // R1
|
||||||
|
|
||||||
|
0x07, // TRIANGLE
|
||||||
|
0x06, // CIRCLE
|
||||||
|
0x05, // CROSS
|
||||||
|
0x04, // SQUARE
|
||||||
|
|
||||||
|
0x10, // PS
|
||||||
|
0x11, // TOUCHPAD
|
||||||
|
};
|
||||||
|
|
||||||
|
union PS4Buttons {
|
||||||
|
struct {
|
||||||
|
uint8_t dpad : 4;
|
||||||
|
uint8_t square : 1;
|
||||||
|
uint8_t cross : 1;
|
||||||
|
uint8_t circle : 1;
|
||||||
|
uint8_t triangle : 1;
|
||||||
|
|
||||||
|
uint8_t l1 : 1;
|
||||||
|
uint8_t r1 : 1;
|
||||||
|
uint8_t l2 : 1;
|
||||||
|
uint8_t r2 : 1;
|
||||||
|
uint8_t share : 1;
|
||||||
|
uint8_t options : 1;
|
||||||
|
uint8_t l3 : 1;
|
||||||
|
uint8_t r3 : 1;
|
||||||
|
|
||||||
|
uint8_t ps : 1;
|
||||||
|
uint8_t touchpad : 1;
|
||||||
|
uint8_t reportCounter : 6;
|
||||||
|
} __attribute__((packed));
|
||||||
|
uint32_t val : 24;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct touchpadXY {
|
||||||
|
uint8_t dummy; // I can not figure out what this data is for, it seems to change randomly, maybe a timestamp?
|
||||||
|
struct {
|
||||||
|
uint8_t counter : 7; // Increments every time a finger is touching the touchpad
|
||||||
|
uint8_t touching : 1; // The top bit is cleared if the finger is touching the touchpad
|
||||||
|
uint16_t x : 12;
|
||||||
|
uint16_t y : 12;
|
||||||
|
} __attribute__((packed)) finger[2]; // 0 = first finger, 1 = second finger
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct PS4Data {
|
||||||
|
/* Button and joystick values */
|
||||||
|
uint8_t hatValue[4];
|
||||||
|
PS4Buttons btn;
|
||||||
|
uint8_t trigger[2];
|
||||||
|
|
||||||
|
/* Gyro and accelerometer values */
|
||||||
|
uint8_t dummy[3]; // First two looks random, while the third one might be some kind of status - it increments once in a while
|
||||||
|
int16_t gyroY, gyroZ, gyroX;
|
||||||
|
int16_t accX, accZ, accY;
|
||||||
|
|
||||||
|
/* The rest is data for the touchpad */
|
||||||
|
uint8_t dummy2[9]; // Byte 5 looks like some kind of status (maybe battery status), bit 1 of byte 8 is set every time a finger is moving around the touchpad
|
||||||
|
touchpadXY xy[3]; // It looks like it sends out three coordinates each time, this might be because the microcontroller inside the PS4 controller is much faster than the Bluetooth connection.
|
||||||
|
// The last data is read from the last position in the array while the oldest measurement is from the first position.
|
||||||
|
// The first position will also keep it's value after the finger is released, while the other two will set them to zero.
|
||||||
|
// Note that if you read fast enough from the device, then only the first one will contain any data.
|
||||||
|
|
||||||
|
// The last three bytes are always: 0x00, 0x80, 0x00
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct PS4Output {
|
||||||
|
uint8_t bigRumble, smallRumble; // Rumble
|
||||||
|
uint8_t r, g, b; // RGB
|
||||||
|
uint8_t flashOn, flashOff; // Time to flash bright/dark (255 = 2.5 seconds)
|
||||||
|
bool reportChanged; // The data is send when data is received from the controller
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
enum DPADEnum {
|
||||||
|
DPAD_UP = 0x0,
|
||||||
|
DPAD_UP_RIGHT = 0x1,
|
||||||
|
DPAD_RIGHT = 0x2,
|
||||||
|
DPAD_RIGHT_DOWN = 0x3,
|
||||||
|
DPAD_DOWN = 0x4,
|
||||||
|
DPAD_DOWN_LEFT = 0x5,
|
||||||
|
DPAD_LEFT = 0x6,
|
||||||
|
DPAD_LEFT_UP = 0x7,
|
||||||
|
DPAD_OFF = 0x8,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** This class parses all the data sent by the PS4 controller */
|
||||||
|
class PS4Parser {
|
||||||
|
public:
|
||||||
|
/** Constructor for the PS4Parser class. */
|
||||||
|
PS4Parser() {
|
||||||
|
Reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @name PS4 Controller functions */
|
||||||
|
/**
|
||||||
|
* getButtonPress(ButtonEnum b) will return true as long as the button is held down.
|
||||||
|
*
|
||||||
|
* While getButtonClick(ButtonEnum b) will only return it once.
|
||||||
|
*
|
||||||
|
* So you instance if you need to increase a variable once you would use getButtonClick(ButtonEnum b),
|
||||||
|
* but if you need to drive a robot forward you would use getButtonPress(ButtonEnum b).
|
||||||
|
* @param b ::ButtonEnum to read.
|
||||||
|
* @return getButtonPress(ButtonEnum b) will return a true as long as a button is held down, while getButtonClick(ButtonEnum b) will return true once for each button press.
|
||||||
|
*/
|
||||||
|
bool getButtonPress(ButtonEnum b);
|
||||||
|
bool getButtonClick(ButtonEnum b);
|
||||||
|
/**@}*/
|
||||||
|
/** @name PS4 Controller functions */
|
||||||
|
/**
|
||||||
|
* Used to get the analog value from button presses.
|
||||||
|
* @param b The ::ButtonEnum to read.
|
||||||
|
* The supported buttons are:
|
||||||
|
* ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2,
|
||||||
|
* ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T.
|
||||||
|
* @return Analog value in the range of 0-255.
|
||||||
|
*/
|
||||||
|
uint8_t getAnalogButton(ButtonEnum b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to read the analog joystick.
|
||||||
|
* @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY.
|
||||||
|
* @return Return the analog value in the range of 0-255.
|
||||||
|
*/
|
||||||
|
uint8_t getAnalogHat(AnalogHatEnum a);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the x-coordinate of the touchpad. Position 0 is in the top left.
|
||||||
|
* @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
|
||||||
|
* @param xyId The controller sends out three packets with the same structure.
|
||||||
|
* The third one will contain the last measure, but if you read from the controller then there is only be data in the first one.
|
||||||
|
* For that reason it will be set to 0 if the argument is omitted.
|
||||||
|
* @return Returns the x-coordinate of the finger.
|
||||||
|
*/
|
||||||
|
uint16_t getX(uint8_t finger = 0, uint8_t xyId = 0) {
|
||||||
|
return ps4Data.xy[xyId].finger[finger].x;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the y-coordinate of the touchpad. Position 0 is in the top left.
|
||||||
|
* @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
|
||||||
|
* @param xyId The controller sends out three packets with the same structure.
|
||||||
|
* The third one will contain the last measure, but if you read from the controller then there is only be data in the first one.
|
||||||
|
* For that reason it will be set to 0 if the argument is omitted.
|
||||||
|
* @return Returns the y-coordinate of the finger.
|
||||||
|
*/
|
||||||
|
uint16_t getY(uint8_t finger = 0, uint8_t xyId = 0) {
|
||||||
|
return ps4Data.xy[xyId].finger[finger].y;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whenever the user is toucing the touchpad.
|
||||||
|
* @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
|
||||||
|
* @param xyId The controller sends out three packets with the same structure.
|
||||||
|
* The third one will contain the last measure, but if you read from the controller then there is only be data in the first one.
|
||||||
|
* For that reason it will be set to 0 if the argument is omitted.
|
||||||
|
* @return Returns true if the specific finger is touching the touchpad.
|
||||||
|
*/
|
||||||
|
bool isTouching(uint8_t finger = 0, uint8_t xyId = 0) {
|
||||||
|
return !(ps4Data.xy[xyId].finger[finger].touching); // The bit is cleared when a finger is touching the touchpad
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This counter increments every time a finger touches the touchpad.
|
||||||
|
* @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
|
||||||
|
* @param xyId The controller sends out three packets with the same structure.
|
||||||
|
* The third one will contain the last measure, but if you read from the controller then there is only be data in the first one.
|
||||||
|
* For that reason it will be set to 0 if the argument is omitted.
|
||||||
|
* @return Return the value of the counter, note that it is only a 7-bit value.
|
||||||
|
*/
|
||||||
|
uint8_t getTouchCounter(uint8_t finger = 0, uint8_t xyId = 0) {
|
||||||
|
return ps4Data.xy[xyId].finger[finger].counter;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the angle of the controller calculated using the accelerometer.
|
||||||
|
* @param a Either ::Pitch or ::Roll.
|
||||||
|
* @return Return the angle in the range of 0-360.
|
||||||
|
*/
|
||||||
|
double getAngle(AngleEnum a) {
|
||||||
|
if (a == Pitch)
|
||||||
|
return (atan2(ps4Data.accY, ps4Data.accZ) + PI) * RAD_TO_DEG;
|
||||||
|
else
|
||||||
|
return (atan2(ps4Data.accX, ps4Data.accZ) + PI) * RAD_TO_DEG;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to get the raw values from the 3-axis gyroscope and 3-axis accelerometer inside the PS4 controller.
|
||||||
|
* @param s The sensor to read.
|
||||||
|
* @return Returns the raw sensor reading.
|
||||||
|
*/
|
||||||
|
int16_t getSensor(SensorEnum s) {
|
||||||
|
switch(s) {
|
||||||
|
case gX:
|
||||||
|
return ps4Data.gyroX;
|
||||||
|
case gY:
|
||||||
|
return ps4Data.gyroY;
|
||||||
|
case gZ:
|
||||||
|
return ps4Data.gyroZ;
|
||||||
|
case aX:
|
||||||
|
return ps4Data.accX;
|
||||||
|
case aY:
|
||||||
|
return ps4Data.accY;
|
||||||
|
case aZ:
|
||||||
|
return ps4Data.accZ;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Turn both rumble and the LEDs off. */
|
||||||
|
void setAllOff() {
|
||||||
|
setRumbleOff();
|
||||||
|
setLedOff();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Set rumble off. */
|
||||||
|
void setRumbleOff() {
|
||||||
|
setRumbleOn(0, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn on rumble.
|
||||||
|
* @param mode Either ::RumbleHigh or ::RumbleLow.
|
||||||
|
*/
|
||||||
|
void setRumbleOn(RumbleEnum mode) {
|
||||||
|
if (mode == RumbleLow)
|
||||||
|
setRumbleOn(0x00, 0xFF);
|
||||||
|
else
|
||||||
|
setRumbleOn(0xFF, 0x00);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn on rumble.
|
||||||
|
* @param bigRumble Value for big motor.
|
||||||
|
* @param smallRumble Value for small motor.
|
||||||
|
*/
|
||||||
|
void setRumbleOn(uint8_t bigRumble, uint8_t smallRumble) {
|
||||||
|
ps4Output.bigRumble = bigRumble;
|
||||||
|
ps4Output.smallRumble = smallRumble;
|
||||||
|
ps4Output.reportChanged = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Turn all LEDs off. */
|
||||||
|
void setLedOff() {
|
||||||
|
setLed(0, 0, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this to set the color using RGB values.
|
||||||
|
* @param r,g,b RGB value.
|
||||||
|
*/
|
||||||
|
void setLed(uint8_t r, uint8_t g, uint8_t b) {
|
||||||
|
ps4Output.r = r;
|
||||||
|
ps4Output.g = g;
|
||||||
|
ps4Output.b = b;
|
||||||
|
ps4Output.reportChanged = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this to set the color using the predefined colors in ::ColorsEnum.
|
||||||
|
* @param color The desired color.
|
||||||
|
*/
|
||||||
|
void setLed(ColorsEnum color) {
|
||||||
|
setLed((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the LEDs flash time.
|
||||||
|
* @param flashOn Time to flash bright (255 = 2.5 seconds).
|
||||||
|
* @param flashOff Time to flash dark (255 = 2.5 seconds).
|
||||||
|
*/
|
||||||
|
void setLedFlash(uint8_t flashOn, uint8_t flashOff) {
|
||||||
|
ps4Output.flashOn = flashOn;
|
||||||
|
ps4Output.flashOff = flashOff;
|
||||||
|
ps4Output.reportChanged = true;
|
||||||
|
};
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Used to parse data sent from the PS4 controller.
|
||||||
|
* @param len Length of the data.
|
||||||
|
* @param buf Pointer to the data buffer.
|
||||||
|
*/
|
||||||
|
void Parse(uint8_t len, uint8_t *buf);
|
||||||
|
|
||||||
|
/** Used to reset the different buffers to their default values */
|
||||||
|
void Reset() {
|
||||||
|
uint8_t i;
|
||||||
|
for (i = 0; i < sizeof(ps4Data.hatValue); i++)
|
||||||
|
ps4Data.hatValue[i] = 127; // Center value
|
||||||
|
ps4Data.btn.val = 0;
|
||||||
|
oldButtonState.val = 0;
|
||||||
|
for (i = 0; i < sizeof(ps4Data.trigger); i++)
|
||||||
|
ps4Data.trigger[i] = 0;
|
||||||
|
for (i = 0; i < sizeof(ps4Data.xy)/sizeof(ps4Data.xy[0]); i++) {
|
||||||
|
for (uint8_t j = 0; j < sizeof(ps4Data.xy[0].finger)/sizeof(ps4Data.xy[0].finger[0]); j++)
|
||||||
|
ps4Data.xy[i].finger[j].touching = 1; // The bit is cleared if the finger is touching the touchpad
|
||||||
|
}
|
||||||
|
|
||||||
|
ps4Data.btn.dpad = DPAD_OFF;
|
||||||
|
oldButtonState.dpad = DPAD_OFF;
|
||||||
|
buttonClickState.dpad = 0;
|
||||||
|
oldDpad = 0;
|
||||||
|
|
||||||
|
ps4Output.bigRumble = ps4Output.smallRumble = 0;
|
||||||
|
ps4Output.r = ps4Output.g = ps4Output.b = 0;
|
||||||
|
ps4Output.flashOn = ps4Output.flashOff = 0;
|
||||||
|
ps4Output.reportChanged = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the output to the PS4 controller. This is implemented in PS4BT.h and PS4USB.h.
|
||||||
|
* @param output Pointer to PS4Output buffer;
|
||||||
|
*/
|
||||||
|
virtual void sendOutputReport(PS4Output *output) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool checkDpad(ButtonEnum b); // Used to check PS4 DPAD buttons
|
||||||
|
|
||||||
|
PS4Data ps4Data;
|
||||||
|
PS4Buttons oldButtonState, buttonClickState;
|
||||||
|
PS4Output ps4Output;
|
||||||
|
uint8_t oldDpad;
|
||||||
|
};
|
||||||
|
#endif
|
118
PS4USB.h
Normal file
118
PS4USB.h
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/* Copyright (C) 2014 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 _ps4usb_h_
|
||||||
|
#define _ps4usb_h_
|
||||||
|
|
||||||
|
#include "hiduniversal.h"
|
||||||
|
#include "PS4Parser.h"
|
||||||
|
|
||||||
|
#define PS4_VID 0x054C // Sony Corporation
|
||||||
|
#define PS4_PID 0x05C4 // PS4 Controller
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements support for the PS4 controller via USB.
|
||||||
|
* It uses the HIDUniversal class for all the USB communication.
|
||||||
|
*/
|
||||||
|
class PS4USB : public HIDUniversal, public PS4Parser {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor for the PS4USB class.
|
||||||
|
* @param p Pointer to the USB class instance.
|
||||||
|
*/
|
||||||
|
PS4USB(USB *p) :
|
||||||
|
HIDUniversal(p) {
|
||||||
|
PS4Parser::Reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to check if a PS4 controller is connected.
|
||||||
|
* @return Returns true if it is connected.
|
||||||
|
*/
|
||||||
|
bool connected() {
|
||||||
|
return HIDUniversal::isReady() && HIDUniversal::VID == PS4_VID && HIDUniversal::PID == PS4_PID;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to call your own function when the device is successfully initialized.
|
||||||
|
* @param funcOnInit Function to call.
|
||||||
|
*/
|
||||||
|
void attachOnInit(void (*funcOnInit)(void)) {
|
||||||
|
pFuncOnInit = funcOnInit;
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** @name HIDUniversal implementation */
|
||||||
|
/**
|
||||||
|
* Used to parse USB HID data.
|
||||||
|
* @param hid Pointer to the HID class.
|
||||||
|
* @param is_rpt_id Only used for Hubs.
|
||||||
|
* @param len The length of the incoming data.
|
||||||
|
* @param buf Pointer to the data buffer.
|
||||||
|
*/
|
||||||
|
virtual void ParseHIDData(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
|
||||||
|
if (HIDUniversal::VID == PS4_VID && HIDUniversal::PID == PS4_PID)
|
||||||
|
PS4Parser::Parse(len, buf);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a device is successfully initialized.
|
||||||
|
* Use attachOnInit(void (*funcOnInit)(void)) to call your own function.
|
||||||
|
* This is useful for instance if you want to set the LEDs in a specific way.
|
||||||
|
*/
|
||||||
|
virtual uint8_t OnInitSuccessful() {
|
||||||
|
if (HIDUniversal::VID == PS4_VID && HIDUniversal::PID == PS4_PID) {
|
||||||
|
PS4Parser::Reset();
|
||||||
|
if (pFuncOnInit)
|
||||||
|
pFuncOnInit(); // Call the user function
|
||||||
|
else
|
||||||
|
setLed(Blue);
|
||||||
|
};
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
/** @name PS4Parser implementation */
|
||||||
|
virtual void sendOutputReport(PS4Output *output) { // Source: https://github.com/chrippa/ds4drv
|
||||||
|
uint8_t buf[32];
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
|
buf[0] = 0x05; // Report ID
|
||||||
|
buf[1]= 0xFF;
|
||||||
|
|
||||||
|
buf[4] = output->smallRumble; // Small Rumble
|
||||||
|
buf[5] = output->bigRumble; // Big rumble
|
||||||
|
|
||||||
|
buf[6] = output->r; // Red
|
||||||
|
buf[7] = output->g; // Green
|
||||||
|
buf[8] = output->b; // Blue
|
||||||
|
|
||||||
|
buf[9] = output->flashOn; // Time to flash bright (255 = 2.5 seconds)
|
||||||
|
buf[10] = output->flashOff; // Time to flash dark (255 = 2.5 seconds)
|
||||||
|
|
||||||
|
output->reportChanged = false;
|
||||||
|
|
||||||
|
// The PS4 console actually set the four last bytes to a CRC32 checksum, but it seems like it is actually not needed
|
||||||
|
|
||||||
|
pUsb->outTransfer(bAddress, epInfo[ hidInterfaces[0].epIndex[epInterruptOutIndex] ].epAddr, sizeof(buf), buf);
|
||||||
|
};
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
private:
|
||||||
|
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
|
||||||
|
};
|
||||||
|
#endif
|
39
README.md
39
README.md
|
@ -22,7 +22,7 @@ For more information about the hardware see the [Hardware Manual](http://www.cir
|
||||||
* __Alexei Glushchenko, Circuits@Home__ - <alex-gl@mail.ru>
|
* __Alexei Glushchenko, Circuits@Home__ - <alex-gl@mail.ru>
|
||||||
* Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries
|
* Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries
|
||||||
* __Kristian Lauszus, TKJ Electronics__ - <kristianl@tkjelectronics.com>
|
* __Kristian Lauszus, TKJ Electronics__ - <kristianl@tkjelectronics.com>
|
||||||
* Developer of the [BTD](#bluetooth-libraries), [BTHID](#bthid-library), [SPP](#spp-library), [PS3](#ps3-library), [Wii](#wii-library), and [Xbox](#xbox-library) libraries
|
* Developer of the [BTD](#bluetooth-libraries), [BTHID](#bthid-library), [SPP](#spp-library), [PS4](#ps4-library), [PS3](#ps3-library), [Wii](#wii-library), and [Xbox](#xbox-library) libraries
|
||||||
* __Andrew Kroll__ - <xxxajk@gmail.com>
|
* __Andrew Kroll__ - <xxxajk@gmail.com>
|
||||||
* Major contributor to mass storage code
|
* Major contributor to mass storage code
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ Documentation for the library can be found at the following link: <http://felis.
|
||||||
|
|
||||||
By default serial debugging is disabled. To turn it on simply change ```ENABLE_UHS_DEBUGGING``` to 1 in [settings.h](settings.h) like so:
|
By default serial debugging is disabled. To turn it on simply change ```ENABLE_UHS_DEBUGGING``` to 1 in [settings.h](settings.h) like so:
|
||||||
|
|
||||||
```
|
```C++
|
||||||
#define ENABLE_UHS_DEBUGGING 1
|
#define ENABLE_UHS_DEBUGGING 1
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -66,8 +66,10 @@ By default serial debugging is disabled. To turn it on simply change ```ENABLE_U
|
||||||
Currently the following boards are supported by the library:
|
Currently the following boards are supported by the library:
|
||||||
|
|
||||||
* All official Arduino AVR boards (Uno, Duemilanove, Mega, Mega 2560, Mega ADK, Leonardo etc.)
|
* All official Arduino AVR boards (Uno, Duemilanove, Mega, Mega 2560, Mega ADK, Leonardo etc.)
|
||||||
* Teensy (Teensy++ 1.0, Teensy 2.0, Teensy++ 2.0, and Teensy 3.0)
|
* Arduino Due
|
||||||
* Note if you are using the Teensy 3.0 you should download this SPI library as well: <https://github.com/xxxajk/spi4teensy3>. You should then add ```#include <spi4teensy3.h>``` to your .ino file.
|
* If you are using the Arduino Due, then you must include the Arduino SPI library like so: ```#include <SPI.h>``` in your .ino file.
|
||||||
|
* Teensy (Teensy++ 1.0, Teensy 2.0, Teensy++ 2.0, and Teensy 3.x)
|
||||||
|
* Note if you are using the Teensy 3.x you should download this SPI library as well: <https://github.com/xxxajk/spi4teensy3>. You should then add ```#include <spi4teensy3.h>``` to your .ino file.
|
||||||
* Balanduino
|
* Balanduino
|
||||||
* Sanguino
|
* Sanguino
|
||||||
* Black Widdow
|
* Black Widdow
|
||||||
|
@ -97,6 +99,10 @@ Currently HID mice and keyboards are supported.
|
||||||
|
|
||||||
It uses the standard Boot protocol by default, but it is also able to use the Report protocol as well. You would simply have to call ```setProtocolMode()``` and then parse ```HID_RPT_PROTOCOL``` as an argument. You will then have to modify the parser for your device. See the example: [BTHID.ino](examples/Bluetooth/BTHID/BTHID.ino) for more information.
|
It uses the standard Boot protocol by default, but it is also able to use the Report protocol as well. You would simply have to call ```setProtocolMode()``` and then parse ```HID_RPT_PROTOCOL``` as an argument. You will then have to modify the parser for your device. See the example: [BTHID.ino](examples/Bluetooth/BTHID/BTHID.ino) for more information.
|
||||||
|
|
||||||
|
The [PS4 library](#ps4-library) also uses this class to handle all Bluetooth communication.
|
||||||
|
|
||||||
|
For information see the following blog post: <http://blog.tkjelectronics.dk/2013/12/bluetooth-hid-devices-now-supported-by-the-usb-host-library/>.
|
||||||
|
|
||||||
### [SPP library](SPP.cpp)
|
### [SPP library](SPP.cpp)
|
||||||
|
|
||||||
SPP stands for "Serial Port Profile" and is a Bluetooth protocol that implements a virtual comport which allows you to send data back and forth from your computer/phone to your Arduino via Bluetooth.
|
SPP stands for "Serial Port Profile" and is a Bluetooth protocol that implements a virtual comport which allows you to send data back and forth from your computer/phone to your Arduino via Bluetooth.
|
||||||
|
@ -112,6 +118,22 @@ More information can be found at these blog posts:
|
||||||
To implement the SPP protocol I used a Bluetooth sniffing tool called [PacketLogger](http://www.tkjelectronics.com/uploads/PacketLogger.zip) developed by Apple.
|
To implement the SPP protocol I used a Bluetooth sniffing tool called [PacketLogger](http://www.tkjelectronics.com/uploads/PacketLogger.zip) developed by Apple.
|
||||||
It enables me to see the Bluetooth communication between my Mac and any device.
|
It enables me to see the Bluetooth communication between my Mac and any device.
|
||||||
|
|
||||||
|
### PS4 Library
|
||||||
|
|
||||||
|
The PS4BT library is split up into the [PS4BT](PS4BT.h) and the [PS4USB](PS4USB.h) library. These allow you to use the Sony PS4 controller via Bluetooth and USB.
|
||||||
|
|
||||||
|
The [PS4BT.ino](examples/Bluetooth/PS4BT/PS4BT.ino) and [PS4USB.ino](examples/PS4USB/PS4USB.ino) examples shows how to easily read the buttons, joysticks, touchpad and IMU on the controller via Bluetooth and USB respectively. It is also possible to control the rumble and light on the controller.
|
||||||
|
|
||||||
|
Before you can use the PS4 controller via Bluetooth you will need to pair with it.
|
||||||
|
|
||||||
|
Simply create the PS4BT instance like so: ```PS4BT PS4(&Btd, PAIR);``` and then hold down the PS and Share button at the same time, the PS4 controller will then start to blink rapidly indicating that it is in paring mode.
|
||||||
|
|
||||||
|
It should then automatically pair the dongle with your controller. This only have to be done once.
|
||||||
|
|
||||||
|
For information see the following blog post: <http://blog.tkjelectronics.dk/2014/01/ps4-controller-now-supported-by-the-usb-host-library/>.
|
||||||
|
|
||||||
|
Also check out this excellent Wiki by Frank Zhao about the PS4 controller: <http://eleccelerator.com/wiki/index.php?title=DualShock_4> and this Linux driver: <https://github.com/chrippa/ds4drv>.
|
||||||
|
|
||||||
### PS3 Library
|
### PS3 Library
|
||||||
|
|
||||||
These libraries consist of the [PS3BT](PS3BT.cpp) and [PS3USB](PS3USB.cpp). These libraries allows you to use a Dualshock 3, Navigation or a Motion controller with the USB Host Shield both via Bluetooth and USB.
|
These libraries consist of the [PS3BT](PS3BT.cpp) and [PS3USB](PS3USB.cpp). These libraries allows you to use a Dualshock 3, Navigation or a Motion controller with the USB Host Shield both via Bluetooth and USB.
|
||||||
|
@ -183,15 +205,15 @@ The [Wii](Wii.cpp) library support the Wiimote, but also the Nunchuch and Motion
|
||||||
|
|
||||||
First you have to pair with the controller, this is done automatically by the library if you create the instance like so:
|
First you have to pair with the controller, this is done automatically by the library if you create the instance like so:
|
||||||
|
|
||||||
```
|
```C++
|
||||||
WII Wii(&Btd,PAIR);
|
WII Wii(&Btd, PAIR);
|
||||||
```
|
```
|
||||||
|
|
||||||
And then press 1 & 2 at once on the Wiimote or press sync if you are using a Wii U Pro Controller.
|
And then press 1 & 2 at once on the Wiimote or press sync if you are using a Wii U Pro Controller.
|
||||||
|
|
||||||
After that you can simply create the instance like so:
|
After that you can simply create the instance like so:
|
||||||
|
|
||||||
```
|
```C++
|
||||||
WII Wii(&Btd);
|
WII Wii(&Btd);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -220,4 +242,5 @@ All the information about the Wii controllers are from these sites:
|
||||||
|
|
||||||
> When I plug my device into the USB connector nothing happens?
|
> When I plug my device into the USB connector nothing happens?
|
||||||
|
|
||||||
Try to connect a external power supply to the Arduino - this solves the problem in most cases.
|
* Try to connect a external power supply to the Arduino - this solves the problem in most cases.
|
||||||
|
* You can also use a powered hub between the device and the USB Host Shield. You should then include the USB hub library: ```#include <usbhub.h>``` and create the instance like so: ```USBHub Hub1(&Usb);```.
|
22
UsbCore.h
22
UsbCore.h
|
@ -1,8 +1,18 @@
|
||||||
/*
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
* File: UsbCore.h
|
|
||||||
* Author: xxxajk
|
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
|
||||||
* Created on September 29, 2013, 9:25 PM
|
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
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Circuits At Home, LTD
|
||||||
|
Web : http://www.circuitsathome.com
|
||||||
|
e-mail : support@circuitsathome.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(_usb_h_) || defined(USBCORE_H)
|
#if !defined(_usb_h_) || defined(USBCORE_H)
|
||||||
|
@ -28,7 +38,7 @@ typedef MAX3421e<P53, P54> MAX3421E; // Arduino Mega ADK
|
||||||
#elif defined(ARDUINO_AVR_BALANDUINO)
|
#elif defined(ARDUINO_AVR_BALANDUINO)
|
||||||
typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
|
typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
|
||||||
#else
|
#else
|
||||||
typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo etc.) or Teensy 2.0 and 3.0
|
typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo, Due etc.) or Teensy 2.0 and 3.0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Common setup data constant combinations */
|
/* Common setup data constant combinations */
|
||||||
|
|
2
Wii.h
2
Wii.h
|
@ -280,7 +280,7 @@ public:
|
||||||
|
|
||||||
#ifdef WIICAMERA
|
#ifdef WIICAMERA
|
||||||
/** @name Wiimote IR camera functions
|
/** @name Wiimote IR camera functions
|
||||||
* You will have to set ENABLE_WII_IR_CAMERA in settings.h to 1 in order use the IR camera.
|
* You will have to set ::ENABLE_WII_IR_CAMERA in settings.h to 1 in order use the IR camera.
|
||||||
*/
|
*/
|
||||||
/** Initialises the camera as per the steps from: http://wiibrew.org/wiki/Wiimote#IR_Camera */
|
/** Initialises the camera as per the steps from: http://wiibrew.org/wiki/Wiimote#IR_Camera */
|
||||||
void IRinitialize();
|
void IRinitialize();
|
||||||
|
|
|
@ -173,7 +173,7 @@ public:
|
||||||
*/
|
*/
|
||||||
void setRumbleOn(uint8_t lValue, uint8_t rValue, uint8_t controller = 0);
|
void setRumbleOn(uint8_t lValue, uint8_t rValue, uint8_t controller = 0);
|
||||||
/**
|
/**
|
||||||
* Set LED value. Without using the ::LEDEnum or ::LEDMode enum.
|
* Set LED value. Without using the ::LEDEnum or ::LEDModeEnum.
|
||||||
* @param value See:
|
* @param value See:
|
||||||
* setLedOff(uint8_t controller), setLedOn(uint8_t controller, LED l),
|
* setLedOff(uint8_t controller), setLedOn(uint8_t controller, LED l),
|
||||||
* setLedBlink(uint8_t controller, LED l), and setLedMode(uint8_t controller, LEDMode lm).
|
* setLedBlink(uint8_t controller, LED l), and setLedMode(uint8_t controller, LEDMode lm).
|
||||||
|
|
|
@ -105,7 +105,7 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||||
Notify(PSTR("\r\nThis library only supports Xbox 360 controllers via USB"), 0x80);
|
Notify(PSTR("\r\nThis library only supports Xbox 360 controllers via USB"), 0x80);
|
||||||
#endif
|
#endif
|
||||||
goto FailUnknownDevice;
|
goto FailUnknownDevice;
|
||||||
} else if(PID != XBOX_WIRED_PID && PID != MADCATZ_WIRED_PID && PID != GAMESTOP_WIRED_PID) // Check PID
|
} else if(PID != XBOX_WIRED_PID && PID != MADCATZ_WIRED_PID && PID != GAMESTOP_WIRED_PID && PID != AFTERGLOW_WIRED_PID) // Check PID
|
||||||
goto FailUnknownDevice;
|
goto FailUnknownDevice;
|
||||||
|
|
||||||
// Allocate new address according to device class
|
// Allocate new address according to device class
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#define XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID 0x0291 // Third party Wireless Gaming Receiver
|
#define XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID 0x0291 // Third party Wireless Gaming Receiver
|
||||||
#define MADCATZ_WIRED_PID 0xF016 // Mad Catz wired controller
|
#define MADCATZ_WIRED_PID 0xF016 // Mad Catz wired controller
|
||||||
#define GAMESTOP_WIRED_PID 0x0401 // Gamestop wired controller
|
#define GAMESTOP_WIRED_PID 0x0401 // Gamestop wired controller
|
||||||
|
#define AFTERGLOW_WIRED_PID 0x0213 // Afterglow wired controller - it uses the same VID as a Gamestop controller
|
||||||
|
|
||||||
#define XBOX_REPORT_BUFFER_SIZE 14 // Size of the input report buffer
|
#define XBOX_REPORT_BUFFER_SIZE 14 // Size of the input report buffer
|
||||||
|
|
||||||
|
@ -105,7 +106,7 @@ public:
|
||||||
* @return Returns true if the device's VID and PID matches this driver.
|
* @return Returns true if the device's VID and PID matches this driver.
|
||||||
*/
|
*/
|
||||||
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) {
|
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) {
|
||||||
return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID || vid == GAMESTOP_VID) && (pid == XBOX_WIRED_PID || pid == MADCATZ_WIRED_PID || pid == GAMESTOP_WIRED_PID));
|
return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID || vid == GAMESTOP_VID) && (pid == XBOX_WIRED_PID || pid == MADCATZ_WIRED_PID || pid == GAMESTOP_WIRED_PID || pid == AFTERGLOW_WIRED_PID));
|
||||||
};
|
};
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
|
@ -149,7 +150,7 @@ public:
|
||||||
*/
|
*/
|
||||||
void setRumbleOn(uint8_t lValue, uint8_t rValue);
|
void setRumbleOn(uint8_t lValue, uint8_t rValue);
|
||||||
/**
|
/**
|
||||||
* Set LED value. Without using the ::LEDEnum or ::LEDMode enum.
|
* Set LED value. Without using the ::LEDEnum or ::LEDModeEnum.
|
||||||
* @param value See:
|
* @param value See:
|
||||||
* setLedOff(), setLedOn(LEDEnum l),
|
* setLedOff(), setLedOn(LEDEnum l),
|
||||||
* setLedBlink(LEDEnum l), and setLedMode(LEDModeEnum lm).
|
* setLedBlink(LEDEnum l), and setLedMode(LEDModeEnum lm).
|
||||||
|
@ -172,7 +173,7 @@ public:
|
||||||
void setLedBlink(LEDEnum l);
|
void setLedBlink(LEDEnum l);
|
||||||
/**
|
/**
|
||||||
* Used to set special LED modes supported by the Xbox controller.
|
* Used to set special LED modes supported by the Xbox controller.
|
||||||
* @param lm See ::LEDMode.
|
* @param lm See ::LEDModeEnum.
|
||||||
*/
|
*/
|
||||||
void setLedMode(LEDModeEnum lm);
|
void setLedMode(LEDModeEnum lm);
|
||||||
|
|
||||||
|
|
59
avrpins.h
59
avrpins.h
|
@ -457,7 +457,7 @@ public:
|
||||||
#define P2 Pe4
|
#define P2 Pe4
|
||||||
#define P3 Pe5
|
#define P3 Pe5
|
||||||
#define P4 Pg5
|
#define P4 Pg5
|
||||||
#define P5 Pe5
|
#define P5 Pe3
|
||||||
#define P6 Ph3
|
#define P6 Ph3
|
||||||
#define P7 Ph4
|
#define P7 Ph4
|
||||||
|
|
||||||
|
@ -749,11 +749,13 @@ public:
|
||||||
|
|
||||||
#endif // __AVR__
|
#endif // __AVR__
|
||||||
|
|
||||||
#if defined(__arm__) && defined(CORE_TEENSY)
|
#if defined(__arm__)
|
||||||
|
|
||||||
// pointers are 32 bits on ARM
|
// pointers are 32 bits on ARM
|
||||||
#define pgm_read_pointer(p) pgm_read_dword(p)
|
#define pgm_read_pointer(p) pgm_read_dword(p)
|
||||||
|
|
||||||
|
#if defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__))
|
||||||
|
|
||||||
#include "core_pins.h"
|
#include "core_pins.h"
|
||||||
#include "avr_emulation.h"
|
#include "avr_emulation.h"
|
||||||
|
|
||||||
|
@ -819,6 +821,59 @@ MAKE_PIN(P33, CORE_PIN33_PORTREG, CORE_PIN33_BIT, CORE_PIN33_CONFIG);
|
||||||
|
|
||||||
#undef MAKE_PIN
|
#undef MAKE_PIN
|
||||||
|
|
||||||
|
#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
|
||||||
|
|
||||||
|
// SetDirRead:
|
||||||
|
// Disable interrupts
|
||||||
|
// Disable the pull up resistor
|
||||||
|
// Set to INPUT
|
||||||
|
// Enable PIO
|
||||||
|
|
||||||
|
// SetDirWrite:
|
||||||
|
// Disable interrupts
|
||||||
|
// Disable the pull up resistor
|
||||||
|
// Set to OUTPUT
|
||||||
|
// Enable PIO
|
||||||
|
|
||||||
|
#define MAKE_PIN(className, pio, pinMask) \
|
||||||
|
class className { \
|
||||||
|
public: \
|
||||||
|
static void Set() { \
|
||||||
|
pio->PIO_SODR = pinMask; \
|
||||||
|
} \
|
||||||
|
static void Clear() { \
|
||||||
|
pio->PIO_CODR = pinMask; \
|
||||||
|
} \
|
||||||
|
static void SetDirRead() { \
|
||||||
|
pio->PIO_IDR = pinMask ; \
|
||||||
|
pio->PIO_PUDR = pinMask; \
|
||||||
|
pio->PIO_ODR = pinMask; \
|
||||||
|
pio->PIO_PER = pinMask; \
|
||||||
|
} \
|
||||||
|
static void SetDirWrite() { \
|
||||||
|
pio->PIO_IDR = pinMask ; \
|
||||||
|
pio->PIO_PUDR = pinMask; \
|
||||||
|
pio->PIO_OER = pinMask; \
|
||||||
|
pio->PIO_PER = pinMask; \
|
||||||
|
} \
|
||||||
|
static uint8_t IsSet() { \
|
||||||
|
return pio->PIO_PDSR & pinMask; \
|
||||||
|
} \
|
||||||
|
};
|
||||||
|
|
||||||
|
MAKE_PIN(P9, PIOC, PIO_PC21); // INT
|
||||||
|
MAKE_PIN(P10, PIOC, PIO_PC29); // SS
|
||||||
|
MAKE_PIN(P74, PIOA, PIO_PA25); // MISO
|
||||||
|
MAKE_PIN(P75, PIOA, PIO_PA26); // MOSI
|
||||||
|
MAKE_PIN(P76, PIOA, PIO_PA27); // CLK
|
||||||
|
|
||||||
|
#undef MAKE_PIN
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Please define board in avrpins.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // __arm__
|
#endif // __arm__
|
||||||
|
|
||||||
#endif //_avrpins_h_
|
#endif //_avrpins_h_
|
||||||
|
|
|
@ -18,9 +18,9 @@
|
||||||
#ifndef _controllerenums_h
|
#ifndef _controllerenums_h
|
||||||
#define _controllerenums_h
|
#define _controllerenums_h
|
||||||
|
|
||||||
/*
|
/**
|
||||||
This header file is used to store different enums for the controllers,
|
* This header file is used to store different enums for the controllers,
|
||||||
This is necessary so all the different libraries can be used at once
|
* This is necessary so all the different libraries can be used at once.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Enum used to turn on the LEDs on the different controllers. */
|
/** Enum used to turn on the LEDs on the different controllers. */
|
||||||
|
@ -41,6 +41,33 @@ enum LEDEnum {
|
||||||
ALL = 5,
|
ALL = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Used to set the colors of the Move and PS4 controller. */
|
||||||
|
enum ColorsEnum {
|
||||||
|
/** r = 255, g = 0, b = 0 */
|
||||||
|
Red = 0xFF0000,
|
||||||
|
/** r = 0, g = 255, b = 0 */
|
||||||
|
Green = 0xFF00,
|
||||||
|
/** r = 0, g = 0, b = 255 */
|
||||||
|
Blue = 0xFF,
|
||||||
|
|
||||||
|
/** r = 255, g = 235, b = 4 */
|
||||||
|
Yellow = 0xFFEB04,
|
||||||
|
/** r = 0, g = 255, b = 255 */
|
||||||
|
Lightblue = 0xFFFF,
|
||||||
|
/** r = 255, g = 0, b = 255 */
|
||||||
|
Purble = 0xFF00FF,
|
||||||
|
|
||||||
|
/** r = 255, g = 255, b = 255 */
|
||||||
|
White = 0xFFFFFF,
|
||||||
|
/** r = 0, g = 0, b = 0 */
|
||||||
|
Off = 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RumbleEnum {
|
||||||
|
RumbleHigh = 0x10,
|
||||||
|
RumbleLow = 0x20,
|
||||||
|
};
|
||||||
|
|
||||||
/** This enum is used to read all the different buttons on the different controllers */
|
/** This enum is used to read all the different buttons on the different controllers */
|
||||||
enum ButtonEnum {
|
enum ButtonEnum {
|
||||||
/**@{*/
|
/**@{*/
|
||||||
|
@ -94,6 +121,12 @@ enum ButtonEnum {
|
||||||
T = 18, // Covers 12 bits - we only need to read the top 8
|
T = 18, // Covers 12 bits - we only need to read the top 8
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
|
/** PS4 controllers buttons - SHARE and OPTIONS are present instead of SELECT and START */
|
||||||
|
SHARE = 4,
|
||||||
|
OPTIONS = 5,
|
||||||
|
TOUCHPAD = 17,
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
/**@{*/
|
/**@{*/
|
||||||
/** Xbox buttons */
|
/** Xbox buttons */
|
||||||
BACK = 4,
|
BACK = 4,
|
||||||
|
@ -118,4 +151,46 @@ enum AnalogHatEnum {
|
||||||
RightHatY = 3,
|
RightHatY = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sensors inside the Sixaxis Dualshock 3, Move controller and PS4 controller.
|
||||||
|
* <B>Note:</B> that the location is shifted 9 when it's connected via USB on the PS3 controller.
|
||||||
|
*/
|
||||||
|
enum SensorEnum {
|
||||||
|
/** Accelerometer values */
|
||||||
|
aX = 50, aY = 52, aZ = 54,
|
||||||
|
/** Gyro z-axis */
|
||||||
|
gZ = 56,
|
||||||
|
gX, gY, // These are not available on the PS3 controller
|
||||||
|
|
||||||
|
/** Accelerometer x-axis */
|
||||||
|
aXmove = 28,
|
||||||
|
/** Accelerometer z-axis */
|
||||||
|
aZmove = 30,
|
||||||
|
/** Accelerometer y-axis */
|
||||||
|
aYmove = 32,
|
||||||
|
|
||||||
|
/** Gyro x-axis */
|
||||||
|
gXmove = 40,
|
||||||
|
/** Gyro z-axis */
|
||||||
|
gZmove = 42,
|
||||||
|
/** Gyro y-axis */
|
||||||
|
gYmove = 44,
|
||||||
|
|
||||||
|
/** Temperature sensor */
|
||||||
|
tempMove = 46,
|
||||||
|
|
||||||
|
/** Magnetometer x-axis */
|
||||||
|
mXmove = 47,
|
||||||
|
/** Magnetometer z-axis */
|
||||||
|
mZmove = 49,
|
||||||
|
/** Magnetometer y-axis */
|
||||||
|
mYmove = 50,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Used to get the angle calculated using the PS3 controller and PS4 controller. */
|
||||||
|
enum AngleEnum {
|
||||||
|
Pitch = 0x01,
|
||||||
|
Roll = 0x02,
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,7 +20,7 @@ BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
|
||||||
/* You can create the instance of the class in two ways */
|
/* You can create the instance of the class in two ways */
|
||||||
// This will start an inquiry and then pair with your device - you only have to do this once
|
// This will start an inquiry and then pair with your device - you only have to do this once
|
||||||
// If you are using a Bluetooth keyboard, then you should type in the password on the keypad and then press enter
|
// If you are using a Bluetooth keyboard, then you should type in the password on the keypad and then press enter
|
||||||
BTHID hid(&Btd, PAIR, "0000");
|
BTHID bthid(&Btd, PAIR, "0000");
|
||||||
|
|
||||||
// After that you can simply create the instance like so and then press any button on the device
|
// After that you can simply create the instance like so and then press any button on the device
|
||||||
//BTHID hid(&Btd);
|
//BTHID hid(&Btd);
|
||||||
|
@ -36,13 +36,13 @@ void setup() {
|
||||||
while (1); // Halt
|
while (1); // Halt
|
||||||
}
|
}
|
||||||
|
|
||||||
hid.SetReportParser(KEYBOARD_PARSER_ID, (HIDReportParser*)&keyboardPrs);
|
bthid.SetReportParser(KEYBOARD_PARSER_ID, (HIDReportParser*)&keyboardPrs);
|
||||||
hid.SetReportParser(MOUSE_PARSER_ID, (HIDReportParser*)&mousePrs);
|
bthid.SetReportParser(MOUSE_PARSER_ID, (HIDReportParser*)&mousePrs);
|
||||||
|
|
||||||
// If "Boot Protocol Mode" does not work, then try "Report Protocol Mode"
|
// If "Boot Protocol Mode" does not work, then try "Report Protocol Mode"
|
||||||
// If that does not work either, then uncomment PRINTREPORT in BTHID.cpp to see the raw report
|
// If that does not work either, then uncomment PRINTREPORT in BTHID.cpp to see the raw report
|
||||||
hid.setProtocolMode(HID_BOOT_PROTOCOL); // Boot Protocol Mode
|
bthid.setProtocolMode(HID_BOOT_PROTOCOL); // Boot Protocol Mode
|
||||||
//hid.setProtocolMode(HID_RPT_PROTOCOL); // Report Protocol Mode
|
//bthid.setProtocolMode(HID_RPT_PROTOCOL); // Report Protocol Mode
|
||||||
|
|
||||||
Serial.print(F("\r\nHID Bluetooth Library Started"));
|
Serial.print(F("\r\nHID Bluetooth Library Started"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ USB Usb;
|
||||||
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
|
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
|
||||||
/* You can create the instance of the class in two ways */
|
/* You can create the instance of the class in two ways */
|
||||||
PS3BT PS3(&Btd); // This will just create the instance
|
PS3BT PS3(&Btd); // This will just create the instance
|
||||||
//PS3BT PS3(&Btd,0x00,0x15,0x83,0x3D,0x0A,0x57); // This will also store the bluetooth address - this can be obtained from the dongle when running the sketch
|
//PS3BT PS3(&Btd, 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;
|
boolean printAngle;
|
||||||
|
@ -52,7 +52,7 @@ void loop() {
|
||||||
if (PS3.getAnalogButton(L2) || PS3.getAnalogButton(R2)) {
|
if (PS3.getAnalogButton(L2) || PS3.getAnalogButton(R2)) {
|
||||||
Serial.print(F("\r\nL2: "));
|
Serial.print(F("\r\nL2: "));
|
||||||
Serial.print(PS3.getAnalogButton(L2));
|
Serial.print(PS3.getAnalogButton(L2));
|
||||||
if (!PS3.PS3NavigationConnected) {
|
if (PS3.PS3Connected) {
|
||||||
Serial.print(F("\tR2: "));
|
Serial.print(F("\tR2: "));
|
||||||
Serial.print(PS3.getAnalogButton(R2));
|
Serial.print(PS3.getAnalogButton(R2));
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ void loop() {
|
||||||
if (PS3[i]->getAnalogButton(L2) || PS3[i]->getAnalogButton(R2)) {
|
if (PS3[i]->getAnalogButton(L2) || PS3[i]->getAnalogButton(R2)) {
|
||||||
Serial.print(F("\r\nL2: "));
|
Serial.print(F("\r\nL2: "));
|
||||||
Serial.print(PS3[i]->getAnalogButton(L2));
|
Serial.print(PS3[i]->getAnalogButton(L2));
|
||||||
if (!PS3[i]->PS3NavigationConnected) {
|
if (PS3[i]->PS3Connected) {
|
||||||
Serial.print(F("\tR2: "));
|
Serial.print(F("\tR2: "));
|
||||||
Serial.print(PS3[i]->getAnalogButton(R2));
|
Serial.print(PS3[i]->getAnalogButton(R2));
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
|
||||||
SPP SerialBT(&Btd); // This will set the name to the defaults: "Arduino" and the pin to "0000"
|
SPP SerialBT(&Btd); // This will set the name to the defaults: "Arduino" and the pin to "0000"
|
||||||
//SPP SerialBTBT(&Btd,"Lauszus's Arduino","0000"); // You can also set the name and pin like so
|
//SPP SerialBTBT(&Btd,"Lauszus's Arduino","0000"); // You can also set the name and pin like so
|
||||||
PS3BT PS3(&Btd); // This will just create the instance
|
PS3BT PS3(&Btd); // This will just create the instance
|
||||||
//PS3BT PS3(&Btd,0x00,0x15,0x83,0x3D,0x0A,0x57); // This will also store the bluetooth address - this can be obtained from the dongle when running the sketch
|
//PS3BT PS3(&Btd, 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 firstMessage = true;
|
boolean firstMessage = true;
|
||||||
String output = ""; // We will store the data in this string
|
String output = ""; // We will store the data in this string
|
||||||
|
@ -77,7 +77,7 @@ void loop() {
|
||||||
output += "\r\n";
|
output += "\r\n";
|
||||||
output += "L2: ";
|
output += "L2: ";
|
||||||
output += PS3.getAnalogButton(L2);
|
output += PS3.getAnalogButton(L2);
|
||||||
if (!PS3.PS3NavigationConnected) {
|
if (PS3.PS3Connected) {
|
||||||
output += "\tR2: ";
|
output += "\tR2: ";
|
||||||
output += PS3.getAnalogButton(R2);
|
output += PS3.getAnalogButton(R2);
|
||||||
}
|
}
|
||||||
|
|
124
examples/Bluetooth/PS4BT/PS4BT.ino
Normal file
124
examples/Bluetooth/PS4BT/PS4BT.ino
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
Example sketch for the PS4 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 <PS4BT.h>
|
||||||
|
#include <usbhub.h>
|
||||||
|
|
||||||
|
// Satisfy IDE, which only needs to see the include statment in the ino.
|
||||||
|
#ifdef dobogusinclude
|
||||||
|
#include <spi4teensy3.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
USB Usb;
|
||||||
|
//USBHub Hub1(&Usb); // Some dongles have a hub inside
|
||||||
|
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
|
||||||
|
|
||||||
|
/* You can create the instance of the PS4BT class in two ways */
|
||||||
|
// This will start an inquiry and then pair with the PS4 controller - you only have to do this once
|
||||||
|
// You will need to hold down the PS and Share button at the same time, the PS4 controller will then start to blink rapidly indicating that it is in paring mode
|
||||||
|
PS4BT PS4(&Btd, PAIR);
|
||||||
|
|
||||||
|
// After that you can simply create the instance like so and then press the PS button on the device
|
||||||
|
//PS4BT PS4(&Btd);
|
||||||
|
|
||||||
|
boolean printAngle, printTouch;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
|
||||||
|
if (Usb.Init() == -1) {
|
||||||
|
Serial.print(F("\r\nOSC did not start"));
|
||||||
|
while (1); // Halt
|
||||||
|
}
|
||||||
|
Serial.print(F("\r\nPS4 Bluetooth Library Started"));
|
||||||
|
}
|
||||||
|
void loop() {
|
||||||
|
Usb.Task();
|
||||||
|
|
||||||
|
if (PS4.connected()) {
|
||||||
|
if (PS4.getAnalogHat(LeftHatX) > 137 || PS4.getAnalogHat(LeftHatX) < 117 || PS4.getAnalogHat(LeftHatY) > 137 || PS4.getAnalogHat(LeftHatY) < 117 || PS4.getAnalogHat(RightHatX) > 137 || PS4.getAnalogHat(RightHatX) < 117 || PS4.getAnalogHat(RightHatY) > 137 || PS4.getAnalogHat(RightHatY) < 117) {
|
||||||
|
Serial.print(F("\r\nLeftHatX: "));
|
||||||
|
Serial.print(PS4.getAnalogHat(LeftHatX));
|
||||||
|
Serial.print(F("\tLeftHatY: "));
|
||||||
|
Serial.print(PS4.getAnalogHat(LeftHatY));
|
||||||
|
Serial.print(F("\tRightHatX: "));
|
||||||
|
Serial.print(PS4.getAnalogHat(RightHatX));
|
||||||
|
Serial.print(F("\tRightHatY: "));
|
||||||
|
Serial.print(PS4.getAnalogHat(RightHatY));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PS4.getAnalogButton(L2) || PS4.getAnalogButton(R2)) { // These are the only analog buttons on the PS4 controller
|
||||||
|
Serial.print(F("\r\nL2: "));
|
||||||
|
Serial.print(PS4.getAnalogButton(L2));
|
||||||
|
Serial.print(F("\tR2: "));
|
||||||
|
Serial.print(PS4.getAnalogButton(R2));
|
||||||
|
}
|
||||||
|
if (PS4.getButtonClick(PS)) {
|
||||||
|
Serial.print(F("\r\nPS"));
|
||||||
|
PS4.disconnect();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (PS4.getButtonClick(TRIANGLE))
|
||||||
|
Serial.print(F("\r\nTraingle"));
|
||||||
|
if (PS4.getButtonClick(CIRCLE))
|
||||||
|
Serial.print(F("\r\nCircle"));
|
||||||
|
if (PS4.getButtonClick(CROSS))
|
||||||
|
Serial.print(F("\r\nCross"));
|
||||||
|
if (PS4.getButtonClick(SQUARE))
|
||||||
|
Serial.print(F("\r\nSquare"));
|
||||||
|
|
||||||
|
if (PS4.getButtonClick(UP))
|
||||||
|
Serial.print(F("\r\nUp"));
|
||||||
|
if (PS4.getButtonClick(RIGHT))
|
||||||
|
Serial.print(F("\r\nRight"));
|
||||||
|
if (PS4.getButtonClick(DOWN))
|
||||||
|
Serial.print(F("\r\nDown"));
|
||||||
|
if (PS4.getButtonClick(LEFT))
|
||||||
|
Serial.print(F("\r\nLeft"));
|
||||||
|
|
||||||
|
if (PS4.getButtonClick(L1))
|
||||||
|
Serial.print(F("\r\nL1"));
|
||||||
|
if (PS4.getButtonClick(L3))
|
||||||
|
Serial.print(F("\r\nL3"));
|
||||||
|
if (PS4.getButtonClick(R1))
|
||||||
|
Serial.print(F("\r\nR1"));
|
||||||
|
if (PS4.getButtonClick(R3))
|
||||||
|
Serial.print(F("\r\nR3"));
|
||||||
|
|
||||||
|
if (PS4.getButtonClick(SHARE))
|
||||||
|
Serial.print(F("\r\nShare"));
|
||||||
|
if (PS4.getButtonClick(OPTIONS)) {
|
||||||
|
Serial.print(F("\r\nOptions"));
|
||||||
|
printAngle = !printAngle;
|
||||||
|
}
|
||||||
|
if (PS4.getButtonClick(TOUCHPAD)) {
|
||||||
|
Serial.print(F("\r\nTouchpad"));
|
||||||
|
printTouch = !printTouch;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (printAngle) { // Print angle calculated using the accelerometer only
|
||||||
|
Serial.print(F("\r\nPitch: "));
|
||||||
|
Serial.print(PS4.getAngle(Pitch));
|
||||||
|
Serial.print(F("\tRoll: "));
|
||||||
|
Serial.print(PS4.getAngle(Roll));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (printTouch) { // Print the x, y coordinates of the touchpad
|
||||||
|
if (PS4.isTouching(0) || PS4.isTouching(1)) // Print newline and carriage return if any of the fingers are touching the touchpad
|
||||||
|
Serial.print(F("\r\n"));
|
||||||
|
for (uint8_t i = 0; i < 2; i++) { // The touchpad track two fingers
|
||||||
|
if (PS4.isTouching(i)) { // Print the position of the finger if it is touching the touchpad
|
||||||
|
Serial.print(F("X")); Serial.print(i + 1); Serial.print(F(": "));
|
||||||
|
Serial.print(PS4.getX(i));
|
||||||
|
Serial.print(F("\tY")); Serial.print(i + 1); Serial.print(F(": "));
|
||||||
|
Serial.print(PS4.getY(i));
|
||||||
|
Serial.print(F("\t"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
112
examples/PS4USB/PS4USB.ino
Normal file
112
examples/PS4USB/PS4USB.ino
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
Example sketch for the PS4 USB 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 <PS4USB.h>
|
||||||
|
|
||||||
|
// Satisfy IDE, which only needs to see the include statment in the ino.
|
||||||
|
#ifdef dobogusinclude
|
||||||
|
#include <spi4teensy3.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
USB Usb;
|
||||||
|
PS4USB PS4(&Usb);
|
||||||
|
|
||||||
|
boolean printAngle, printTouch;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
|
||||||
|
if (Usb.Init() == -1) {
|
||||||
|
Serial.print(F("\r\nOSC did not start"));
|
||||||
|
while (1); // Halt
|
||||||
|
}
|
||||||
|
Serial.print(F("\r\nPS4 USB Library Started"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
Usb.Task();
|
||||||
|
|
||||||
|
if (PS4.connected()) {
|
||||||
|
if (PS4.getAnalogHat(LeftHatX) > 137 || PS4.getAnalogHat(LeftHatX) < 117 || PS4.getAnalogHat(LeftHatY) > 137 || PS4.getAnalogHat(LeftHatY) < 117 || PS4.getAnalogHat(RightHatX) > 137 || PS4.getAnalogHat(RightHatX) < 117 || PS4.getAnalogHat(RightHatY) > 137 || PS4.getAnalogHat(RightHatY) < 117) {
|
||||||
|
Serial.print(F("\r\nLeftHatX: "));
|
||||||
|
Serial.print(PS4.getAnalogHat(LeftHatX));
|
||||||
|
Serial.print(F("\tLeftHatY: "));
|
||||||
|
Serial.print(PS4.getAnalogHat(LeftHatY));
|
||||||
|
Serial.print(F("\tRightHatX: "));
|
||||||
|
Serial.print(PS4.getAnalogHat(RightHatX));
|
||||||
|
Serial.print(F("\tRightHatY: "));
|
||||||
|
Serial.print(PS4.getAnalogHat(RightHatY));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PS4.getAnalogButton(L2) || PS4.getAnalogButton(R2)) { // These are the only analog buttons on the PS4 controller
|
||||||
|
Serial.print(F("\r\nL2: "));
|
||||||
|
Serial.print(PS4.getAnalogButton(L2));
|
||||||
|
Serial.print(F("\tR2: "));
|
||||||
|
Serial.print(PS4.getAnalogButton(R2));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PS4.getButtonClick(PS))
|
||||||
|
Serial.print(F("\r\nPS"));
|
||||||
|
if (PS4.getButtonClick(TRIANGLE))
|
||||||
|
Serial.print(F("\r\nTraingle"));
|
||||||
|
if (PS4.getButtonClick(CIRCLE))
|
||||||
|
Serial.print(F("\r\nCircle"));
|
||||||
|
if (PS4.getButtonClick(CROSS))
|
||||||
|
Serial.print(F("\r\nCross"));
|
||||||
|
if (PS4.getButtonClick(SQUARE))
|
||||||
|
Serial.print(F("\r\nSquare"));
|
||||||
|
|
||||||
|
if (PS4.getButtonClick(UP))
|
||||||
|
Serial.print(F("\r\nUp"));
|
||||||
|
if (PS4.getButtonClick(RIGHT))
|
||||||
|
Serial.print(F("\r\nRight"));
|
||||||
|
if (PS4.getButtonClick(DOWN))
|
||||||
|
Serial.print(F("\r\nDown"));
|
||||||
|
if (PS4.getButtonClick(LEFT))
|
||||||
|
Serial.print(F("\r\nLeft"));
|
||||||
|
|
||||||
|
if (PS4.getButtonClick(L1))
|
||||||
|
Serial.print(F("\r\nL1"));
|
||||||
|
if (PS4.getButtonClick(L3))
|
||||||
|
Serial.print(F("\r\nL3"));
|
||||||
|
if (PS4.getButtonClick(R1))
|
||||||
|
Serial.print(F("\r\nR1"));
|
||||||
|
if (PS4.getButtonClick(R3))
|
||||||
|
Serial.print(F("\r\nR3"));
|
||||||
|
|
||||||
|
if (PS4.getButtonClick(SHARE))
|
||||||
|
Serial.print(F("\r\nShare"));
|
||||||
|
if (PS4.getButtonClick(OPTIONS)) {
|
||||||
|
Serial.print(F("\r\nOptions"));
|
||||||
|
printAngle = !printAngle;
|
||||||
|
}
|
||||||
|
if (PS4.getButtonClick(TOUCHPAD)) {
|
||||||
|
Serial.print(F("\r\nTouchpad"));
|
||||||
|
printTouch = !printTouch;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (printAngle) { // Print angle calculated using the accelerometer only
|
||||||
|
Serial.print(F("\r\nPitch: "));
|
||||||
|
Serial.print(PS4.getAngle(Pitch));
|
||||||
|
Serial.print(F("\tRoll: "));
|
||||||
|
Serial.print(PS4.getAngle(Roll));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (printTouch) { // Print the x, y coordinates of the touchpad
|
||||||
|
if (PS4.isTouching(0) || PS4.isTouching(1)) // Print newline and carriage return if any of the fingers are touching the touchpad
|
||||||
|
Serial.print(F("\r\n"));
|
||||||
|
for (uint8_t i = 0; i < 2; i++) { // The touchpad track two fingers
|
||||||
|
if (PS4.isTouching(i)) { // Print the position of the finger if it is touching the touchpad
|
||||||
|
Serial.print(F("X")); Serial.print(i + 1); Serial.print(F(": "));
|
||||||
|
Serial.print(PS4.getX(i));
|
||||||
|
Serial.print(F("\tY")); Serial.print(i + 1); Serial.print(F(": "));
|
||||||
|
Serial.print(PS4.getY(i));
|
||||||
|
Serial.print(F("\t"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
hid.cpp
17
hid.cpp
|
@ -1,3 +1,20 @@
|
||||||
|
/* Copyright (C) 2011 Circuits At Home, LTD. 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
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Circuits At Home, LTD
|
||||||
|
Web : http://www.circuitsathome.com
|
||||||
|
e-mail : support@circuitsathome.com
|
||||||
|
*/
|
||||||
|
|
||||||
#include "hid.h"
|
#include "hid.h"
|
||||||
|
|
||||||
//get HID report descriptor
|
//get HID report descriptor
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
/* Copyright (C) 2011 Circuits At Home, LTD. 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
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Circuits At Home, LTD
|
||||||
|
Web : http://www.circuitsathome.com
|
||||||
|
e-mail : support@circuitsathome.com
|
||||||
|
*/
|
||||||
|
|
||||||
#include "hidescriptorparser.h"
|
#include "hidescriptorparser.h"
|
||||||
|
|
||||||
const char * const ReportDescParserBase::usagePageTitles0[] PROGMEM = {
|
const char * const ReportDescParserBase::usagePageTitles0[] PROGMEM = {
|
||||||
|
|
|
@ -1,8 +1,26 @@
|
||||||
|
/* Copyright (C) 2011 Circuits At Home, LTD. 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
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Circuits At Home, LTD
|
||||||
|
Web : http://www.circuitsathome.com
|
||||||
|
e-mail : support@circuitsathome.com
|
||||||
|
*/
|
||||||
|
|
||||||
#include "hiduniversal.h"
|
#include "hiduniversal.h"
|
||||||
|
|
||||||
HIDUniversal::HIDUniversal(USB *p) :
|
HIDUniversal::HIDUniversal(USB *p) :
|
||||||
HID(p),
|
HID(p),
|
||||||
qNextPollTime(0),
|
qNextPollTime(0),
|
||||||
|
pollInterval(0),
|
||||||
bPollEnable(false),
|
bPollEnable(false),
|
||||||
bHasReportId(false) {
|
bHasReportId(false) {
|
||||||
Initialize();
|
Initialize();
|
||||||
|
@ -47,6 +65,7 @@ void HIDUniversal::Initialize() {
|
||||||
bNumEP = 1;
|
bNumEP = 1;
|
||||||
bNumIface = 0;
|
bNumIface = 0;
|
||||||
bConfNum = 0;
|
bConfNum = 0;
|
||||||
|
pollInterval = 0;
|
||||||
|
|
||||||
ZeroMemory(constBuffLen, prevBuf);
|
ZeroMemory(constBuffLen, prevBuf);
|
||||||
}
|
}
|
||||||
|
@ -167,6 +186,9 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||||
if(rcode)
|
if(rcode)
|
||||||
goto FailGetDevDescr;
|
goto FailGetDevDescr;
|
||||||
|
|
||||||
|
VID = udd->idVendor; // Can be used by classes that inherits this class to check the VID and PID of the connected device
|
||||||
|
PID = udd->idProduct;
|
||||||
|
|
||||||
num_of_conf = udd->bNumConfigurations;
|
num_of_conf = udd->bNumConfigurations;
|
||||||
|
|
||||||
// Assign epInfo to epinfo pointer
|
// Assign epInfo to epinfo pointer
|
||||||
|
@ -198,7 +220,7 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||||
// Assign epInfo to epinfo pointer
|
// Assign epInfo to epinfo pointer
|
||||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||||
|
|
||||||
USBTRACE2("\r\nCnf:", bConfNum);
|
USBTRACE2("Cnf:", bConfNum);
|
||||||
|
|
||||||
// Set Configuration Value
|
// Set Configuration Value
|
||||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||||
|
@ -307,6 +329,9 @@ void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint
|
||||||
// Fill in the endpoint index list
|
// Fill in the endpoint index list
|
||||||
piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
|
piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
|
||||||
|
|
||||||
|
if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
|
||||||
|
pollInterval = pep->bInterval;
|
||||||
|
|
||||||
bNumEP++;
|
bNumEP++;
|
||||||
}
|
}
|
||||||
//PrintEndpointDescriptor(pep);
|
//PrintEndpointDescriptor(pep);
|
||||||
|
@ -346,7 +371,7 @@ uint8_t HIDUniversal::Poll() {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(qNextPollTime <= millis()) {
|
if(qNextPollTime <= millis()) {
|
||||||
qNextPollTime = millis() + 50;
|
qNextPollTime = millis() + pollInterval;
|
||||||
|
|
||||||
uint8_t buf[constBuffLen];
|
uint8_t buf[constBuffLen];
|
||||||
|
|
||||||
|
@ -373,13 +398,15 @@ uint8_t HIDUniversal::Poll() {
|
||||||
|
|
||||||
if(identical)
|
if(identical)
|
||||||
return 0;
|
return 0;
|
||||||
|
#if 1
|
||||||
Notify(PSTR("\r\nBuf: "), 0x80);
|
Notify(PSTR("\r\nBuf: "), 0x80);
|
||||||
|
|
||||||
for(uint8_t i = 0; i < read; i++)
|
for(uint8_t i = 0; i < read; i++)
|
||||||
D_PrintHex<uint8_t > (buf[i], 0x80);
|
D_PrintHex<uint8_t > (buf[i], 0x80);
|
||||||
|
|
||||||
Notify(PSTR("\r\n"), 0x80);
|
Notify(PSTR("\r\n"), 0x80);
|
||||||
|
#endif
|
||||||
|
ParseHIDData(this, bHasReportId, (uint8_t)read, buf);
|
||||||
|
|
||||||
HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0));
|
HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0));
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
/* Copyright (C) 2011 Circuits At Home, LTD. 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
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Circuits At Home, LTD
|
||||||
|
Web : http://www.circuitsathome.com
|
||||||
|
e-mail : support@circuitsathome.com
|
||||||
|
*/
|
||||||
|
|
||||||
#if !defined(__HIDUNIVERSAL_H__)
|
#if !defined(__HIDUNIVERSAL_H__)
|
||||||
#define __HIDUNIVERSAL_H__
|
#define __HIDUNIVERSAL_H__
|
||||||
|
|
||||||
|
@ -17,10 +34,7 @@ class HIDUniversal : public HID {
|
||||||
// Returns HID class specific descriptor length by its type and order number
|
// Returns HID class specific descriptor length by its type and order number
|
||||||
uint16_t GetHidClassDescrLen(uint8_t type, uint8_t num);
|
uint16_t GetHidClassDescrLen(uint8_t type, uint8_t num);
|
||||||
|
|
||||||
EpInfo epInfo[totalEndpoints];
|
|
||||||
|
|
||||||
struct HIDInterface {
|
struct HIDInterface {
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint8_t bmInterface : 3;
|
uint8_t bmInterface : 3;
|
||||||
uint8_t bmAltSet : 3;
|
uint8_t bmAltSet : 3;
|
||||||
|
@ -29,12 +43,11 @@ class HIDUniversal : public HID {
|
||||||
uint8_t epIndex[maxEpPerInterface];
|
uint8_t epIndex[maxEpPerInterface];
|
||||||
};
|
};
|
||||||
|
|
||||||
HIDInterface hidInterfaces[maxHidInterfaces];
|
|
||||||
|
|
||||||
uint8_t bConfNum; // configuration number
|
uint8_t bConfNum; // configuration number
|
||||||
uint8_t bNumIface; // number of interfaces in the configuration
|
uint8_t bNumIface; // number of interfaces in the configuration
|
||||||
uint8_t bNumEP; // total number of EP in the configuration
|
uint8_t bNumEP; // total number of EP in the configuration
|
||||||
uint32_t qNextPollTime; // next poll time
|
uint32_t qNextPollTime; // next poll time
|
||||||
|
uint8_t pollInterval;
|
||||||
bool bPollEnable; // poll enable flag
|
bool bPollEnable; // poll enable flag
|
||||||
|
|
||||||
static const uint16_t constBuffLen = 64; // event buffer length
|
static const uint16_t constBuffLen = 64; // event buffer length
|
||||||
|
@ -48,8 +61,13 @@ class HIDUniversal : public HID {
|
||||||
void SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest);
|
void SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
EpInfo epInfo[totalEndpoints];
|
||||||
|
HIDInterface hidInterfaces[maxHidInterfaces];
|
||||||
|
|
||||||
bool bHasReportId;
|
bool bHasReportId;
|
||||||
|
|
||||||
|
uint16_t PID, VID; // PID and VID of connected device
|
||||||
|
|
||||||
// HID implementation
|
// HID implementation
|
||||||
virtual HIDReportParser* GetReportParser(uint8_t id);
|
virtual HIDReportParser* GetReportParser(uint8_t id);
|
||||||
|
|
||||||
|
@ -57,6 +75,10 @@ protected:
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtual void ParseHIDData(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HIDUniversal(USB *p);
|
HIDUniversal(USB *p);
|
||||||
|
|
||||||
|
@ -72,6 +94,10 @@ public:
|
||||||
return bAddress;
|
return bAddress;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtual bool isReady() {
|
||||||
|
return bPollEnable;
|
||||||
|
};
|
||||||
|
|
||||||
// UsbConfigXtracter implementation
|
// UsbConfigXtracter implementation
|
||||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||||
};
|
};
|
||||||
|
|
16
keywords.txt
16
keywords.txt
|
@ -25,7 +25,7 @@ BTD KEYWORD1
|
||||||
Task KEYWORD2
|
Task KEYWORD2
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
# Syntax Coloring Map For PS3 Bluetooth/USB Library
|
# Syntax Coloring Map For PS3/PS4 Bluetooth/USB Library
|
||||||
####################################################
|
####################################################
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
|
@ -34,6 +34,8 @@ Task KEYWORD2
|
||||||
|
|
||||||
PS3BT KEYWORD1
|
PS3BT KEYWORD1
|
||||||
PS3USB KEYWORD1
|
PS3USB KEYWORD1
|
||||||
|
PS4BT KEYWORD1
|
||||||
|
PS4USB KEYWORD1
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
# Methods and Functions (KEYWORD2)
|
# Methods and Functions (KEYWORD2)
|
||||||
|
@ -62,6 +64,7 @@ setRumbleOn KEYWORD2
|
||||||
setLedOff KEYWORD2
|
setLedOff KEYWORD2
|
||||||
setLedOn KEYWORD2
|
setLedOn KEYWORD2
|
||||||
setLedToggle KEYWORD2
|
setLedToggle KEYWORD2
|
||||||
|
setLedFlash KEYWORD2
|
||||||
moveSetBulb KEYWORD2
|
moveSetBulb KEYWORD2
|
||||||
moveSetRumble KEYWORD2
|
moveSetRumble KEYWORD2
|
||||||
|
|
||||||
|
@ -74,6 +77,11 @@ PS3NavigationConnected KEYWORD2
|
||||||
isReady KEYWORD2
|
isReady KEYWORD2
|
||||||
watingForConnection KEYWORD2
|
watingForConnection KEYWORD2
|
||||||
|
|
||||||
|
isTouching KEYWORD2
|
||||||
|
getX KEYWORD2
|
||||||
|
getY KEYWORD2
|
||||||
|
getTouchCounter KEYWORD2
|
||||||
|
|
||||||
####################################################
|
####################################################
|
||||||
# Constants and enums (LITERAL1)
|
# Constants and enums (LITERAL1)
|
||||||
####################################################
|
####################################################
|
||||||
|
@ -118,6 +126,10 @@ PS LITERAL1
|
||||||
MOVE LITERAL1
|
MOVE LITERAL1
|
||||||
T LITERAL1
|
T LITERAL1
|
||||||
|
|
||||||
|
SHARE LITERAL1
|
||||||
|
OPTIONS LITERAL1
|
||||||
|
TOUCHPAD LITERAL1
|
||||||
|
|
||||||
LeftHatX LITERAL1
|
LeftHatX LITERAL1
|
||||||
LeftHatY LITERAL1
|
LeftHatY LITERAL1
|
||||||
RightHatX LITERAL1
|
RightHatX LITERAL1
|
||||||
|
@ -126,6 +138,8 @@ RightHatY LITERAL1
|
||||||
aX LITERAL1
|
aX LITERAL1
|
||||||
aY LITERAL1
|
aY LITERAL1
|
||||||
aZ LITERAL1
|
aZ LITERAL1
|
||||||
|
gX LITERAL1
|
||||||
|
gY LITERAL1
|
||||||
gZ LITERAL1
|
gZ LITERAL1
|
||||||
aXmove LITERAL1
|
aXmove LITERAL1
|
||||||
aYmove LITERAL1
|
aYmove LITERAL1
|
||||||
|
|
20
macros.h
20
macros.h
|
@ -1,8 +1,18 @@
|
||||||
/*
|
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
|
||||||
* File: macros.h
|
|
||||||
* Author: AJK
|
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
|
||||||
* Created on September 23, 2013, 12:31 AM
|
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
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Circuits At Home, LTD
|
||||||
|
Web : http://www.circuitsathome.com
|
||||||
|
e-mail : support@circuitsathome.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(_usb_h_) || defined(MACROS_H)
|
#if !defined(_usb_h_) || defined(MACROS_H)
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
/* Copyright (C) 2011 Circuits At Home, LTD. 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
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Circuits At Home, LTD
|
||||||
|
Web : http://www.circuitsathome.com
|
||||||
|
e-mail : support@circuitsathome.com
|
||||||
|
*/
|
||||||
|
|
||||||
#include "masstorage.h"
|
#include "masstorage.h"
|
||||||
|
|
||||||
const uint8_t BulkOnly::epDataInIndex = 1;
|
const uint8_t BulkOnly::epDataInIndex = 1;
|
||||||
|
|
17
masstorage.h
17
masstorage.h
|
@ -1,3 +1,20 @@
|
||||||
|
/* Copyright (C) 2011 Circuits At Home, LTD. 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
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Circuits At Home, LTD
|
||||||
|
Web : http://www.circuitsathome.com
|
||||||
|
e-mail : support@circuitsathome.com
|
||||||
|
*/
|
||||||
|
|
||||||
#if !defined(__MASSTORAGE_H__)
|
#if !defined(__MASSTORAGE_H__)
|
||||||
#define __MASSTORAGE_H__
|
#define __MASSTORAGE_H__
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,6 @@
|
||||||
// No user serviceable parts below this line.
|
// No user serviceable parts below this line.
|
||||||
// DO NOT change anything below here unless you are a developer!
|
// DO NOT change anything below here unless you are a developer!
|
||||||
|
|
||||||
// When will we drop support for the older bug-ridden stuff?
|
|
||||||
#if defined(ARDUINO) && ARDUINO >=100
|
#if defined(ARDUINO) && ARDUINO >=100
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#else
|
#else
|
||||||
|
@ -79,7 +78,7 @@
|
||||||
#define F(str) (str)
|
#define F(str) (str)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#if defined(__GNUC__) && defined(__AVR__)
|
||||||
#ifndef GCC_VERSION
|
#ifndef GCC_VERSION
|
||||||
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||||
#endif
|
#endif
|
||||||
|
@ -122,10 +121,14 @@
|
||||||
#define EXT_RAM 0
|
#define EXT_RAM 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__MK20DX128__) || defined(__MK20DX256__)
|
#if defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__))
|
||||||
#define USING_SPI4TEENSY3 USE_SPI4TEENSY3
|
#define USING_SPI4TEENSY3 USE_SPI4TEENSY3
|
||||||
#else
|
#else
|
||||||
#define USING_SPI4TEENSY3 0
|
#define USING_SPI4TEENSY3 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
|
||||||
|
#include <SPI.h> // Use the Arduino SPI library for the Arduino Due
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* SETTINGS_H */
|
#endif /* SETTINGS_H */
|
||||||
|
|
37
usbhost.h
37
usbhost.h
|
@ -29,9 +29,8 @@ e-mail : support@circuitsathome.com
|
||||||
|
|
||||||
/* SPI initialization */
|
/* SPI initialization */
|
||||||
template< typename SPI_CLK, typename SPI_MOSI, typename SPI_MISO, typename SPI_SS > class SPi {
|
template< typename SPI_CLK, typename SPI_MOSI, typename SPI_MISO, typename SPI_SS > class SPi {
|
||||||
#if USING_SPI4TEENSY3
|
|
||||||
public:
|
public:
|
||||||
|
#if USING_SPI4TEENSY3
|
||||||
static void init() {
|
static void init() {
|
||||||
// spi4teensy3 inits everything for us, except /SS
|
// spi4teensy3 inits everything for us, except /SS
|
||||||
// CLK, MOSI and MISO are hard coded for now.
|
// CLK, MOSI and MISO are hard coded for now.
|
||||||
|
@ -40,10 +39,14 @@ public:
|
||||||
SPI_SS::SetDirWrite();
|
SPI_SS::SetDirWrite();
|
||||||
SPI_SS::Set();
|
SPI_SS::Set();
|
||||||
}
|
}
|
||||||
|
#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
|
||||||
|
static void init() {
|
||||||
|
SPI_SS::SetDirWrite();
|
||||||
|
SPI_SS::Set();
|
||||||
|
SPI.begin();
|
||||||
|
SPI.setClockDivider(4); // Set speed to 84MHz/4=21MHz - the MAX3421E can handle up to 26MHz
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
public:
|
|
||||||
|
|
||||||
static void init() {
|
static void init() {
|
||||||
//uint8_t tmp;
|
//uint8_t tmp;
|
||||||
SPI_CLK::SetDirWrite();
|
SPI_CLK::SetDirWrite();
|
||||||
|
@ -67,8 +70,10 @@ typedef SPi< Pb1, Pb2, Pb3, Pb0 > spi;
|
||||||
typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi;
|
typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi;
|
||||||
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
|
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
|
||||||
typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi;
|
typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi;
|
||||||
#elif defined(__MK20DX128__) || defined(__MK20DX256__)
|
#elif defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__))
|
||||||
typedef SPi< P13, P11, P12, P10 > spi;
|
typedef SPi< P13, P11, P12, P10 > spi;
|
||||||
|
#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
|
||||||
|
typedef SPi< P76, P75, P74, P10 > spi;
|
||||||
#else
|
#else
|
||||||
#error "No SPI entry in usbhost.h"
|
#error "No SPI entry in usbhost.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -130,6 +135,9 @@ void MAX3421e< SPI_SS, INTR >::regWr(uint8_t reg, uint8_t data) {
|
||||||
c[0] = reg | 0x02;
|
c[0] = reg | 0x02;
|
||||||
c[1] = data;
|
c[1] = data;
|
||||||
spi4teensy3::send(c, 2);
|
spi4teensy3::send(c, 2);
|
||||||
|
#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
|
||||||
|
SPI.transfer(reg | 0x02);
|
||||||
|
SPI.transfer(data);
|
||||||
#else
|
#else
|
||||||
SPDR = (reg | 0x02);
|
SPDR = (reg | 0x02);
|
||||||
while(!(SPSR & (1 << SPIF)));
|
while(!(SPSR & (1 << SPIF)));
|
||||||
|
@ -151,6 +159,13 @@ uint8_t* MAX3421e< SPI_SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t*
|
||||||
spi4teensy3::send(reg | 0x02);
|
spi4teensy3::send(reg | 0x02);
|
||||||
spi4teensy3::send(data_p, nbytes);
|
spi4teensy3::send(data_p, nbytes);
|
||||||
data_p += nbytes;
|
data_p += nbytes;
|
||||||
|
#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
|
||||||
|
SPI.transfer(reg | 0x02);
|
||||||
|
while(nbytes) {
|
||||||
|
SPI.transfer(*data_p);
|
||||||
|
nbytes--;
|
||||||
|
data_p++; // advance data pointer
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
SPDR = (reg | 0x02); //set WR bit and send register number
|
SPDR = (reg | 0x02); //set WR bit and send register number
|
||||||
while(nbytes) {
|
while(nbytes) {
|
||||||
|
@ -186,6 +201,10 @@ uint8_t MAX3421e< SPI_SS, INTR >::regRd(uint8_t reg) {
|
||||||
spi4teensy3::send(reg);
|
spi4teensy3::send(reg);
|
||||||
uint8_t rv = spi4teensy3::receive();
|
uint8_t rv = spi4teensy3::receive();
|
||||||
SPI_SS::Set();
|
SPI_SS::Set();
|
||||||
|
#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
|
||||||
|
SPI.transfer(reg);
|
||||||
|
uint8_t rv = SPI.transfer(0);
|
||||||
|
SPI_SS::Set();
|
||||||
#else
|
#else
|
||||||
SPDR = reg;
|
SPDR = reg;
|
||||||
while(!(SPSR & (1 << SPIF)));
|
while(!(SPSR & (1 << SPIF)));
|
||||||
|
@ -208,6 +227,12 @@ uint8_t* MAX3421e< SPI_SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t*
|
||||||
spi4teensy3::send(reg);
|
spi4teensy3::send(reg);
|
||||||
spi4teensy3::receive(data_p, nbytes);
|
spi4teensy3::receive(data_p, nbytes);
|
||||||
data_p += nbytes;
|
data_p += nbytes;
|
||||||
|
#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
|
||||||
|
SPI.transfer(reg);
|
||||||
|
while(nbytes) {
|
||||||
|
*data_p++ = SPI.transfer(0);
|
||||||
|
nbytes--;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
SPDR = reg;
|
SPDR = reg;
|
||||||
while(!(SPSR & (1 << SPIF))); //wait
|
while(!(SPSR & (1 << SPIF))); //wait
|
||||||
|
|
Loading…
Reference in a new issue