mirror of
https://github.com/felis/USB_Host_Shield_2.0.git
synced 2024-03-22 11:31:26 +01:00
Merge branch 'xxxajk' into arm
Conflicts: Usb.cpp Usb.h XBOXRECV.cpp adk.h avrpins.h cdcacm.h cdcprolific.h hid.h hidboot.h hidescriptorparser.cpp hidescriptorparser.h masstorage.h message.cpp parsetools.h usbhub.h
This commit is contained in:
commit
84bab09221
113 changed files with 6111 additions and 2909 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
*.bak
|
||||
*.zip
|
||||
*.rar
|
||||
build/
|
12
.gitmodules
vendored
Normal file
12
.gitmodules
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
[submodule "examples/testusbhostFAT/generic_storage"]
|
||||
path = examples/testusbhostFAT/generic_storage
|
||||
url = https://github.com/xxxajk/generic_storage
|
||||
[submodule "examples/testusbhostFAT/xmem2"]
|
||||
path = examples/testusbhostFAT/xmem2
|
||||
url = https://github.com/xxxajk/xmem2
|
||||
[submodule "examples/testusbhostFAT/Arduino_Makefile_master"]
|
||||
path = examples/testusbhostFAT/Arduino_Makefile_master
|
||||
url = https://github.com/xxxajk/Arduino_Makefile_master
|
||||
[submodule "examples/testusbhostFAT/RTClib"]
|
||||
path = examples/testusbhostFAT/RTClib
|
||||
url = https://github.com/xxxajk/RTClib
|
193
BTD.cpp
193
BTD.cpp
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
#include "BTD.h"
|
||||
#define DEBUG // Uncomment to print data for debugging
|
||||
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
|
||||
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
||||
|
||||
const uint8_t BTD::BTD_CONTROL_PIPE = 0;
|
||||
|
@ -25,18 +25,24 @@ const uint8_t BTD::BTD_DATAIN_PIPE = 2;
|
|||
const uint8_t BTD::BTD_DATAOUT_PIPE = 3;
|
||||
|
||||
BTD::BTD(USB *p) :
|
||||
connectToWii(false),
|
||||
pairWithWii(false),
|
||||
pUsb(p), // Pointer to USB class instance - mandatory
|
||||
bAddress(0), // Device address - mandatory
|
||||
bNumEP(1), // If config descriptor needs to be parsed
|
||||
qNextPollTime(0), // Reset NextPollTime
|
||||
pollInterval(0),
|
||||
bPollEnable(false) // Don't start polling before dongle is connected
|
||||
{
|
||||
for (uint8_t i = 0; i < BTD_MAX_ENDPOINTS; i++) {
|
||||
uint8_t i;
|
||||
for (i = 0; i < BTD_MAX_ENDPOINTS; i++) {
|
||||
epInfo[i].epAddr = 0;
|
||||
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
||||
epInfo[i].epAttribs = 0;
|
||||
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
||||
}
|
||||
for (i = 0; i < BTD_NUMSERVICES; i++)
|
||||
btService[i] = NULL;
|
||||
|
||||
if (pUsb) // register in USB subsystem
|
||||
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
|
||||
|
@ -58,7 +64,7 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
#endif
|
||||
// check if address has already been assigned to an instance
|
||||
if (bAddress) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nAddress in use"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
|
@ -68,14 +74,14 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nAddress not found"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
if (!p->epinfo) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nepinfo is null"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
|
@ -110,19 +116,18 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||
if (rcode) {
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nsetAddr: "), 0x80);
|
||||
D_PrintHex<uint8_t > (rcode, 0x80);
|
||||
#endif
|
||||
PrintHex<uint8_t > (rcode, 0x80);
|
||||
return rcode;
|
||||
goto Fail;
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nAddr: "), 0x80);
|
||||
PrintHex<uint8_t > (bAddress, 0x80);
|
||||
D_PrintHex<uint8_t > (bAddress, 0x80);
|
||||
#endif
|
||||
delay(300); // Spec says you should wait at least 200ms
|
||||
|
||||
p->lowspeed = false;
|
||||
|
||||
//get pointer to assigned address record
|
||||
|
@ -145,7 +150,7 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
if (rcode)
|
||||
goto FailSetConfDescr;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
if (PID == PS3_PID || PID == PS3NAVIGATION_PID) {
|
||||
if (PID == PS3_PID)
|
||||
Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80);
|
||||
|
@ -156,25 +161,25 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
#endif
|
||||
|
||||
if (my_bdaddr[0] == 0x00 && my_bdaddr[1] == 0x00 && my_bdaddr[2] == 0x00 && my_bdaddr[3] == 0x00 && my_bdaddr[4] == 0x00 && my_bdaddr[5] == 0x00) {
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nPlease plug in the dongle before trying to pair with the PS3 Controller\n\rOr set the Bluetooth address in the constructor of the PS3BT class"), 0x80);
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nPlease plug in the dongle before trying to pair with the PS3 Controller\r\nor set the Bluetooth address in the constructor of the PS3BT class"), 0x80);
|
||||
#endif
|
||||
} else {
|
||||
if (PID == PS3_PID || PID == PS3NAVIGATION_PID)
|
||||
setBdaddr(my_bdaddr); // Set internal Bluetooth address
|
||||
else
|
||||
setMoveBdaddr(my_bdaddr); // Set internal Bluetooth address
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
|
||||
for (int8_t i = 5; i > 0; i--) {
|
||||
PrintHex<uint8_t > (my_bdaddr[i], 0x80);
|
||||
D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
|
||||
Notify(PSTR(":"), 0x80);
|
||||
}
|
||||
PrintHex<uint8_t > (my_bdaddr[0], 0x80);
|
||||
D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
|
||||
#endif
|
||||
}
|
||||
|
||||
rcode = pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 0); // Reset configuration value
|
||||
pUsb->setConf(bAddress, epInfo[ BTD_CONTROL_PIPE ].epAddr, 0); // Reset configuration value
|
||||
pUsb->setAddr(bAddress, 0, 0); // Reset address
|
||||
Release(); // Release device
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; // Return
|
||||
|
@ -185,9 +190,14 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
// First interface in the configuration must have Bluetooth assigned Class/Subclass/Protocol
|
||||
// And 3 endpoints - interrupt-IN, bulk-IN, bulk-OUT, not necessarily in this order
|
||||
for (uint8_t i = 0; i < num_of_conf; i++) {
|
||||
if (VID == IOGEAR_GBU521_VID && PID == IOGEAR_GBU521_PID) {
|
||||
ConfigDescParser<USB_CLASS_VENDOR_SPECIFIC, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this); // Needed for the IOGEAR GBU521
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||
} else {
|
||||
ConfigDescParser<USB_CLASS_WIRELESS_CTRL, WI_SUBCLASS_RF, WI_PROTOCOL_BT, CP_MASK_COMPARE_ALL> confDescrParser(this);
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||
if (rcode)
|
||||
}
|
||||
if (rcode) // Check error code
|
||||
goto FailGetConfDescr;
|
||||
if (bNumEP >= BTD_MAX_ENDPOINTS) // All endpoints extracted
|
||||
break;
|
||||
|
@ -214,7 +224,7 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
watingForConnection = false;
|
||||
bPollEnable = true;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nBluetooth Dongle Initialized"), 0x80);
|
||||
#endif
|
||||
}
|
||||
|
@ -222,30 +232,40 @@ uint8_t BTD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
|
||||
/* diagnostic messages */
|
||||
FailGetDevDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetDevDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetDevTblEntry:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetDevTblEntry();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailGetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetConfDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetConfDescr();
|
||||
#endif
|
||||
goto Fail;
|
||||
|
||||
FailUnknownDevice:
|
||||
NotifyFailUnknownDevice(VID,PID);
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailUnknownDevice(VID, PID);
|
||||
#endif
|
||||
pUsb->setAddr(bAddress, 0, 0); // Reset address
|
||||
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
Fail:
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nBTD Init Failed, error code: "), 0x80);
|
||||
#endif
|
||||
NotifyFail(rcode);
|
||||
#endif
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
@ -262,10 +282,10 @@ void BTD::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto
|
|||
bConfNum = conf;
|
||||
uint8_t index;
|
||||
|
||||
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) // Interrupt In endpoint found
|
||||
if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) { // Interrupt In endpoint found
|
||||
index = BTD_EVENT_PIPE;
|
||||
|
||||
else {
|
||||
epInfo[index].bmNakPower = USB_NAK_NOWAIT;
|
||||
} else {
|
||||
if ((pep->bmAttributes & 0x02) == 2) // Bulk endpoint found
|
||||
index = ((pep->bEndpointAddress & 0x80) == 0x80) ? BTD_DATAIN_PIPE : BTD_DATAOUT_PIPE;
|
||||
else
|
||||
|
@ -287,17 +307,17 @@ void BTD::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
|
|||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nEndpoint descriptor:"), 0x80);
|
||||
Notify(PSTR("\r\nLength:\t\t"), 0x80);
|
||||
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
|
||||
D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
|
||||
Notify(PSTR("\r\nType:\t\t"), 0x80);
|
||||
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
|
||||
D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
|
||||
Notify(PSTR("\r\nAddress:\t"), 0x80);
|
||||
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
|
||||
D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
|
||||
Notify(PSTR("\r\nAttributes:\t"), 0x80);
|
||||
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
|
||||
D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
|
||||
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
|
||||
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
|
||||
D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
|
||||
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
|
||||
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
|
||||
D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -330,7 +350,7 @@ void BTD::HCI_event_task() {
|
|||
/* check the event pipe*/
|
||||
uint16_t MAX_BUFFER_SIZE = BULK_MAXPKTSIZE; // Request more than 16 bytes anyway, the inTransfer routine will take care of this
|
||||
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ BTD_EVENT_PIPE ].epAddr, &MAX_BUFFER_SIZE, hcibuf); // input on endpoint 1
|
||||
if (!rcode) // Check for errors
|
||||
if (!rcode || rcode == hrNAK) // Check for errors
|
||||
{
|
||||
switch (hcibuf[0]) //switch on event type
|
||||
{
|
||||
|
@ -350,13 +370,13 @@ void BTD::HCI_event_task() {
|
|||
|
||||
case EV_COMMAND_STATUS:
|
||||
if (hcibuf[2]) { // show status on serial if not OK
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nHCI Command Failed: "), 0x80);
|
||||
PrintHex<uint8_t > (hcibuf[2], 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[2], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (hcibuf[4], 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[4], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (hcibuf[5], 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[5], 0x80);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
@ -364,7 +384,7 @@ void BTD::HCI_event_task() {
|
|||
case EV_INQUIRY_COMPLETE:
|
||||
if (inquiry_counter >= 5) {
|
||||
inquiry_counter = 0;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nCouldn't find Wiimote"), 0x80);
|
||||
#endif
|
||||
connectToWii = false;
|
||||
|
@ -398,11 +418,11 @@ void BTD::HCI_event_task() {
|
|||
#ifdef EXTRADEBUG
|
||||
else {
|
||||
Notify(PSTR("\r\nClass of device: "), 0x80);
|
||||
PrintHex<uint8_t > (hcibuf[6 + 8 * hcibuf[2] + 3 * i], 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[6 + 8 * hcibuf[2] + 3 * i], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (hcibuf[5 + 8 * hcibuf[2] + 3 * i], 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[5 + 8 * hcibuf[2] + 3 * i], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (hcibuf[4 + 8 * hcibuf[2] + 3 * i], 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[4 + 8 * hcibuf[2] + 3 * i], 0x80);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -432,7 +452,7 @@ void BTD::HCI_event_task() {
|
|||
|
||||
case EV_REMOTE_NAME_COMPLETE:
|
||||
if (!hcibuf[2]) { // check if reading is OK
|
||||
for (uint8_t i = 0; i < min(sizeof(remote_name),sizeof(hcibuf)-9); i++)
|
||||
for (uint8_t i = 0; i < min(sizeof (remote_name), sizeof (hcibuf) - 9); i++)
|
||||
remote_name[i] = hcibuf[9 + i];
|
||||
hci_event_flag |= HCI_FLAG_REMOTE_NAME_COMPLETE;
|
||||
}
|
||||
|
@ -447,29 +467,29 @@ void BTD::HCI_event_task() {
|
|||
disc_bdaddr[5] = hcibuf[7];
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nClass of device: "), 0x80);
|
||||
PrintHex<uint8_t > (hcibuf[10], 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[10], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (hcibuf[9], 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[9], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (hcibuf[8], 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[8], 0x80);
|
||||
#endif
|
||||
hci_event_flag |= HCI_FLAG_INCOMING_REQUEST;
|
||||
break;
|
||||
|
||||
case EV_PIN_CODE_REQUEST:
|
||||
if (pairWithWii) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nPairing with wiimote"), 0x80);
|
||||
#endif
|
||||
hci_pin_code_request_reply();
|
||||
} else if (btdPin != NULL) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nBluetooth pin is set too: "), 0x80);
|
||||
NotifyStr(btdPin, 0x80);
|
||||
#endif
|
||||
hci_pin_code_request_reply();
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nNo pin was set"), 0x80);
|
||||
#endif
|
||||
hci_pin_code_negative_request_reply();
|
||||
|
@ -477,7 +497,7 @@ void BTD::HCI_event_task() {
|
|||
break;
|
||||
|
||||
case EV_LINK_KEY_REQUEST:
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nReceived Key Request"), 0x80);
|
||||
#endif
|
||||
hci_link_key_request_negative_reply();
|
||||
|
@ -485,7 +505,7 @@ void BTD::HCI_event_task() {
|
|||
|
||||
case EV_AUTHENTICATION_COMPLETE:
|
||||
if (pairWithWii && !connectToWii) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nPairing successful"), 0x80);
|
||||
#endif
|
||||
connectToWii = true; // Only send the ACL data to the Wii service
|
||||
|
@ -508,16 +528,16 @@ void BTD::HCI_event_task() {
|
|||
default:
|
||||
if (hcibuf[0] != 0x00) {
|
||||
Notify(PSTR("\r\nUnmanaged HCI Event: "), 0x80);
|
||||
PrintHex<uint8_t > (hcibuf[0], 0x80);
|
||||
D_PrintHex<uint8_t > (hcibuf[0], 0x80);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
} // switch
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
else if (rcode != hrNAK) {
|
||||
else {
|
||||
Notify(PSTR("\r\nHCI event error: "), 0x80);
|
||||
PrintHex<uint8_t > (rcode, 0x80);
|
||||
D_PrintHex<uint8_t > (rcode, 0x80);
|
||||
}
|
||||
#endif
|
||||
HCI_task();
|
||||
|
@ -539,7 +559,7 @@ void BTD::HCI_task() {
|
|||
hci_counter++;
|
||||
if (hci_cmd_complete) {
|
||||
hci_counter = 0;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nHCI Reset complete"), 0x80);
|
||||
#endif
|
||||
hci_state = HCI_CLASS_STATE;
|
||||
|
@ -548,7 +568,7 @@ void BTD::HCI_task() {
|
|||
hci_num_reset_loops *= 10;
|
||||
if (hci_num_reset_loops > 2000)
|
||||
hci_num_reset_loops = 2000;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nNo response to HCI Reset"), 0x80);
|
||||
#endif
|
||||
hci_state = HCI_INIT_STATE;
|
||||
|
@ -558,7 +578,7 @@ void BTD::HCI_task() {
|
|||
|
||||
case HCI_CLASS_STATE:
|
||||
if (hci_cmd_complete) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nWrite class of device"), 0x80);
|
||||
#endif
|
||||
hci_state = HCI_BDADDR_STATE;
|
||||
|
@ -568,13 +588,13 @@ void BTD::HCI_task() {
|
|||
|
||||
case HCI_BDADDR_STATE:
|
||||
if (hci_read_bdaddr_complete) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nLocal Bluetooth Address: "), 0x80);
|
||||
for (int8_t i = 5; i > 0; i--) {
|
||||
PrintHex<uint8_t > (my_bdaddr[i], 0x80);
|
||||
D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
|
||||
Notify(PSTR(":"), 0x80);
|
||||
}
|
||||
PrintHex<uint8_t > (my_bdaddr[0], 0x80);
|
||||
D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
|
||||
#endif
|
||||
hci_read_local_version_information();
|
||||
hci_state = HCI_LOCAL_VERSION_STATE;
|
||||
|
@ -593,7 +613,7 @@ void BTD::HCI_task() {
|
|||
|
||||
case HCI_SET_NAME_STATE:
|
||||
if (hci_cmd_complete) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nThe name is set to: "), 0x80);
|
||||
NotifyStr(btdName, 0x80);
|
||||
#endif
|
||||
|
@ -603,7 +623,7 @@ void BTD::HCI_task() {
|
|||
|
||||
case HCI_CHECK_WII_SERVICE:
|
||||
if (pairWithWii) { // Check if it should try to connect to a wiimote
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nStarting inquiry\r\nPress 1 & 2 on the Wiimote\r\nOr press sync if you are using a Wii U Pro Controller"), 0x80);
|
||||
#endif
|
||||
hci_inquiry();
|
||||
|
@ -615,7 +635,7 @@ void BTD::HCI_task() {
|
|||
case HCI_INQUIRY_STATE:
|
||||
if (hci_wii_found) {
|
||||
hci_inquiry_cancel(); // Stop inquiry
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nWiimote found"), 0x80);
|
||||
Notify(PSTR("\r\nNow just create the instance like so:"), 0x80);
|
||||
Notify(PSTR("\r\nWII Wii(&Btd);"), 0x80);
|
||||
|
@ -631,7 +651,7 @@ void BTD::HCI_task() {
|
|||
|
||||
case HCI_CONNECT_WII_STATE:
|
||||
if (hci_cmd_complete) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nConnecting to Wiimote"), 0x80);
|
||||
#endif
|
||||
hci_connect();
|
||||
|
@ -642,13 +662,13 @@ void BTD::HCI_task() {
|
|||
case HCI_CONNECTED_WII_STATE:
|
||||
if (hci_connect_event) {
|
||||
if (hci_connect_complete) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nConnected to Wiimote"), 0x80);
|
||||
#endif
|
||||
hci_authentication_request(); // This will start the pairing with the wiimote
|
||||
hci_state = HCI_SCANNING_STATE;
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nTrying to connect one more time..."), 0x80);
|
||||
#endif
|
||||
hci_connect(); // Try to connect one more time
|
||||
|
@ -658,7 +678,7 @@ void BTD::HCI_task() {
|
|||
|
||||
case HCI_SCANNING_STATE:
|
||||
if (!connectToWii && !pairWithWii) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nWait For Incoming Connection Request"), 0x80);
|
||||
#endif
|
||||
hci_write_scan_enable();
|
||||
|
@ -670,7 +690,7 @@ void BTD::HCI_task() {
|
|||
case HCI_CONNECT_IN_STATE:
|
||||
if (hci_incoming_connect_request) {
|
||||
watingForConnection = false;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nIncoming Connection Request"), 0x80);
|
||||
#endif
|
||||
hci_remote_name();
|
||||
|
@ -681,7 +701,7 @@ void BTD::HCI_task() {
|
|||
|
||||
case HCI_REMOTE_NAME_STATE:
|
||||
if (hci_remote_name_complete) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nRemote Name: "), 0x80);
|
||||
for (uint8_t i = 0; i < 30; i++) {
|
||||
if (remote_name[i] == NULL)
|
||||
|
@ -691,16 +711,16 @@ void BTD::HCI_task() {
|
|||
#endif
|
||||
if (strncmp((const char*)remote_name, "Nintendo", 8) == 0) {
|
||||
incomingWii = true;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nWiimote is connecting"), 0x80);
|
||||
#endif
|
||||
if (strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-TR", 22) == 0) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR(" with Motion Plus Inside"), 0x80);
|
||||
#endif
|
||||
motionPlusInside = true;
|
||||
} else if (strncmp((const char*)remote_name, "Nintendo RVL-CNT-01-UC", 22) == 0) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR(" - Wii U Pro Controller"), 0x80);
|
||||
#endif
|
||||
motionPlusInside = true;
|
||||
|
@ -721,13 +741,13 @@ void BTD::HCI_task() {
|
|||
|
||||
case HCI_CONNECTED_STATE:
|
||||
if (hci_connect_complete) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nConnected to Device: "), 0x80);
|
||||
for (int8_t i = 5; i > 0; i--) {
|
||||
PrintHex<uint8_t > (disc_bdaddr[i], 0x80);
|
||||
D_PrintHex<uint8_t > (disc_bdaddr[i], 0x80);
|
||||
Notify(PSTR(":"), 0x80);
|
||||
}
|
||||
PrintHex<uint8_t > (disc_bdaddr[0], 0x80);
|
||||
D_PrintHex<uint8_t > (disc_bdaddr[0], 0x80);
|
||||
#endif
|
||||
// Clear these flags for a new connection
|
||||
l2capConnectionClaimed = false;
|
||||
|
@ -749,7 +769,7 @@ void BTD::HCI_task() {
|
|||
|
||||
case HCI_DISCONNECT_STATE:
|
||||
if (hci_disconnect_complete) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nHCI Disconnected from Device"), 0x80);
|
||||
#endif
|
||||
hci_event_flag = 0; // Clear all flags
|
||||
|
@ -779,7 +799,7 @@ void BTD::ACL_event_task() {
|
|||
#ifdef EXTRADEBUG
|
||||
else if (rcode != hrNAK) {
|
||||
Notify(PSTR("\r\nACL data in error: "), 0x80);
|
||||
PrintHex<uint8_t > (rcode, 0x80);
|
||||
D_PrintHex<uint8_t > (rcode, 0x80);
|
||||
}
|
||||
#endif
|
||||
for (uint8_t i = 0; i < BTD_NUMSERVICES; i++)
|
||||
|
@ -946,15 +966,14 @@ void BTD::hci_pin_code_request_reply() {
|
|||
hcibuf[8] = disc_bdaddr[5];
|
||||
if (pairWithWii) {
|
||||
hcibuf[9] = 6; // Pin length is the length of the Bluetooth address
|
||||
if(wiiUProController) {
|
||||
#ifdef DEBUG
|
||||
if (wiiUProController) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nParing with Wii U Pro Controller"), 0x80);
|
||||
#endif
|
||||
for(uint8_t i = 0; i < 6; i++)
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
hcibuf[10 + i] = my_bdaddr[i]; // The pin is the Bluetooth dongles Bluetooth address backwards
|
||||
}
|
||||
else {
|
||||
for(uint8_t i = 0; i < 6; i++)
|
||||
} else {
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
hcibuf[10 + i] = disc_bdaddr[i]; // The pin is the Wiimote's Bluetooth address backwards
|
||||
}
|
||||
for (uint8_t i = 16; i < 26; i++)
|
||||
|
@ -1074,13 +1093,13 @@ void BTD::L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t
|
|||
uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ BTD_DATAOUT_PIPE ].epAddr, (8 + nbytes), buf);
|
||||
if (rcode) {
|
||||
delay(100); // This small delay prevents it from overflowing if it fails
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nError sending L2CAP message: 0x"), 0x80);
|
||||
PrintHex<uint8_t > (rcode, 0x80);
|
||||
D_PrintHex<uint8_t > (rcode, 0x80);
|
||||
Notify(PSTR(" - Channel ID: "), 0x80);
|
||||
PrintHex<uint8_t > (channelHigh, 0x80);
|
||||
D_PrintHex<uint8_t > (channelHigh, 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (channelLow, 0x80);
|
||||
D_PrintHex<uint8_t > (channelLow, 0x80);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
25
BTD.h
25
BTD.h
|
@ -19,7 +19,6 @@
|
|||
#define _btd_h_
|
||||
|
||||
#include "Usb.h"
|
||||
#include "confdescparser.h"
|
||||
|
||||
//PID and VID of the Sony PS3 devices
|
||||
#define PS3_VID 0x054C // Sony Corporation
|
||||
|
@ -27,6 +26,9 @@
|
|||
#define PS3NAVIGATION_PID 0x042F // Navigation controller
|
||||
#define PS3MOVE_PID 0x03D5 // Motion controller
|
||||
|
||||
#define IOGEAR_GBU521_VID 0x0A5C // The IOGEAR GBU521 dongle does not presents itself correctly, so we have to check for it manually
|
||||
#define IOGEAR_GBU521_PID 0x21E8
|
||||
|
||||
/* Bluetooth dongle data taken from descriptors */
|
||||
#define BULK_MAXPKTSIZE 64 // max size for ACL data
|
||||
|
||||
|
@ -129,7 +131,7 @@
|
|||
#define WI_PROTOCOL_BT 0x01 // Bluetooth Programming Interface
|
||||
|
||||
#define BTD_MAX_ENDPOINTS 4
|
||||
#define BTD_NUMSERVICES 4 // Max number of Bluetooth services
|
||||
#define BTD_NUMSERVICES 4 // Max number of Bluetooth services - if you need more than four simply increase this number
|
||||
|
||||
/** All Bluetooth services should include this class. */
|
||||
class BluetoothService {
|
||||
|
@ -194,6 +196,23 @@ public:
|
|||
virtual bool isReady() {
|
||||
return bPollEnable;
|
||||
};
|
||||
/**
|
||||
* Used by the USB core to check what this driver support.
|
||||
* @param klass The device's USB class.
|
||||
* @return Returns true if the device's USB class matches this driver.
|
||||
*/
|
||||
virtual boolean DEVCLASSOK(uint8_t klass) { return (klass == USB_CLASS_WIRELESS_CTRL); }
|
||||
|
||||
/**
|
||||
* Used by the USB core to check what this driver support.
|
||||
* Used to set the Bluetooth address into the PS3 controllers.
|
||||
* @param vid The device's VID.
|
||||
* @param pid The device's PID.
|
||||
* @return Returns true if the device's VID and PID matches this driver.
|
||||
*/
|
||||
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) {
|
||||
return ((vid == PS3_VID || vid == IOGEAR_GBU521_VID) && (pid == PS3_PID || pid == PS3NAVIGATION_PID || pid == PS3MOVE_PID || pid == IOGEAR_GBU521_PID));
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/** @name UsbConfigXtracter implementation */
|
||||
|
@ -450,7 +469,7 @@ private:
|
|||
|
||||
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 l2capoutbuf[BULK_MAXPKTSIZE]; //General purpose buffer for l2cap out data
|
||||
uint8_t l2capoutbuf[14]; //General purpose buffer for l2cap out data
|
||||
|
||||
/* State machines */
|
||||
void HCI_event_task(); // Poll the HCI event pipe
|
||||
|
|
87
PS3BT.cpp
87
PS3BT.cpp
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
#include "PS3BT.h"
|
||||
#define DEBUG // Uncomment to print data for debugging
|
||||
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
|
||||
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
||||
//#define PRINTREPORT // Uncomment to print the report send by the PS3 Controllers
|
||||
|
||||
|
@ -255,7 +255,7 @@ void PS3BT::ACLData(uint8_t* ACLData) {
|
|||
l2cap_state = L2CAP_WAIT;
|
||||
for (uint8_t i = 0; i < 30; i++)
|
||||
remote_name[i] = pBtd->remote_name[i]; // Store the remote name for the connection
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
if (pBtd->hci_version < 3) { // Check the HCI Version of the Bluetooth dongle
|
||||
Notify(PSTR("\r\nYour dongle may not support reading the analog buttons, sensors and status\r\nYour HCI Version is: "), 0x80);
|
||||
Notify(pBtd->hci_version, 0x80);
|
||||
|
@ -270,32 +270,32 @@ void PS3BT::ACLData(uint8_t* ACLData) {
|
|||
l2capinbuf[i] = ACLData[i];
|
||||
if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { //l2cap_control - Channel ID for ACL-U
|
||||
if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
||||
Notify(PSTR(" Data: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[17], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[16], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[15], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
#endif
|
||||
} else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
||||
Notify(PSTR(" SCID: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[15], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
Notify(PSTR(" Identifier: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[9], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
|
||||
#endif
|
||||
if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
|
||||
identifier = l2capinbuf[9];
|
||||
|
@ -330,14 +330,14 @@ void PS3BT::ACLData(uint8_t* ACLData) {
|
|||
}
|
||||
} else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
|
||||
if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
pBtd->l2cap_disconnection_response(hci_handle, identifier, control_dcid, control_scid);
|
||||
Reset();
|
||||
} else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
|
@ -358,7 +358,7 @@ void PS3BT::ACLData(uint8_t* ACLData) {
|
|||
#ifdef EXTRADEBUG
|
||||
else {
|
||||
Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[8], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
|
||||
}
|
||||
#endif
|
||||
} else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
|
||||
|
@ -381,7 +381,7 @@ void PS3BT::ACLData(uint8_t* ACLData) {
|
|||
|
||||
#ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send by the PS3 Controllers
|
||||
for (uint8_t i = 10; i < 58; i++) {
|
||||
PrintHex<uint8_t > (l2capinbuf[i], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[i], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
}
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
|
@ -397,7 +397,7 @@ void PS3BT::L2CAP_task() {
|
|||
switch (l2cap_state) {
|
||||
case L2CAP_WAIT:
|
||||
if (l2cap_connection_request_control_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING);
|
||||
|
@ -411,7 +411,7 @@ void PS3BT::L2CAP_task() {
|
|||
break;
|
||||
case L2CAP_CONTROL_REQUEST:
|
||||
if (l2cap_config_request_control_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nHID Control Configuration Request"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_config_response(hci_handle, identifier, control_scid);
|
||||
|
@ -421,7 +421,7 @@ void PS3BT::L2CAP_task() {
|
|||
|
||||
case L2CAP_CONTROL_SUCCESS:
|
||||
if (l2cap_config_success_control_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
|
||||
#endif
|
||||
l2cap_state = L2CAP_INTERRUPT_SETUP;
|
||||
|
@ -429,7 +429,7 @@ void PS3BT::L2CAP_task() {
|
|||
break;
|
||||
case L2CAP_INTERRUPT_SETUP:
|
||||
if (l2cap_connection_request_interrupt_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING);
|
||||
|
@ -444,7 +444,7 @@ void PS3BT::L2CAP_task() {
|
|||
break;
|
||||
case L2CAP_INTERRUPT_REQUEST:
|
||||
if (l2cap_config_request_interrupt_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nHID Interrupt Configuration Request"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_config_response(hci_handle, identifier, interrupt_scid);
|
||||
|
@ -453,15 +453,12 @@ void PS3BT::L2CAP_task() {
|
|||
break;
|
||||
case L2CAP_INTERRUPT_SUCCESS:
|
||||
if (l2cap_config_success_interrupt_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nHID Interrupt Successfully Configured"), 0x80);
|
||||
#endif
|
||||
if (remote_name[0] == 'M') { // First letter in Motion Controller ('M')
|
||||
for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) // Reset l2cap in buffer as it sometimes read it as a button has been pressed
|
||||
l2capinbuf[i] = 0;
|
||||
ButtonState = 0;
|
||||
OldButtonState = 0;
|
||||
|
||||
l2cap_state = L2CAP_HID_PS3_LED;
|
||||
} else
|
||||
l2cap_state = L2CAP_HID_ENABLE_SIXAXIS;
|
||||
|
@ -473,7 +470,7 @@ void PS3BT::L2CAP_task() {
|
|||
|
||||
case L2CAP_INTERRUPT_DISCONNECT:
|
||||
if (l2cap_disconnect_response_interrupt_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
|
||||
#endif
|
||||
identifier++;
|
||||
|
@ -484,7 +481,7 @@ void PS3BT::L2CAP_task() {
|
|||
|
||||
case L2CAP_CONTROL_DISCONNECT:
|
||||
if (l2cap_disconnect_response_control_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
|
||||
#endif
|
||||
pBtd->hci_disconnect(hci_handle);
|
||||
|
@ -502,12 +499,9 @@ void PS3BT::Run() {
|
|||
if (millis() - timer > 1000) { // loop 1 second before sending the command
|
||||
for (uint8_t i = 0; i < BULK_MAXPKTSIZE; i++) // Reset l2cap in buffer as it sometimes read it as a button has been pressed
|
||||
l2capinbuf[i] = 0;
|
||||
ButtonState = 0;
|
||||
OldButtonState = 0;
|
||||
|
||||
enable_sixaxis();
|
||||
for (uint8_t i = 15; i < 19; i++)
|
||||
l2capinbuf[i] = 0x7F; // Set the analog joystick values to center position
|
||||
enable_sixaxis();
|
||||
l2cap_state = L2CAP_HID_PS3_LED;
|
||||
timer = millis();
|
||||
}
|
||||
|
@ -516,25 +510,27 @@ void PS3BT::Run() {
|
|||
case L2CAP_HID_PS3_LED:
|
||||
if (millis() - timer > 1000) { // loop 1 second before sending the command
|
||||
if (remote_name[0] == 'P') { // First letter in PLAYSTATION(R)3 Controller ('P')
|
||||
setLedOn(LED1);
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDualshock 3 Controller Enabled\r\n"), 0x80);
|
||||
#endif
|
||||
PS3Connected = true;
|
||||
} else if (remote_name[0] == 'N') { // First letter in Navigation Controller ('N')
|
||||
setLedOn(LED1); // This just turns LED constantly on, on the Navigation controller
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nNavigation Controller Enabled\r\n"), 0x80);
|
||||
#endif
|
||||
PS3NavigationConnected = true;
|
||||
} else if (remote_name[0] == 'M') { // First letter in Motion Controller ('M')
|
||||
moveSetBulb(Red);
|
||||
timerBulbRumble = millis();
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nMotion Controller Enabled\r\n"), 0x80);
|
||||
#endif
|
||||
PS3MoveConnected = true;
|
||||
}
|
||||
ButtonState = 0; // Clear all values
|
||||
OldButtonState = 0;
|
||||
ButtonClickState = 0;
|
||||
|
||||
onInit(); // Turn on the LED on the controller
|
||||
l2cap_state = L2CAP_DONE;
|
||||
}
|
||||
break;
|
||||
|
@ -650,7 +646,7 @@ void PS3BT::moveSetBulb(Colors color) { //Use this to set the Color using the pr
|
|||
}
|
||||
|
||||
void PS3BT::moveSetRumble(uint8_t rumble) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
if (rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
|
||||
Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"), 0x80);
|
||||
#endif
|
||||
|
@ -659,3 +655,14 @@ void PS3BT::moveSetRumble(uint8_t rumble) {
|
|||
|
||||
HIDMove_Command(HIDMoveBuffer, HID_BUFFERSIZE);
|
||||
}
|
||||
|
||||
void PS3BT::onInit() {
|
||||
if (pFuncOnInit)
|
||||
pFuncOnInit(); // Call the user function
|
||||
else {
|
||||
if (PS3MoveConnected)
|
||||
moveSetBulb(Red);
|
||||
else // Dualshock 3 or Navigation controller
|
||||
setLedOn(LED1);
|
||||
}
|
||||
}
|
26
PS3BT.h
26
PS3BT.h
|
@ -207,19 +207,35 @@ public:
|
|||
* @param rumble The desired value in the range from 64-255.
|
||||
*/
|
||||
void moveSetRumble(uint8_t rumble);
|
||||
|
||||
/**
|
||||
* Used to call your own function when the controller is successfully initialized.
|
||||
* @param funcOnInit Function to call.
|
||||
*/
|
||||
void attachOnInit(void (*funcOnInit)(void)) {
|
||||
pFuncOnInit = funcOnInit;
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/** Variable used to indicate if the normal playstation controller is successfully connected. */
|
||||
/** Variable used to indicate if the normal Playstation controller is successfully connected. */
|
||||
bool PS3Connected;
|
||||
/** Variable used to indicate if the move controller is successfully connected. */
|
||||
/** Variable used to indicate if the Move controller is successfully connected. */
|
||||
bool PS3MoveConnected;
|
||||
/** Variable used to indicate if the navigation controller is successfully connected. */
|
||||
/** Variable used to indicate if the Navigation controller is successfully connected. */
|
||||
bool PS3NavigationConnected;
|
||||
|
||||
private:
|
||||
/* mandatory members */
|
||||
/* Mandatory members */
|
||||
BTD *pBtd;
|
||||
|
||||
/**
|
||||
* Called when the controller 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.
|
||||
*/
|
||||
void onInit();
|
||||
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
|
||||
|
||||
void L2CAP_task(); // L2CAP state machine
|
||||
|
||||
/* Variables filled from HCI event management */
|
||||
|
@ -229,7 +245,7 @@ private:
|
|||
|
||||
/* variables used by high level L2CAP task */
|
||||
uint8_t l2cap_state;
|
||||
uint16_t l2cap_event_flag; // L2CAP flags of received bluetooth events
|
||||
uint16_t l2cap_event_flag; // L2CAP flags of received Bluetooth events
|
||||
|
||||
unsigned long timer;
|
||||
|
||||
|
|
84
PS3USB.cpp
84
PS3USB.cpp
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
#include "PS3USB.h"
|
||||
#define DEBUG // Uncomment to print data for debugging
|
||||
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
|
||||
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
||||
//#define PRINTREPORT // Uncomment to print the report send by the PS3 Controllers
|
||||
|
||||
|
@ -58,7 +58,7 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
#endif
|
||||
// check if address has already been assigned to an instance
|
||||
if (bAddress) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nAddress in use"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
|
@ -68,14 +68,14 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nAddress not found"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
if (!p->epinfo) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nepinfo is null"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
|
@ -118,16 +118,18 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nsetAddr: "), 0x80);
|
||||
D_PrintHex<uint8_t > (rcode, 0x80);
|
||||
#endif
|
||||
PrintHex<uint8_t > (rcode, 0x80);
|
||||
return rcode;
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nAddr: "), 0x80);
|
||||
PrintHex<uint8_t > (bAddress, 0x80);
|
||||
D_PrintHex<uint8_t > (bAddress, 0x80);
|
||||
#endif
|
||||
delay(300); // Spec says you should wait at least 200ms
|
||||
|
||||
p->lowspeed = false;
|
||||
|
||||
//get pointer to assigned address record
|
||||
|
@ -173,20 +175,17 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
|
||||
if (PID == PS3_PID || PID == PS3NAVIGATION_PID) {
|
||||
if (PID == PS3_PID) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDualshock 3 Controller Connected"), 0x80);
|
||||
#endif
|
||||
PS3Connected = true;
|
||||
} else { // must be a navigation controller
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nNavigation Controller Connected"), 0x80);
|
||||
#endif
|
||||
PS3NavigationConnected = true;
|
||||
}
|
||||
/* Set internal bluetooth address and request for data */
|
||||
setBdaddr(my_bdaddr);
|
||||
enable_sixaxis();
|
||||
setLedOn(LED1);
|
||||
enable_sixaxis(); // The PS3 controller needs a special command before it starts sending data
|
||||
|
||||
// Needed for PS3 Dualshock and Navigation commands to work
|
||||
for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++)
|
||||
|
@ -195,24 +194,28 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
for (uint8_t i = 6; i < 10; i++)
|
||||
readBuf[i] = 0x7F; // Set the analog joystick values to center position
|
||||
} else { // must be a Motion controller
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nMotion Controller Connected"), 0x80);
|
||||
#endif
|
||||
PS3MoveConnected = true;
|
||||
setMoveBdaddr(my_bdaddr); // Set internal bluetooth address
|
||||
moveSetBulb(Red);
|
||||
|
||||
writeBuf[0] = 0x02; // Set report ID, this is needed for Move commands to work
|
||||
}
|
||||
if (my_bdaddr[0] != 0x00 || my_bdaddr[1] != 0x00 || my_bdaddr[2] != 0x00 || my_bdaddr[3] != 0x00 || my_bdaddr[4] != 0x00 || my_bdaddr[5] != 0x00) {
|
||||
if (PS3MoveConnected)
|
||||
setMoveBdaddr(my_bdaddr); // Set internal Bluetooth address
|
||||
else
|
||||
setBdaddr(my_bdaddr); // Set internal Bluetooth address
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nBluetooth Address was set to: "), 0x80);
|
||||
for (int8_t i = 5; i > 0; i--) {
|
||||
PrintHex<uint8_t > (my_bdaddr[i], 0x80);
|
||||
D_PrintHex<uint8_t > (my_bdaddr[i], 0x80);
|
||||
Notify(PSTR(":"), 0x80);
|
||||
}
|
||||
PrintHex<uint8_t > (my_bdaddr[0], 0x80);
|
||||
D_PrintHex<uint8_t > (my_bdaddr[0], 0x80);
|
||||
#endif
|
||||
}
|
||||
onInit();
|
||||
|
||||
bPollEnable = true;
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
|
@ -221,25 +224,32 @@ uint8_t PS3USB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
|
||||
/* diagnostic messages */
|
||||
FailGetDevDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetDevDescr();
|
||||
goto Fail;
|
||||
|
||||
#endif
|
||||
FailSetDevTblEntry:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetDevTblEntry();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetConfDescr();
|
||||
#endif
|
||||
goto Fail;
|
||||
FailUnknownDevice:
|
||||
NotifyFailUnknownDevice(VID,PID);
|
||||
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
Fail:
|
||||
|
||||
#ifdef DEBUG
|
||||
Notify(PSTR("\r\nPS3 Init Failed, error code: "), 0x80);
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailUnknownDevice(VID, PID);
|
||||
#endif
|
||||
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
Fail:
|
||||
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nPS3 Init Failed, error code: "), 0x80);
|
||||
NotifyFail(rcode);
|
||||
#endif
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
@ -298,7 +308,7 @@ void PS3USB::printReport() { //Uncomment "#define PRINTREPORT" to print the repo
|
|||
if (readBuf == NULL)
|
||||
return;
|
||||
for (uint8_t i = 0; i < PS3_REPORT_BUFFER_SIZE; i++) {
|
||||
PrintHex<uint8_t > (readBuf[i], 0x80);
|
||||
D_PrintHex<uint8_t > (readBuf[i], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
}
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
|
@ -427,7 +437,7 @@ void PS3USB::setRumbleOff() {
|
|||
|
||||
void PS3USB::setRumbleOn(Rumble mode) {
|
||||
if ((mode & 0x30) > 0x00) {
|
||||
uint8_t power[2] = { 0xff, 0x00 }; // Defaults to RumbleLow
|
||||
uint8_t power[2] = {0xff, 0x00}; // Defaults to RumbleLow
|
||||
if (mode == RumbleHigh) {
|
||||
power[0] = 0x00;
|
||||
power[1] = 0xff;
|
||||
|
@ -448,14 +458,17 @@ void PS3USB::setLedRaw(uint8_t value) {
|
|||
writeBuf[9] = value << 1;
|
||||
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
void PS3USB::setLedOff(LED a) {
|
||||
writeBuf[9] &= ~((uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1));
|
||||
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
void PS3USB::setLedOn(LED a) {
|
||||
writeBuf[9] |= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1);
|
||||
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
void PS3USB::setLedToggle(LED a) {
|
||||
writeBuf[9] ^= (uint8_t)((pgm_read_byte(&LEDS[(uint8_t)a]) & 0x0f) << 1);
|
||||
PS3_Command(writeBuf, PS3_REPORT_BUFFER_SIZE);
|
||||
|
@ -503,7 +516,7 @@ void PS3USB::moveSetBulb(Colors color) { //Use this to set the Color using the p
|
|||
}
|
||||
|
||||
void PS3USB::moveSetRumble(uint8_t rumble) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
if (rumble < 64 && rumble != 0) // The rumble value has to at least 64, or approximately 25% (64/255*100)
|
||||
Notify(PSTR("\r\nThe rumble value has to at least 64, or approximately 25%"), 0x80);
|
||||
#endif
|
||||
|
@ -528,3 +541,14 @@ void PS3USB::setMoveBdaddr(uint8_t* BDADDR) {
|
|||
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x05), Report Type (Feature 0x03), interface (0x00), datalength, datalength, data)
|
||||
pUsb->ctrlReq(bAddress, epInfo[PS3_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x05, 0x03, 0x00, 11, 11, buf, NULL);
|
||||
}
|
||||
|
||||
void PS3USB::onInit() {
|
||||
if (pFuncOnInit)
|
||||
pFuncOnInit(); // Call the user function
|
||||
else {
|
||||
if (PS3MoveConnected)
|
||||
moveSetBulb(Red);
|
||||
else // Dualshock 3 or Navigation controller
|
||||
setLedOn(LED1);
|
||||
}
|
||||
}
|
||||
|
|
32
PS3USB.h
32
PS3USB.h
|
@ -18,12 +18,6 @@
|
|||
#ifndef _ps3usb_h_
|
||||
#define _ps3usb_h_
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include "Usb.h"
|
||||
#include "PS3Enums.h"
|
||||
|
||||
|
@ -104,6 +98,16 @@ public:
|
|||
virtual bool isReady() {
|
||||
return bPollEnable;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used by the USB core to check what this driver support.
|
||||
* @param vid The device's VID.
|
||||
* @param pid The device's PID.
|
||||
* @return Returns true if the device's VID and PID matches this driver.
|
||||
*/
|
||||
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) {
|
||||
return (vid == PS3_VID && (pid == PS3_PID || pid == PS3NAVIGATION_PID || pid == PS3MOVE_PID));
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/**
|
||||
|
@ -224,6 +228,14 @@ public:
|
|||
* @param rumble The desired value in the range from 64-255.
|
||||
*/
|
||||
void moveSetRumble(uint8_t rumble);
|
||||
|
||||
/**
|
||||
* Used to call your own function when the controller is successfully initialized.
|
||||
* @param funcOnInit Function to call.
|
||||
*/
|
||||
void attachOnInit(void (*funcOnInit)(void)) {
|
||||
pFuncOnInit = funcOnInit;
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/** Variable used to indicate if the normal playstation controller is successfully connected. */
|
||||
|
@ -242,6 +254,14 @@ protected:
|
|||
EpInfo epInfo[PS3_MAX_ENDPOINTS];
|
||||
|
||||
private:
|
||||
/**
|
||||
* Called when the controller 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.
|
||||
*/
|
||||
void onInit();
|
||||
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
|
||||
|
||||
bool bPollEnable;
|
||||
|
||||
uint32_t timer; // used to continuously set PS3 Move controller Bulb and rumble values
|
||||
|
|
73
README.md
73
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>
|
||||
* Developers of the USB Core, HID, FTDI, ADK, ACM, and PL2303 libraries
|
||||
* __Kristian Lauszus, TKJ Electronics__ - <kristianl@tkjelectronics.com>
|
||||
* Developer of the BTD, SPP, PS3, Wii, and Xbox libraries
|
||||
* Developer of the [BTD](#bluetooth-libraries), [SPP](#spp-library), [PS3](#ps3-library), [Wii](#wii-library), and [Xbox](#xbox-library) libraries
|
||||
* __Andrew Kroll__ - <xxxajk@gmail.com>
|
||||
* Major contributor to mass storage code
|
||||
|
||||
|
@ -53,23 +53,41 @@ For more information visit the following site: <http://arduino.cc/en/Guide/Libra
|
|||
|
||||
Documentation for the library can be found at the following link: <http://felis.github.com/USB_Host_Shield_2.0/>.
|
||||
|
||||
### Arduino ADK
|
||||
To use this library with the official [Arduino ADK](http://arduino.cc/en/Main/ArduinoBoardADK) uncomment the following line in [avrpins.h](https://github.com/felis/USB_Host_Shield_2.0/blob/master/avrpins.h):
|
||||
### Enable debugging
|
||||
|
||||
<code>
|
||||
\#define BOARD\_MEGA_ADK
|
||||
</code>
|
||||
By default serial debugging is disabled. To turn it on simply change ```ENABLE_UHS_DEBUGGING``` to 1 in [settings.h](settings.h) like so:
|
||||
|
||||
### [Bluetooth libraries](https://github.com/felis/USB_Host_Shield_2.0/blob/master/BTD.cpp)
|
||||
```
|
||||
#define ENABLE_UHS_DEBUGGING 1
|
||||
```
|
||||
|
||||
The [BTD library](https://github.com/felis/USB_Host_Shield_2.0/blob/master/BTD.cpp) is a general purpose library for an ordinary Bluetooth dongle.
|
||||
### Boards
|
||||
|
||||
Currently the following boards are supported by the library:
|
||||
|
||||
* All official Arduino AVR boards (Uno, Duemilanove, Mega, Mega 2560, Mega ADK, Leonardo etc.)
|
||||
* Teensy (Teensy 1.0, Teensy 2.0 and Teensy++ 2.0)
|
||||
* Balanduino
|
||||
* Sanguino
|
||||
* Black Widdow
|
||||
|
||||
The following boards need to be activated manually in [settings.h](settings.h):
|
||||
|
||||
* Arduino Mega ADK
|
||||
* Black Widdow
|
||||
|
||||
Simply set the corresponding value to 1 instead of 0.
|
||||
|
||||
### [Bluetooth libraries](BTD.cpp)
|
||||
|
||||
The [BTD library](BTD.cpp) is a general purpose library for an ordinary Bluetooth dongle.
|
||||
This library make it easy to add support for different Bluetooth services like a PS3 or a Wii controller or SPP which is a virtual serial port via Bluetooth.
|
||||
Some different examples can be found in the [example directory](https://github.com/felis/USB_Host_Shield_2.0/tree/master/examples/Bluetooth).
|
||||
Some different examples can be found in the [example directory](examples/Bluetooth).
|
||||
|
||||
The BTD library will also make it possible to use multiple services at once, the following example sketch is an example of this:
|
||||
<https://github.com/felis/USB_Host_Shield_2.0/blob/master/examples/Bluetooth/PS3SPP/PS3SPP.ino>
|
||||
|
||||
### [SPP library](https://github.com/felis/USB_Host_Shield_2.0/blob/master/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.
|
||||
It has been tested successfully on Windows, Mac OS X, Linux, and Android.
|
||||
|
@ -84,7 +102,7 @@ It enables me to see the Bluetooth communication between my Mac and any device.
|
|||
|
||||
### PS3 Library
|
||||
|
||||
These libraries consist of the [PS3BT](https://github.com/felis/USB_Host_Shield_2.0/blob/master/PS3BT.cpp) and [PS3USB](https://github.com/felis/USB_Host_Shield_2.0/blob/master/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.
|
||||
|
||||
In order to use your Playstation controller via Bluetooth you have to set the Bluetooth address of the dongle internally to your PS3 Controller. This can be achieved by plugging the controller in via USB and letting the library set it automatically.
|
||||
|
||||
|
@ -110,15 +128,30 @@ Also a big thanks all the people behind these sites about the Motion controller:
|
|||
* <https://github.com/thp/psmoveapi>
|
||||
* <http://code.google.com/p/moveonpc/>
|
||||
|
||||
### Xbox 360 Library
|
||||
### Xbox Libraries
|
||||
|
||||
The library supports both the original Xbox controller via USB and the Xbox 360 controller both via USB and wirelessly.
|
||||
|
||||
#### Xbox library
|
||||
|
||||
The [XBOXOLD](XBOXOLD.cpp) class implements support for the original Xbox controller via USB.
|
||||
|
||||
All the information are from the following sites:
|
||||
|
||||
* <https://github.com/torvalds/linux/blob/master/Documentation/input/xpad.txt>
|
||||
* <https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c>
|
||||
* <http://euc.jp/periphs/xbox-controller.ja.html>
|
||||
* <https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL#L15>
|
||||
|
||||
#### Xbox 360 Library
|
||||
|
||||
The library support one Xbox 360 via USB or up to four Xbox 360 controllers wirelessly by using a [Xbox 360 wireless receiver](http://blog.tkjelectronics.dk/wp-content/uploads/xbox360-wireless-receiver.jpg).
|
||||
|
||||
To use it via USB use the [XBOXUSB](https://github.com/felis/USB_Host_Shield_2.0/blob/master/XBOXUSB.cpp) library or to use it wirelessly use the [XBOXRECV](https://github.com/felis/USB_Host_Shield_2.0/blob/master/XBOXRECV.cpp) library.
|
||||
To use it via USB use the [XBOXUSB](XBOXUSB.cpp) library or to use it wirelessly use the [XBOXRECV](XBOXRECV.cpp) library.
|
||||
|
||||
__Note that a Wireless controller can NOT be used via USB!__
|
||||
|
||||
Examples code can be found in the [examples directory](https://github.com/felis/USB_Host_Shield_2.0/tree/master/examples/Xbox).
|
||||
Examples code can be found in the [examples directory](examples/Xbox).
|
||||
|
||||
Also see the following blog posts:
|
||||
|
||||
|
@ -132,23 +165,23 @@ All the information regarding the Xbox 360 controller protocol are form these si
|
|||
* <http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/WirelessUsbInfo>
|
||||
* <https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL>
|
||||
|
||||
### [Wii library](https://github.com/felis/USB_Host_Shield_2.0/blob/master/Wii.cpp)
|
||||
### [Wii library](Wii.cpp)
|
||||
|
||||
The [Wii](https://github.com/felis/USB_Host_Shield_2.0/blob/master/Wii.cpp) library support the Wiimote, but also the Nunchuch and Motion Plus extensions via Bluetooth. The Wii U Pro Controller is also supported via Bluetooth.
|
||||
The [Wii](Wii.cpp) library support the Wiimote, but also the Nunchuch and Motion Plus extensions via Bluetooth. The Wii U Pro Controller is also supported via Bluetooth.
|
||||
|
||||
First you have to pair with the controller, this is done automatically by the library if you create the instance like so:
|
||||
|
||||
<code>
|
||||
```
|
||||
WII Wii(&Btd,PAIR);
|
||||
</code>
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
<code>
|
||||
```
|
||||
WII Wii(&Btd);
|
||||
</code>
|
||||
```
|
||||
|
||||
Then just press any button any button on the Wiimote and it will connect to the dongle.
|
||||
|
||||
|
|
113
SPP.cpp
113
SPP.cpp
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
#include "SPP.h"
|
||||
#define DEBUG // Uncomment to print data for debugging
|
||||
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
|
||||
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
||||
//#define PRINTREPORT // Uncomment to print the report sent to the Arduino
|
||||
|
||||
|
@ -64,6 +64,7 @@ void SPP::Reset() {
|
|||
connected = false;
|
||||
RFCOMMConnected = false;
|
||||
SDPConnected = false;
|
||||
waitForLastCommand = false;
|
||||
l2cap_sdp_state = L2CAP_SDP_WAIT;
|
||||
l2cap_rfcomm_state = L2CAP_RFCOMM_WAIT;
|
||||
l2cap_event_flag = 0;
|
||||
|
@ -99,32 +100,32 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
if (((l2capinbuf[0] | (l2capinbuf[1] << 8)) == (hci_handle | 0x2000))) { // acl_handle_ok
|
||||
if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { //l2cap_control - Channel ID for ACL-U
|
||||
if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
||||
Notify(PSTR(" Data: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[17], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[16], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[15], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
#endif
|
||||
} else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
||||
Notify(PSTR(" SCID: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[15], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
Notify(PSTR(" Identifier: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[9], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
|
||||
#endif
|
||||
if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == SDP_PSM) { // It doesn't matter if it receives another reqeust, since it waits for the channel to disconnect in the L2CAP_SDP_DONE state, and the l2cap_event_flag will be cleared if so
|
||||
identifier = l2capinbuf[9];
|
||||
|
@ -178,7 +179,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
l2cap_event_flag |= L2CAP_FLAG_DISCONNECT_RESPONSE;
|
||||
}
|
||||
} else if (l2capinbuf[8] == L2CAP_CMD_INFORMATION_REQUEST) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nInformation request"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
|
@ -187,7 +188,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
#ifdef EXTRADEBUG
|
||||
else {
|
||||
Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[8], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
|
||||
}
|
||||
#endif
|
||||
} else if (l2capinbuf[6] == sdp_dcid[0] && l2capinbuf[7] == sdp_dcid[1]) { // SDP
|
||||
|
@ -217,18 +218,24 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
uuid = (l2capinbuf[18] << 8 | l2capinbuf[19]);
|
||||
else // Short UUID
|
||||
uuid = (l2capinbuf[16] << 8 | l2capinbuf[17]);
|
||||
PrintHex<uint16_t> (uuid, 0x80);
|
||||
D_PrintHex<uint16_t> (uuid, 0x80);
|
||||
|
||||
Notify(PSTR("\r\nLength: "), 0x80);
|
||||
uint16_t length = l2capinbuf[11] << 8 | l2capinbuf[12];
|
||||
PrintHex<uint16_t> (length, 0x80);
|
||||
D_PrintHex<uint16_t> (length, 0x80);
|
||||
Notify(PSTR("\r\nData: "), 0x80);
|
||||
for (uint8_t i = 0; i < length; i++) {
|
||||
PrintHex<uint8_t> (l2capinbuf[13+i], 0x80);
|
||||
D_PrintHex<uint8_t> (l2capinbuf[13+i], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
else {
|
||||
Notify(PSTR("\r\nUnknown PDU: "), 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
|
||||
}
|
||||
#endif
|
||||
} else if (l2capinbuf[6] == rfcomm_dcid[0] && l2capinbuf[7] == rfcomm_dcid[1]) { // RFCOMM
|
||||
rfcommChannel = l2capinbuf[8] & 0xF8;
|
||||
rfcommDirection = l2capinbuf[8] & 0x04;
|
||||
|
@ -241,20 +248,20 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nRFCOMM Channel: "), 0x80);
|
||||
PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
|
||||
D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
|
||||
Notify(PSTR(" Direction: "), 0x80);
|
||||
PrintHex<uint8_t > (rfcommDirection >> 2, 0x80);
|
||||
D_PrintHex<uint8_t > (rfcommDirection >> 2, 0x80);
|
||||
Notify(PSTR(" CommandResponse: "), 0x80);
|
||||
PrintHex<uint8_t > (rfcommCommandResponse >> 1, 0x80);
|
||||
D_PrintHex<uint8_t > (rfcommCommandResponse >> 1, 0x80);
|
||||
Notify(PSTR(" ChannelType: "), 0x80);
|
||||
PrintHex<uint8_t > (rfcommChannelType, 0x80);
|
||||
D_PrintHex<uint8_t > (rfcommChannelType, 0x80);
|
||||
Notify(PSTR(" PF_BIT: "), 0x80);
|
||||
PrintHex<uint8_t > (rfcommPfBit, 0x80);
|
||||
D_PrintHex<uint8_t > (rfcommPfBit, 0x80);
|
||||
#endif
|
||||
if (rfcommChannelType == RFCOMM_DISC) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nReceived Disconnect RFCOMM Command on channel: "), 0x80);
|
||||
PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
|
||||
D_PrintHex<uint8_t > (rfcommChannel >> 3, 0x80);
|
||||
#endif
|
||||
connected = false;
|
||||
sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
|
||||
|
@ -274,7 +281,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
Notify(rfcommAvailable, 0x80);
|
||||
if (offset) {
|
||||
Notify(PSTR(" - Credit: 0x"), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[11], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
|
||||
}
|
||||
#endif
|
||||
#ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send to the Arduino via Bluetooth
|
||||
|
@ -282,7 +289,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
Notifyc(l2capinbuf[i + 11 + offset], 0x80);
|
||||
#endif
|
||||
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
|
||||
#endif
|
||||
rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
|
||||
|
@ -297,7 +304,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
|
||||
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response
|
||||
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
|
||||
#endif
|
||||
rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
|
||||
|
@ -308,12 +315,12 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
}
|
||||
} else {
|
||||
if (rfcommChannelType == RFCOMM_SABM) { // SABM Command - this is sent twice: once for channel 0 and then for the channel to establish
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nReceived SABM Command"), 0x80);
|
||||
#endif
|
||||
sendRfcomm(rfcommChannel, rfcommDirection, rfcommCommandResponse, RFCOMM_UA, rfcommPfBit, rfcommbuf, 0x00); // UA Command
|
||||
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_PN_CMD) { // UIH Parameter Negotiation Command
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nReceived UIH Parameter Negotiation Command"), 0x80);
|
||||
#endif
|
||||
rfcommbuf[0] = BT_RFCOMM_PN_RSP; // UIH Parameter Negotiation Response
|
||||
|
@ -328,7 +335,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
rfcommbuf[9] = 0x00; // Number of Frames
|
||||
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A);
|
||||
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_CMD) { // UIH Modem Status Command
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSend UIH Modem Status Response"), 0x80);
|
||||
#endif
|
||||
rfcommbuf[0] = BT_RFCOMM_MSC_RSP; // UIH Modem Status Response
|
||||
|
@ -338,7 +345,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
|
||||
|
||||
delay(1);
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSend UIH Modem Status Command"), 0x80);
|
||||
#endif
|
||||
rfcommbuf[0] = BT_RFCOMM_MSC_CMD; // UIH Modem Status Command
|
||||
|
@ -349,7 +356,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x04);
|
||||
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_MSC_RSP) { // UIH Modem Status Response
|
||||
if (!creditSent) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSend UIH Command with credit"), 0x80);
|
||||
#endif
|
||||
sendRfcommCredit(rfcommChannelConnection, rfcommDirection, 0, RFCOMM_UIH, 0x10, sizeof (rfcommDataBuffer)); // Send credit
|
||||
|
@ -358,11 +365,11 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
waitForLastCommand = true;
|
||||
}
|
||||
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[10] == 0x01) { // UIH Command with credit
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nReceived UIH Command with credit"), 0x80);
|
||||
#endif
|
||||
} else if (rfcommChannelType == RFCOMM_UIH && l2capinbuf[11] == BT_RFCOMM_RPN_CMD) { // UIH Remote Port Negotiation Command
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nReceived UIH Remote Port Negotiation Command"), 0x80);
|
||||
#endif
|
||||
rfcommbuf[0] = BT_RFCOMM_RPN_RSP; // Command
|
||||
|
@ -376,7 +383,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
rfcommbuf[8] = l2capinbuf[19]; // MaxRatransm.
|
||||
rfcommbuf[9] = l2capinbuf[20]; // Number of Frames
|
||||
sendRfcomm(rfcommChannel, rfcommDirection, 0, RFCOMM_UIH, rfcommPfBit, rfcommbuf, 0x0A); // UIH Remote Port Negotiation Response
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nRFCOMM Connection is now established\r\n"), 0x80);
|
||||
#endif
|
||||
waitForLastCommand = false;
|
||||
|
@ -384,12 +391,12 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
connected = true; // The RFCOMM channel is now established
|
||||
sppIndex = 0;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
else if (rfcommChannelType != RFCOMM_DISC) {
|
||||
Notify(PSTR("\r\nUnsupported RFCOMM Data - ChannelType: "), 0x80);
|
||||
PrintHex<uint8_t > (rfcommChannelType, 0x80);
|
||||
D_PrintHex<uint8_t > (rfcommChannelType, 0x80);
|
||||
Notify(PSTR(" Command: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[11], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[11], 0x80);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -397,9 +404,9 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
#ifdef EXTRADEBUG
|
||||
else {
|
||||
Notify(PSTR("\r\nUnsupported L2CAP Data - Channel ID: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[7], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[7], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[6], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[6], 0x80);
|
||||
}
|
||||
#endif
|
||||
SDP_task();
|
||||
|
@ -409,7 +416,7 @@ void SPP::ACLData(uint8_t* l2capinbuf) {
|
|||
|
||||
void SPP::Run() {
|
||||
if (waitForLastCommand && (millis() - timer) > 100) { // We will only wait 100ms and see if the UIH Remote Port Negotiation Command is send, as some deviced don't send it
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nRFCOMM Connection is now established - Automatic\r\n"), 0x80);
|
||||
#endif
|
||||
creditSent = false;
|
||||
|
@ -425,7 +432,7 @@ void SPP::SDP_task() {
|
|||
case L2CAP_SDP_WAIT:
|
||||
if (l2cap_connection_request_sdp_flag) {
|
||||
l2cap_event_flag &= ~L2CAP_FLAG_CONNECTION_SDP_REQUEST; // Clear flag
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSDP Incoming Connection Request"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_connection_response(hci_handle, identifier, sdp_dcid, sdp_scid, PENDING);
|
||||
|
@ -440,7 +447,7 @@ void SPP::SDP_task() {
|
|||
case L2CAP_SDP_REQUEST:
|
||||
if (l2cap_config_request_sdp_flag) {
|
||||
l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_SDP_REQUEST; // Clear flag
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSDP Configuration Request"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_config_response(hci_handle, identifier, sdp_scid);
|
||||
|
@ -450,7 +457,7 @@ void SPP::SDP_task() {
|
|||
case L2CAP_SDP_SUCCESS:
|
||||
if (l2cap_config_success_sdp_flag) {
|
||||
l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_SDP_SUCCESS; // Clear flag
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSDP Successfully Configured"), 0x80);
|
||||
#endif
|
||||
firstMessage = true; // Reset bool
|
||||
|
@ -462,7 +469,7 @@ void SPP::SDP_task() {
|
|||
if (l2cap_disconnect_request_sdp_flag) {
|
||||
l2cap_event_flag &= ~L2CAP_FLAG_DISCONNECT_SDP_REQUEST; // Clear flag
|
||||
SDPConnected = false;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnected SDP Channel"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_disconnection_response(hci_handle, identifier, sdp_dcid, sdp_scid);
|
||||
|
@ -472,7 +479,7 @@ void SPP::SDP_task() {
|
|||
break;
|
||||
case L2CAP_DISCONNECT_RESPONSE: // This is for both disconnection response from the RFCOMM and SDP channel if they were connected
|
||||
if (l2cap_disconnect_response_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnected L2CAP Connection"), 0x80);
|
||||
#endif
|
||||
RFCOMMConnected = false;
|
||||
|
@ -492,7 +499,7 @@ void SPP::RFCOMM_task() {
|
|||
case L2CAP_RFCOMM_WAIT:
|
||||
if (l2cap_connection_request_rfcomm_flag) {
|
||||
l2cap_event_flag &= ~L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST; // Clear flag
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nRFCOMM Incoming Connection Request"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_connection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid, PENDING);
|
||||
|
@ -507,7 +514,7 @@ void SPP::RFCOMM_task() {
|
|||
case L2CAP_RFCOMM_REQUEST:
|
||||
if (l2cap_config_request_rfcomm_flag) {
|
||||
l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_RFCOMM_REQUEST; // Clear flag
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nRFCOMM Configuration Request"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_config_response(hci_handle, identifier, rfcomm_scid);
|
||||
|
@ -517,7 +524,7 @@ void SPP::RFCOMM_task() {
|
|||
case L2CAP_RFCOMM_SUCCESS:
|
||||
if (l2cap_config_success_rfcomm_flag) {
|
||||
l2cap_event_flag &= ~L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS; // Clear flag
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nRFCOMM Successfully Configured"), 0x80);
|
||||
#endif
|
||||
rfcommAvailable = 0; // Reset number of bytes available
|
||||
|
@ -531,7 +538,7 @@ void SPP::RFCOMM_task() {
|
|||
l2cap_event_flag &= ~L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST; // Clear flag
|
||||
RFCOMMConnected = false;
|
||||
connected = false;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnected RFCOMM Channel"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_disconnection_response(hci_handle, identifier, rfcomm_dcid, rfcomm_scid);
|
||||
|
@ -692,7 +699,7 @@ void SPP::sendRfcomm(uint8_t channel, uint8_t direction, uint8_t CR, uint8_t cha
|
|||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR(" - RFCOMM Data: "), 0x80);
|
||||
for (i = 0; i < length + 4; i++) {
|
||||
PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
}
|
||||
#endif
|
||||
|
@ -708,7 +715,7 @@ void SPP::sendRfcommCredit(uint8_t channel, uint8_t direction, uint8_t CR, uint8
|
|||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR(" - RFCOMM Credit Data: "), 0x80);
|
||||
for (uint8_t i = 0; i < 5; i++) {
|
||||
PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capoutbuf[i], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
}
|
||||
#endif
|
||||
|
|
274
Usb.cpp
274
Usb.cpp
|
@ -16,15 +16,6 @@ e-mail : support@circuitsathome.com
|
|||
*/
|
||||
/* USB functions */
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >=100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
#include "avrpins.h"
|
||||
#include "max3421e.h"
|
||||
#include "usbhost.h"
|
||||
#include "Usb.h"
|
||||
|
||||
static uint8_t usb_error = 0;
|
||||
|
@ -38,7 +29,7 @@ USB::USB() : bmHubPre(0) {
|
|||
|
||||
/* Initialize data structures */
|
||||
void USB::init() {
|
||||
devConfigIndex = 0;
|
||||
//devConfigIndex = 0;
|
||||
bmHubPre = 0;
|
||||
}
|
||||
|
||||
|
@ -113,6 +104,13 @@ uint8_t USB::SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_l
|
|||
|
||||
uint8_t mode = regRd(rMODE);
|
||||
|
||||
//Serial.print("\r\nMode: ");
|
||||
//Serial.println( mode, HEX);
|
||||
//Serial.print("\r\nLS: ");
|
||||
//Serial.println(p->lowspeed, HEX);
|
||||
|
||||
|
||||
|
||||
// Set bmLOWSPEED and bmHUBPRE in case of low-speed device, reset them otherwise
|
||||
regWr(rMODE, (p->lowspeed) ? mode | bmLOWSPEED | bmHubPre : mode & ~(bmHUBPRE | bmLOWSPEED));
|
||||
|
||||
|
@ -132,7 +130,7 @@ uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bReque
|
|||
SETUP_PKT setup_pkt;
|
||||
|
||||
EpInfo *pep = NULL;
|
||||
uint16_t nak_limit;
|
||||
uint16_t nak_limit = 0;
|
||||
|
||||
rcode = SetAddress(addr, ep, &pep, nak_limit);
|
||||
|
||||
|
@ -170,11 +168,16 @@ uint8_t USB::ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bReque
|
|||
//uint16_t read = (left<nbytes) ? left : nbytes;
|
||||
|
||||
rcode = InTransfer(pep, nak_limit, &read, dataptr);
|
||||
if (rcode == hrTOGERR) {
|
||||
// yes, we flip it wrong here so that next time it is actually correct!
|
||||
pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rcode)
|
||||
return rcode;
|
||||
|
||||
// Invoke callback function if inTransfer completed successfuly and callback function pointer is specified
|
||||
// Invoke callback function if inTransfer completed successfully and callback function pointer is specified
|
||||
if (!rcode && p)
|
||||
((USBReadParser*)p)->Parse(read, dataptr, total - left);
|
||||
|
||||
|
@ -227,21 +230,33 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui
|
|||
while (1) // use a 'return' to exit this loop
|
||||
{
|
||||
rcode = dispatchPkt(tokIN, pep->epAddr, nak_limit); //IN packet to EP-'endpoint'. Function takes care of NAKS.
|
||||
|
||||
if (rcode == hrTOGERR) {
|
||||
// yes, we flip it wrong here so that next time it is actually correct!
|
||||
pep->bmRcvToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
|
||||
regWr(rHCTL, (pep->bmRcvToggle) ? bmRCVTOG1 : bmRCVTOG0); //set toggle value
|
||||
continue;
|
||||
}
|
||||
if (rcode) {
|
||||
//printf("Problem! %i\r\n", rcode);
|
||||
//printf(">>>>>>>> Problem! dispatchPkt %2.2x\r\n", rcode);
|
||||
break; //should be 0, indicating ACK. Else return error code.
|
||||
}
|
||||
/* check for RCVDAVIRQ and generate error if not present */
|
||||
/* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */
|
||||
/* the only case when absence of RCVDAVIRQ makes sense is when toggle error occurred. Need to add handling for that */
|
||||
if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) {
|
||||
//printf("Problem! NO RCVDAVIRQ!\r\n");
|
||||
//printf(">>>>>>>> Problem! NO RCVDAVIRQ!\r\n");
|
||||
rcode = 0xf0; //receive error
|
||||
break;
|
||||
}
|
||||
pktsize = regRd(rRCVBC); //number of received bytes
|
||||
//printf("Got %i bytes ", pktsize);
|
||||
//printf("Got %i bytes \r\n", pktsize);
|
||||
// This would be OK, but...
|
||||
//assert(pktsize <= nbytes);
|
||||
if (pktsize > nbytes) {
|
||||
// This can happen. Use of assert on Arduino locks up the Arduino.
|
||||
// So I will trim the value, and hope for the best.
|
||||
//printf(">>>>>>>> Problem! Wanted %i bytes but got %i.\r\n", nbytes, pktsize);
|
||||
pktsize = nbytes;
|
||||
}
|
||||
|
||||
int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr);
|
||||
|
||||
|
@ -274,7 +289,7 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui
|
|||
/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */
|
||||
uint8_t USB::outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data) {
|
||||
EpInfo *pep = NULL;
|
||||
uint16_t nak_limit;
|
||||
uint16_t nak_limit = 0;
|
||||
|
||||
uint8_t rcode = SetAddress(addr, ep, &pep, nak_limit);
|
||||
|
||||
|
@ -315,15 +330,22 @@ uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8
|
|||
case hrNAK:
|
||||
nak_count++;
|
||||
if (nak_limit && (nak_count == nak_limit))
|
||||
return ( rcode);
|
||||
goto breakout;
|
||||
//return ( rcode);
|
||||
break;
|
||||
case hrTIMEOUT:
|
||||
retry_count++;
|
||||
if (retry_count == USB_RETRY_LIMIT)
|
||||
return ( rcode);
|
||||
goto breakout;
|
||||
//return ( rcode);
|
||||
break;
|
||||
case hrTOGERR:
|
||||
// yes, we flip it wrong here so that next time it is actually correct!
|
||||
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 0 : 1;
|
||||
regWr(rHCTL, (pep->bmSndToggle) ? bmSNDTOG1 : bmSNDTOG0); //set toggle value
|
||||
break;
|
||||
default:
|
||||
return ( rcode);
|
||||
goto breakout;
|
||||
}//switch( rcode
|
||||
|
||||
/* process NAK according to Host out NAK bug */
|
||||
|
@ -338,10 +360,12 @@ uint8_t USB::OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8
|
|||
bytes_left -= bytes_tosend;
|
||||
data_p += bytes_tosend;
|
||||
}//while( bytes_left...
|
||||
breakout:
|
||||
|
||||
pep->bmSndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? 1 : 0; //bmSNDTOG1 : bmSNDTOG0; //update toggle
|
||||
return ( rcode); //should be 0 in all cases
|
||||
}
|
||||
/* dispatch usb packet. Assumes peripheral address is set and relevant buffer is loaded/empty */
|
||||
/* dispatch USB packet. Assumes peripheral address is set and relevant buffer is loaded/empty */
|
||||
/* If NAK, tries to re-send up to nak_limit times */
|
||||
/* If nak_limit == 0, do not count NAKs, exit after timeout */
|
||||
/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
|
||||
|
@ -358,7 +382,7 @@ uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
|
|||
regWr(rHXFR, (token | ep)); //launch the transfer
|
||||
rcode = USB_ERROR_TRANSFER_TIMEOUT;
|
||||
|
||||
while (millis() < timeout) //wait for transfer completion
|
||||
while (timeout > millis()) //wait for transfer completion
|
||||
{
|
||||
tmpdata = regRd(rHIRQ);
|
||||
|
||||
|
@ -370,8 +394,8 @@ uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
|
|||
|
||||
}//while ( millis() < timeout
|
||||
|
||||
if (rcode != 0x00) //exit if timeout
|
||||
return ( rcode);
|
||||
//if (rcode != 0x00) //exit if timeout
|
||||
// return ( rcode);
|
||||
|
||||
rcode = (regRd(rHRSL) & 0x0f); //analyze transfer result
|
||||
|
||||
|
@ -379,15 +403,15 @@ uint8_t USB::dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit) {
|
|||
case hrNAK:
|
||||
nak_count++;
|
||||
if (nak_limit && (nak_count == nak_limit))
|
||||
return ( rcode);
|
||||
return (rcode);
|
||||
break;
|
||||
case hrTIMEOUT:
|
||||
retry_count++;
|
||||
if (retry_count == USB_RETRY_LIMIT)
|
||||
return ( rcode);
|
||||
return (rcode);
|
||||
break;
|
||||
default:
|
||||
return ( rcode);
|
||||
return (rcode);
|
||||
}//switch( rcode
|
||||
|
||||
}//while( timeout > millis()
|
||||
|
@ -419,7 +443,9 @@ void USB::Task(void) //USB state machine
|
|||
lowspeed = false;
|
||||
break;
|
||||
case LSHOST:
|
||||
|
||||
lowspeed = true;
|
||||
//intentional fallthrough
|
||||
case FSHOST: //attached
|
||||
if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) {
|
||||
delay = millis() + USB_SETTLE_DELAY;
|
||||
|
@ -459,17 +485,28 @@ void USB::Task(void) //USB state machine
|
|||
tmpdata = regRd(rMODE) | bmSOFKAENAB; //start SOF generation
|
||||
regWr(rMODE, tmpdata);
|
||||
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
|
||||
delay = millis() + 20; //20ms wait after reset per USB spec
|
||||
//delay = millis() + 20; //20ms wait after reset per USB spec
|
||||
}
|
||||
break;
|
||||
case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order
|
||||
if (regRd(rHIRQ) & bmFRAMEIRQ) //when first SOF received we can continue
|
||||
{
|
||||
if (regRd(rHIRQ) & bmFRAMEIRQ) {
|
||||
//when first SOF received _and_ 20ms has passed we can continue
|
||||
/*
|
||||
if (delay < millis()) //20ms passed
|
||||
usb_task_state = USB_STATE_CONFIGURING;
|
||||
*/
|
||||
usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET;
|
||||
delay = millis() + 20;
|
||||
}
|
||||
break;
|
||||
case USB_ATTACHED_SUBSTATE_WAIT_RESET:
|
||||
if (delay < millis()) usb_task_state = USB_STATE_CONFIGURING;
|
||||
break;
|
||||
case USB_STATE_CONFIGURING:
|
||||
|
||||
//Serial.print("\r\nConf.LS: ");
|
||||
//Serial.println(lowspeed, HEX);
|
||||
|
||||
rcode = Configuring(0, 0, lowspeed);
|
||||
|
||||
if (rcode) {
|
||||
|
@ -483,6 +520,7 @@ void USB::Task(void) //USB state machine
|
|||
case USB_STATE_RUNNING:
|
||||
break;
|
||||
case USB_STATE_ERROR:
|
||||
//MAX3421E::Init();
|
||||
break;
|
||||
} // switch( usb_task_state )
|
||||
}
|
||||
|
@ -527,33 +565,166 @@ uint8_t USB::DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
return 0;
|
||||
};
|
||||
|
||||
uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
//static uint8_t dev_index = 0;
|
||||
uint8_t USB::AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
uint8_t rcode = 0;
|
||||
//printf("AttemptConfig: parent = %i, port = %i\r\n", parent, port);
|
||||
|
||||
for (; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
|
||||
if (!devConfig[devConfigIndex])
|
||||
continue;
|
||||
|
||||
rcode = devConfig[devConfigIndex]->Init(parent, port, lowspeed);
|
||||
|
||||
if (!rcode) {
|
||||
devConfigIndex = 0;
|
||||
return 0;
|
||||
rcode = devConfig[driver]->ConfigureDevice(parent, port, lowspeed);
|
||||
if (rcode == USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET) {
|
||||
if (parent == 0) {
|
||||
// Send a bus reset on the root interface.
|
||||
regWr(rHCTL, bmBUSRST); //issue bus reset
|
||||
delay(102); // delay 102ms, compensate for clock inaccuracy.
|
||||
} else {
|
||||
// reset parent port
|
||||
devConfig[parent]->ResetHubPort(port);
|
||||
}
|
||||
}
|
||||
rcode = devConfig[driver]->Init(parent, port, lowspeed);
|
||||
if(rcode) {
|
||||
// Issue a bus reset, because the device may be in a limbo state
|
||||
if (parent == 0) {
|
||||
// Send a bus reset on the root interface.
|
||||
regWr(rHCTL, bmBUSRST); //issue bus reset
|
||||
delay(102); // delay 102ms, compensate for clock inaccuracy.
|
||||
} else {
|
||||
// reset parent port
|
||||
devConfig[parent]->ResetHubPort(port);
|
||||
}
|
||||
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is broken. We need to enumerate differently.
|
||||
* It causes major problems with several devices if detected in an unexpected order.
|
||||
*
|
||||
*
|
||||
* Oleg - I wouldn't do anything before the newly connected device is considered sane.
|
||||
* i.e.(delays are not indicated for brevity):
|
||||
* 1. reset
|
||||
* 2. GetDevDescr();
|
||||
* 3a. If ACK, continue with allocating address, addressing, etc.
|
||||
* 3b. Else reset again, count resets, stop at some number (5?).
|
||||
* 4. When max.number of resets is reached, toggle power/fail
|
||||
* If desired, this could be modified by performing two resets with GetDevDescr() in the middle - however, from my experience, if a device answers to GDD()
|
||||
* it doesn't need to be reset again
|
||||
* New steps proposal:
|
||||
* 1: get address pool instance. exit on fail
|
||||
* 2: pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf). exit on fail.
|
||||
* 3: bus reset, 100ms delay
|
||||
* 4: set address
|
||||
* 5: pUsb->setEpInfoEntry(bAddress, 1, epInfo), exit on fail
|
||||
* 6: while (configurations) {
|
||||
* for(each configuration) {
|
||||
* for (each driver) {
|
||||
* 6a: Ask device if it likes configuration. Returns 0 on OK.
|
||||
* If successful, the driver configured device.
|
||||
* The driver now owns the endpoints, and takes over managing them.
|
||||
* The following will need codes:
|
||||
* Everything went well, instance consumed, exit with success.
|
||||
* Instance already in use, ignore it, try next driver.
|
||||
* Not a supported device, ignore it, try next driver.
|
||||
* Not a supported configuration for this device, ignore it, try next driver.
|
||||
* Could not configure device, fatal, exit with fail.
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* 7: for(each driver) {
|
||||
* 7a: Ask device if it knows this VID/PID. Acts exactly like 6a, but using VID/PID
|
||||
* 8: if we get here, no driver likes the device plugged in, so exit failure.
|
||||
*
|
||||
*/
|
||||
uint8_t USB::Configuring(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
//uint8_t bAddress = 0;
|
||||
//printf("Configuring: parent = %i, port = %i\r\n", parent, port);
|
||||
uint8_t devConfigIndex;
|
||||
uint8_t rcode = 0;
|
||||
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
EpInfo epInfo;
|
||||
|
||||
epInfo.epAddr = 0;
|
||||
epInfo.maxPktSize = 8;
|
||||
epInfo.epAttribs = 0;
|
||||
epInfo.bmNakPower = USB_NAK_MAX_POWER;
|
||||
|
||||
delay(2000);
|
||||
AddressPool &addrPool = GetAddressPool();
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
if (!p) {
|
||||
//printf("Configuring error: USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL\r\n");
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to
|
||||
// avoid toggle inconsistence
|
||||
|
||||
p->epinfo = &epInfo;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
// Get device descriptor
|
||||
rcode = getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
|
||||
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
if (rcode) {
|
||||
//printf("Configuring error: Can't get USB_DEVICE_DESCRIPTOR\r\n");
|
||||
return rcode;
|
||||
}
|
||||
|
||||
// to-do?
|
||||
// Allocate new address according to device class
|
||||
//bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
||||
//if (!bAddress)
|
||||
// return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
|
||||
uint16_t vid = (uint16_t)((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
|
||||
uint16_t pid = (uint16_t)((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
|
||||
uint8_t klass = ((USB_DEVICE_DESCRIPTOR*)buf)->bDeviceClass;
|
||||
|
||||
// Attempt to configure if VID/PID or device class matches with a driver
|
||||
for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
|
||||
if (!devConfig[devConfigIndex]) continue; // no driver
|
||||
if (devConfig[devConfigIndex]->GetAddress()) continue; // consumed
|
||||
if (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass)) {
|
||||
rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
|
||||
if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (devConfigIndex < USB_NUMDEVICES) {
|
||||
return rcode;
|
||||
}
|
||||
|
||||
|
||||
// blindly attempt to configure
|
||||
for (devConfigIndex = 0; devConfigIndex < USB_NUMDEVICES; devConfigIndex++) {
|
||||
if (!devConfig[devConfigIndex]) continue;
|
||||
if (devConfig[devConfigIndex]->GetAddress()) continue; // consumed
|
||||
if (devConfig[devConfigIndex]->VIDPIDOK(vid, pid) || devConfig[devConfigIndex]->DEVCLASSOK(klass)) continue; // If this is true it means it must have returned USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED above
|
||||
rcode = AttemptConfig(devConfigIndex, parent, port, lowspeed);
|
||||
|
||||
//printf("ERROR ENUMERATING %2.2x\r\n", rcode);
|
||||
if (!(rcode == USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED || rcode == USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE)) {
|
||||
// in case of an error dev_index should be reset to 0
|
||||
// in order to start from the very beginning the
|
||||
// next time the program gets here
|
||||
if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
|
||||
devConfigIndex = 0;
|
||||
|
||||
//if (rcode != USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE)
|
||||
// devConfigIndex = 0;
|
||||
return rcode;
|
||||
}
|
||||
}
|
||||
// if we get here that means that the device class is not supported by any of registered classes
|
||||
devConfigIndex = 0;
|
||||
|
||||
rcode = DefaultAddressing(parent, port, lowspeed);
|
||||
|
||||
return rcode;
|
||||
|
@ -563,10 +734,11 @@ uint8_t USB::ReleaseDevice(uint8_t addr) {
|
|||
if (!addr)
|
||||
return 0;
|
||||
|
||||
for (uint8_t i = 0; i < USB_NUMDEVICES; i++)
|
||||
for (uint8_t i = 0; i < USB_NUMDEVICES; i++) {
|
||||
if(!devConfig[i]) continue;
|
||||
if (devConfig[i]->GetAddress() == addr)
|
||||
return devConfig[i]->Release();
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -582,11 +754,13 @@ uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t con
|
|||
return ( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, nbytes, dataptr, NULL));
|
||||
}
|
||||
|
||||
/* Requests Configuration Descriptor. Sends two Get Conf Descr requests. The first one gets the total length of all descriptors, then the second one requests this
|
||||
total length. The length of the first request can be shorter ( 4 bytes ), however, there are devices which won't work unless this length is set to 9 */
|
||||
uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p) {
|
||||
const uint8_t bufSize = 64;
|
||||
uint8_t buf[bufSize];
|
||||
|
||||
uint8_t ret = getConfDescr(addr, ep, 8, conf, buf);
|
||||
uint8_t ret = getConfDescr(addr, ep, 9, conf, buf);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
272
Usb.h
272
Usb.h
|
@ -18,265 +18,23 @@ e-mail : support@circuitsathome.com
|
|||
#ifndef _usb_h_
|
||||
#define _usb_h_
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >=100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
//#define BOARD_BLACK_WIDDOW
|
||||
|
||||
#define USB_METHODS_INLINE
|
||||
|
||||
// WARNING: Do not change the order of includes, or stuff will break!
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "avrpins.h"
|
||||
#include "max3421e.h"
|
||||
#include "usbhost.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "address.h"
|
||||
// None of these should ever be included by a driver, or a user's sketch.
|
||||
#include "settings.h"
|
||||
#include "printhex.h"
|
||||
#include "message.h"
|
||||
|
||||
/* shield pins. First parameter - SS pin, second parameter - INT pin */
|
||||
|
||||
#if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||
#define BOARD_TEENSY_PLUS_PLUS
|
||||
#endif
|
||||
|
||||
#ifdef BOARD_BLACK_WIDDOW
|
||||
typedef MAX3421e<P6, P3> MAX3421E; // Black Widow
|
||||
#elif defined(BOARD_TEENSY_PLUS_PLUS)
|
||||
typedef MAX3421e<P9, P8> MAX3421E; // Teensy++ 2.0 & 1.0
|
||||
#elif defined(BOARD_MEGA_ADK)
|
||||
typedef MAX3421e<P53, P54> MAX3421E; // Arduino Mega ADK
|
||||
#elif defined(BOARD_BALANDUINO)
|
||||
typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
|
||||
#else
|
||||
typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo etc.)
|
||||
#endif
|
||||
|
||||
//Debug macros. In 1.0 it is possible to move strings to PROGMEM by defining USBTRACE (Serial.print(F(s)))
|
||||
#define USBTRACE(s) (Notify(PSTR(s), 0x80))
|
||||
#define USBTRACE2(s,r) (Notify(PSTR(s), 0x80), PrintHex((r), 0x80), Notify(PSTR("\r\n"), 0x80))
|
||||
|
||||
|
||||
|
||||
/* Common setup data constant combinations */
|
||||
#define bmREQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type
|
||||
#define bmREQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface'
|
||||
#define bmREQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type
|
||||
|
||||
// D7 data transfer direction (0 - host-to-device, 1 - device-to-host)
|
||||
// D6-5 Type (0- standard, 1 - class, 2 - vendor, 3 - reserved)
|
||||
// D4-0 Recipient (0 - device, 1 - interface, 2 - endpoint, 3 - other, 4..31 - reserved)
|
||||
|
||||
// USB Device Classes
|
||||
#define USB_CLASS_USE_CLASS_INFO 0x00 // Use Class Info in the Interface Descriptors
|
||||
#define USB_CLASS_AUDIO 0x01 // Audio
|
||||
#define USB_CLASS_COM_AND_CDC_CTRL 0x02 // Communications and CDC Control
|
||||
#define USB_CLASS_HID 0x03 // HID
|
||||
#define USB_CLASS_PHYSICAL 0x05 // Physical
|
||||
#define USB_CLASS_IMAGE 0x06 // Image
|
||||
#define USB_CLASS_PRINTER 0x07 // Printer
|
||||
#define USB_CLASS_MASS_STORAGE 0x08 // Mass Storage
|
||||
#define USB_CLASS_HUB 0x09 // Hub
|
||||
#define USB_CLASS_CDC_DATA 0x0a // CDC-Data
|
||||
#define USB_CLASS_SMART_CARD 0x0b // Smart-Card
|
||||
#define USB_CLASS_CONTENT_SECURITY 0x0d // Content Security
|
||||
#define USB_CLASS_VIDEO 0x0e // Video
|
||||
#define USB_CLASS_PERSONAL_HEALTH 0x0f // Personal Healthcare
|
||||
#define USB_CLASS_DIAGNOSTIC_DEVICE 0xdc // Diagnostic Device
|
||||
#define USB_CLASS_WIRELESS_CTRL 0xe0 // Wireless Controller
|
||||
#define USB_CLASS_MISC 0xef // Miscellaneous
|
||||
#define USB_CLASS_APP_SPECIFIC 0xfe // Application Specific
|
||||
#define USB_CLASS_VENDOR_SPECIFIC 0xff // Vendor Specific
|
||||
|
||||
// Additional Error Codes
|
||||
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED 0xD1
|
||||
#define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE 0xD2
|
||||
#define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS 0xD3
|
||||
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL 0xD4
|
||||
#define USB_ERROR_HUB_ADDRESS_OVERFLOW 0xD5
|
||||
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL 0xD6
|
||||
#define USB_ERROR_EPINFO_IS_NULL 0xD7
|
||||
#define USB_ERROR_INVALID_ARGUMENT 0xD8
|
||||
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE 0xD9
|
||||
#define USB_ERROR_INVALID_MAX_PKT_SIZE 0xDA
|
||||
#define USB_ERROR_EP_NOT_FOUND_IN_TBL 0xDB
|
||||
#define USB_ERROR_TRANSFER_TIMEOUT 0xFF
|
||||
|
||||
class USBDeviceConfig {
|
||||
public:
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed) = 0;
|
||||
virtual uint8_t Release() = 0;
|
||||
virtual uint8_t Poll() = 0;
|
||||
virtual uint8_t GetAddress() = 0;
|
||||
};
|
||||
|
||||
#define USB_XFER_TIMEOUT 5000 //USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
|
||||
//#define USB_NAK_LIMIT 32000 //NAK limit for a transfer. 0 means NAKs are not counted
|
||||
#define USB_RETRY_LIMIT 3 //retry limit for a transfer
|
||||
#define USB_SETTLE_DELAY 200 //settle delay in milliseconds
|
||||
|
||||
#define USB_NUMDEVICES 16 //number of USB devices
|
||||
//#define HUB_MAX_HUBS 7 // maximum number of hubs that can be attached to the host controller
|
||||
#define HUB_PORT_RESET_DELAY 20 // hub port reset delay 10 ms recomended, can be up to 20 ms
|
||||
|
||||
/* USB state machine states */
|
||||
#define USB_STATE_MASK 0xf0
|
||||
|
||||
#define USB_STATE_DETACHED 0x10
|
||||
#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11
|
||||
#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12
|
||||
#define USB_DETACHED_SUBSTATE_ILLEGAL 0x13
|
||||
#define USB_ATTACHED_SUBSTATE_SETTLE 0x20
|
||||
#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30
|
||||
#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40
|
||||
#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50
|
||||
#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60
|
||||
#define USB_STATE_ADDRESSING 0x70
|
||||
#define USB_STATE_CONFIGURING 0x80
|
||||
#define USB_STATE_RUNNING 0x90
|
||||
#define USB_STATE_ERROR 0xa0
|
||||
|
||||
/* USB Setup Packet Structure */
|
||||
typedef struct {
|
||||
|
||||
union { // offset description
|
||||
uint8_t bmRequestType; // 0 Bit-map of request type
|
||||
|
||||
struct {
|
||||
uint8_t recipient : 5; // Recipient of the request
|
||||
uint8_t type : 2; // Type of request
|
||||
uint8_t direction : 1; // Direction of data X-fer
|
||||
} __attribute__((packed));
|
||||
} ReqType_u;
|
||||
uint8_t bRequest; // 1 Request
|
||||
|
||||
union {
|
||||
uint16_t wValue; // 2 Depends on bRequest
|
||||
|
||||
struct {
|
||||
uint8_t wValueLo;
|
||||
uint8_t wValueHi;
|
||||
} __attribute__((packed));
|
||||
} wVal_u;
|
||||
uint16_t wIndex; // 4 Depends on bRequest
|
||||
uint16_t wLength; // 6 Depends on bRequest
|
||||
} SETUP_PKT, *PSETUP_PKT __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
// Base class for incomming data parser
|
||||
|
||||
class USBReadParser {
|
||||
public:
|
||||
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0;
|
||||
};
|
||||
|
||||
class USB : public MAX3421E {
|
||||
AddressPoolImpl<USB_NUMDEVICES> addrPool;
|
||||
USBDeviceConfig* devConfig[USB_NUMDEVICES];
|
||||
uint8_t devConfigIndex;
|
||||
uint8_t bmHubPre;
|
||||
|
||||
public:
|
||||
USB(void);
|
||||
|
||||
void SetHubPreMask() {
|
||||
bmHubPre |= bmHUBPRE;
|
||||
};
|
||||
|
||||
void ResetHubPreMask() {
|
||||
bmHubPre &= (~bmHUBPRE);
|
||||
};
|
||||
|
||||
AddressPool& GetAddressPool() {
|
||||
return(AddressPool&) addrPool;
|
||||
};
|
||||
|
||||
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) {
|
||||
for(uint8_t i = 0; i < USB_NUMDEVICES; i++) {
|
||||
if(!devConfig[i]) {
|
||||
devConfig[i] = pdev;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS;
|
||||
};
|
||||
|
||||
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
|
||||
addrPool.ForEachUsbDevice(pfunc);
|
||||
};
|
||||
uint8_t getUsbTaskState(void);
|
||||
void setUsbTaskState(uint8_t state);
|
||||
|
||||
EpInfo* getEpInfoEntry(uint8_t addr, uint8_t ep);
|
||||
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr);
|
||||
|
||||
//uint8_t ctrlReq( uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t nbytes, uint8_t* dataptr);
|
||||
|
||||
/* Control requests */
|
||||
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr);
|
||||
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr);
|
||||
|
||||
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p);
|
||||
|
||||
uint8_t getStrDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr);
|
||||
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr);
|
||||
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value);
|
||||
/**/
|
||||
uint8_t ctrlData(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, boolean direction);
|
||||
uint8_t ctrlStatus(uint8_t ep, boolean direction, uint16_t nak_limit);
|
||||
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data);
|
||||
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data);
|
||||
uint8_t dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit);
|
||||
|
||||
void Task(void);
|
||||
|
||||
uint8_t DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
uint8_t Configuring(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
uint8_t ReleaseDevice(uint8_t addr);
|
||||
|
||||
uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
|
||||
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p);
|
||||
|
||||
private:
|
||||
void init();
|
||||
uint8_t SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit);
|
||||
uint8_t OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data);
|
||||
uint8_t InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data);
|
||||
};
|
||||
|
||||
#if 0 //defined(USB_METHODS_INLINE)
|
||||
//get device descriptor
|
||||
|
||||
inline uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) {
|
||||
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr));
|
||||
}
|
||||
//get configuration descriptor
|
||||
|
||||
inline uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
|
||||
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr));
|
||||
}
|
||||
//get string descriptor
|
||||
|
||||
inline uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t nuint8_ts, uint8_t index, uint16_t langid, uint8_t* dataptr) {
|
||||
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nuint8_ts, dataptr));
|
||||
}
|
||||
//set address
|
||||
|
||||
inline uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
|
||||
return( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL));
|
||||
}
|
||||
//set configuration
|
||||
|
||||
inline uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
|
||||
return( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL));
|
||||
}
|
||||
|
||||
#endif // defined(USB_METHODS_INLINE)
|
||||
#include "hexdump.h"
|
||||
#include "max3421e.h"
|
||||
#include "address.h"
|
||||
#include "avrpins.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "usbhost.h"
|
||||
#include "UsbCore.h"
|
||||
#include "parsetools.h"
|
||||
#include "confdescparser.h"
|
||||
|
||||
#endif //_usb_h_
|
||||
|
|
254
UsbCore.h
Normal file
254
UsbCore.h
Normal file
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* File: UsbCore.h
|
||||
* Author: xxxajk
|
||||
*
|
||||
* Created on September 29, 2013, 9:25 PM
|
||||
*/
|
||||
|
||||
#if !defined(_usb_h_) || defined(USBCORE_H)
|
||||
#error "Never include UsbCore.h directly; include Usb.h instead"
|
||||
#else
|
||||
#define USBCORE_H
|
||||
|
||||
// Not used anymore? If anyone uses this, please let us know so that this may be
|
||||
// moved to the proper place, settings.h.
|
||||
//#define USB_METHODS_INLINE
|
||||
|
||||
/* shield pins. First parameter - SS pin, second parameter - INT pin */
|
||||
#ifdef BOARD_BLACK_WIDDOW
|
||||
typedef MAX3421e<P6, P3> MAX3421E; // Black Widow
|
||||
#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
|
||||
typedef MAX3421e<P9, P8> MAX3421E; // Teensy++ 2.0 & 1.0
|
||||
#elif defined(BOARD_MEGA_ADK)
|
||||
typedef MAX3421e<P53, P54> MAX3421E; // Arduino Mega ADK
|
||||
#elif defined(ARDUINO_AVR_BALANDUINO)
|
||||
typedef MAX3421e<P20, P19> MAX3421E; // Balanduino
|
||||
#else
|
||||
typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo etc.)
|
||||
#endif
|
||||
|
||||
/* Common setup data constant combinations */
|
||||
#define bmREQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type
|
||||
#define bmREQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface'
|
||||
#define bmREQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type
|
||||
|
||||
// D7 data transfer direction (0 - host-to-device, 1 - device-to-host)
|
||||
// D6-5 Type (0- standard, 1 - class, 2 - vendor, 3 - reserved)
|
||||
// D4-0 Recipient (0 - device, 1 - interface, 2 - endpoint, 3 - other, 4..31 - reserved)
|
||||
|
||||
// USB Device Classes
|
||||
#define USB_CLASS_USE_CLASS_INFO 0x00 // Use Class Info in the Interface Descriptors
|
||||
#define USB_CLASS_AUDIO 0x01 // Audio
|
||||
#define USB_CLASS_COM_AND_CDC_CTRL 0x02 // Communications and CDC Control
|
||||
#define USB_CLASS_HID 0x03 // HID
|
||||
#define USB_CLASS_PHYSICAL 0x05 // Physical
|
||||
#define USB_CLASS_IMAGE 0x06 // Image
|
||||
#define USB_CLASS_PRINTER 0x07 // Printer
|
||||
#define USB_CLASS_MASS_STORAGE 0x08 // Mass Storage
|
||||
#define USB_CLASS_HUB 0x09 // Hub
|
||||
#define USB_CLASS_CDC_DATA 0x0a // CDC-Data
|
||||
#define USB_CLASS_SMART_CARD 0x0b // Smart-Card
|
||||
#define USB_CLASS_CONTENT_SECURITY 0x0d // Content Security
|
||||
#define USB_CLASS_VIDEO 0x0e // Video
|
||||
#define USB_CLASS_PERSONAL_HEALTH 0x0f // Personal Healthcare
|
||||
#define USB_CLASS_DIAGNOSTIC_DEVICE 0xdc // Diagnostic Device
|
||||
#define USB_CLASS_WIRELESS_CTRL 0xe0 // Wireless Controller
|
||||
#define USB_CLASS_MISC 0xef // Miscellaneous
|
||||
#define USB_CLASS_APP_SPECIFIC 0xfe // Application Specific
|
||||
#define USB_CLASS_VENDOR_SPECIFIC 0xff // Vendor Specific
|
||||
|
||||
// Additional Error Codes
|
||||
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED 0xD1
|
||||
#define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE 0xD2
|
||||
#define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS 0xD3
|
||||
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL 0xD4
|
||||
#define USB_ERROR_HUB_ADDRESS_OVERFLOW 0xD5
|
||||
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL 0xD6
|
||||
#define USB_ERROR_EPINFO_IS_NULL 0xD7
|
||||
#define USB_ERROR_INVALID_ARGUMENT 0xD8
|
||||
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE 0xD9
|
||||
#define USB_ERROR_INVALID_MAX_PKT_SIZE 0xDA
|
||||
#define USB_ERROR_EP_NOT_FOUND_IN_TBL 0xDB
|
||||
#define USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET 0xE0
|
||||
#define USB_ERROR_FailGetDevDescr 0xE1
|
||||
#define USB_ERROR_FailSetDevTblEntry 0xE2
|
||||
#define USB_ERROR_FailGetConfDescr 0xE3
|
||||
#define USB_ERROR_TRANSFER_TIMEOUT 0xFF
|
||||
|
||||
#define USB_XFER_TIMEOUT 10000 //30000 // (5000) USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
|
||||
//#define USB_NAK_LIMIT 32000 //NAK limit for a transfer. 0 means NAKs are not counted
|
||||
#define USB_RETRY_LIMIT 3 // 3 retry limit for a transfer
|
||||
#define USB_SETTLE_DELAY 200 //settle delay in milliseconds
|
||||
|
||||
#define USB_NUMDEVICES 16 //number of USB devices
|
||||
//#define HUB_MAX_HUBS 7 // maximum number of hubs that can be attached to the host controller
|
||||
#define HUB_PORT_RESET_DELAY 20 // hub port reset delay 10 ms recomended, can be up to 20 ms
|
||||
|
||||
/* USB state machine states */
|
||||
#define USB_STATE_MASK 0xf0
|
||||
|
||||
#define USB_STATE_DETACHED 0x10
|
||||
#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11
|
||||
#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12
|
||||
#define USB_DETACHED_SUBSTATE_ILLEGAL 0x13
|
||||
#define USB_ATTACHED_SUBSTATE_SETTLE 0x20
|
||||
#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30
|
||||
#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40
|
||||
#define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50
|
||||
#define USB_ATTACHED_SUBSTATE_WAIT_RESET 0x51
|
||||
#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60
|
||||
#define USB_STATE_ADDRESSING 0x70
|
||||
#define USB_STATE_CONFIGURING 0x80
|
||||
#define USB_STATE_RUNNING 0x90
|
||||
#define USB_STATE_ERROR 0xa0
|
||||
|
||||
class USBDeviceConfig {
|
||||
public:
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed) { return 0; }
|
||||
virtual uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {return 0; }
|
||||
virtual uint8_t Release() { return 0; }
|
||||
virtual uint8_t Poll() { return 0; }
|
||||
virtual uint8_t GetAddress() { return 0; }
|
||||
virtual void ResetHubPort(uint8_t port) { return; } // Note used for hubs only!
|
||||
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) { return false; }
|
||||
virtual boolean DEVCLASSOK(uint8_t klass) { return false; }
|
||||
};
|
||||
|
||||
/* USB Setup Packet Structure */
|
||||
typedef struct {
|
||||
|
||||
union { // offset description
|
||||
uint8_t bmRequestType; // 0 Bit-map of request type
|
||||
|
||||
struct {
|
||||
uint8_t recipient : 5; // Recipient of the request
|
||||
uint8_t type : 2; // Type of request
|
||||
uint8_t direction : 1; // Direction of data X-fer
|
||||
} __attribute__((packed));
|
||||
} ReqType_u;
|
||||
uint8_t bRequest; // 1 Request
|
||||
|
||||
union {
|
||||
uint16_t wValue; // 2 Depends on bRequest
|
||||
|
||||
struct {
|
||||
uint8_t wValueLo;
|
||||
uint8_t wValueHi;
|
||||
} __attribute__((packed));
|
||||
} wVal_u;
|
||||
uint16_t wIndex; // 4 Depends on bRequest
|
||||
uint16_t wLength; // 6 Depends on bRequest
|
||||
} SETUP_PKT, *PSETUP_PKT __attribute__((packed));
|
||||
|
||||
|
||||
|
||||
// Base class for incoming data parser
|
||||
|
||||
class USBReadParser {
|
||||
public:
|
||||
virtual void Parse(const uint16_t len, const uint8_t *pbuf, const uint16_t &offset) = 0;
|
||||
};
|
||||
|
||||
class USB : public MAX3421E {
|
||||
AddressPoolImpl<USB_NUMDEVICES> addrPool;
|
||||
USBDeviceConfig* devConfig[USB_NUMDEVICES];
|
||||
uint8_t bmHubPre;
|
||||
|
||||
public:
|
||||
USB(void);
|
||||
|
||||
void SetHubPreMask() {
|
||||
bmHubPre |= bmHUBPRE;
|
||||
};
|
||||
|
||||
void ResetHubPreMask() {
|
||||
bmHubPre &= (~bmHUBPRE);
|
||||
};
|
||||
|
||||
AddressPool& GetAddressPool() {
|
||||
return(AddressPool&) addrPool;
|
||||
};
|
||||
|
||||
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev) {
|
||||
for(uint8_t i = 0; i < USB_NUMDEVICES; i++) {
|
||||
if(!devConfig[i]) {
|
||||
devConfig[i] = pdev;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS;
|
||||
};
|
||||
|
||||
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
|
||||
addrPool.ForEachUsbDevice(pfunc);
|
||||
};
|
||||
uint8_t getUsbTaskState(void);
|
||||
void setUsbTaskState(uint8_t state);
|
||||
|
||||
EpInfo* getEpInfoEntry(uint8_t addr, uint8_t ep);
|
||||
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo* eprecord_ptr);
|
||||
|
||||
/* Control requests */
|
||||
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr);
|
||||
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr);
|
||||
|
||||
uint8_t getConfDescr(uint8_t addr, uint8_t ep, uint8_t conf, USBReadParser *p);
|
||||
|
||||
uint8_t getStrDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr);
|
||||
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr);
|
||||
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value);
|
||||
/**/
|
||||
uint8_t ctrlData(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr, boolean direction);
|
||||
uint8_t ctrlStatus(uint8_t ep, boolean direction, uint16_t nak_limit);
|
||||
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t* data);
|
||||
uint8_t outTransfer(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* data);
|
||||
uint8_t dispatchPkt(uint8_t token, uint8_t ep, uint16_t nak_limit);
|
||||
|
||||
void Task(void);
|
||||
|
||||
uint8_t DefaultAddressing(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
uint8_t Configuring(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
uint8_t ReleaseDevice(uint8_t addr);
|
||||
|
||||
uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi,
|
||||
uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t* dataptr, USBReadParser *p);
|
||||
|
||||
private:
|
||||
void init();
|
||||
uint8_t SetAddress(uint8_t addr, uint8_t ep, EpInfo **ppep, uint16_t &nak_limit);
|
||||
uint8_t OutTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t nbytes, uint8_t *data);
|
||||
uint8_t InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, uint8_t *data);
|
||||
uint8_t AttemptConfig(uint8_t driver, uint8_t parent, uint8_t port, bool lowspeed);
|
||||
};
|
||||
|
||||
#if 0 //defined(USB_METHODS_INLINE)
|
||||
//get device descriptor
|
||||
|
||||
inline uint8_t USB::getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t* dataptr) {
|
||||
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr));
|
||||
}
|
||||
//get configuration descriptor
|
||||
|
||||
inline uint8_t USB::getConfDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t conf, uint8_t* dataptr) {
|
||||
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr));
|
||||
}
|
||||
//get string descriptor
|
||||
|
||||
inline uint8_t USB::getStrDescr(uint8_t addr, uint8_t ep, uint16_t nuint8_ts, uint8_t index, uint16_t langid, uint8_t* dataptr) {
|
||||
return( ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nuint8_ts, dataptr));
|
||||
}
|
||||
//set address
|
||||
|
||||
inline uint8_t USB::setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr) {
|
||||
return( ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL));
|
||||
}
|
||||
//set configuration
|
||||
|
||||
inline uint8_t USB::setConf(uint8_t addr, uint8_t ep, uint8_t conf_value) {
|
||||
return( ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL));
|
||||
}
|
||||
|
||||
#endif // defined(USB_METHODS_INLINE)
|
||||
|
||||
#endif /* USBCORE_H */
|
||||
|
215
Wii.cpp
215
Wii.cpp
|
@ -14,13 +14,11 @@
|
|||
Web : http://www.tkjelectronics.com
|
||||
e-mail : kristianl@tkjelectronics.com
|
||||
|
||||
IR camera support added by:
|
||||
Allan Glover
|
||||
adglover9.81@gmail.com
|
||||
IR camera support added by Allan Glover (adglover9.81@gmail.com) and Kristian Lauszus
|
||||
*/
|
||||
|
||||
#include "Wii.h"
|
||||
#define DEBUG // Uncomment to print data for debugging
|
||||
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
|
||||
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
||||
//#define PRINTREPORT // Uncomment to print the report send by the Wii controllers
|
||||
|
||||
|
@ -109,7 +107,7 @@ void WII::Reset() {
|
|||
activateNunchuck = false;
|
||||
motionValuesReset = false;
|
||||
activeConnection = false;
|
||||
pBtd->motionPlusInside = false;
|
||||
motionPlusInside = false;
|
||||
pBtd->wiiUProController = false;
|
||||
wiiUProControllerConnected = false;
|
||||
l2cap_event_flag = 0; // Reset flags
|
||||
|
@ -117,13 +115,17 @@ void WII::Reset() {
|
|||
}
|
||||
|
||||
void WII::disconnect() { // Use this void to disconnect any of the controllers
|
||||
if (motionPlusConnected && !pBtd->motionPlusInside) { // Disable the Motion Plus extension
|
||||
#ifdef DEBUG
|
||||
if (!motionPlusInside) { // The old Wiimote needs a delay after the first command or it will automatically reconnect
|
||||
if (motionPlusConnected) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDeactivating Motion Plus"), 0x80);
|
||||
#endif
|
||||
initExtension1(); // This will disable the Motion Plus extension
|
||||
}
|
||||
//First the HID interrupt channel has to be disconencted, then the HID control channel and finally the HCI connection
|
||||
timer = millis() + 1000; // We have to wait for the message before the rest of the channels can be deactivated
|
||||
} else
|
||||
timer = millis(); // Don't wait
|
||||
// First the HID interrupt channel has to be disconnected, then the HID control channel and finally the HCI connection
|
||||
pBtd->l2cap_disconnection_request(hci_handle, 0x0A, interrupt_scid, interrupt_dcid);
|
||||
Reset();
|
||||
l2cap_state = L2CAP_INTERRUPT_DISCONNECT;
|
||||
|
@ -133,6 +135,7 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
|||
if (!pBtd->l2capConnectionClaimed && pBtd->incomingWii && !wiimoteConnected && !activeConnection) {
|
||||
if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
|
||||
if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
|
||||
motionPlusInside = pBtd->motionPlusInside;
|
||||
pBtd->incomingWii = false;
|
||||
pBtd->l2capConnectionClaimed = true; // Claim that the incoming connection belongs to this service
|
||||
activeConnection = true;
|
||||
|
@ -144,19 +147,19 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
|||
if ((l2capinbuf[0] | (l2capinbuf[1] << 8)) == (hci_handle | 0x2000)) { // acl_handle_ok or it's a new connection
|
||||
if ((l2capinbuf[6] | (l2capinbuf[7] << 8)) == 0x0001) { //l2cap_control - Channel ID for ACL-U
|
||||
if (l2capinbuf[8] == L2CAP_CMD_COMMAND_REJECT) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nL2CAP Command Rejected - Reason: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[17], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[17], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[16], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[16], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[15], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
#endif
|
||||
} else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_RESPONSE) {
|
||||
if (((l2capinbuf[16] | (l2capinbuf[17] << 8)) == 0x0000) && ((l2capinbuf[18] | (l2capinbuf[19] << 8)) == SUCCESSFUL)) { // Success
|
||||
|
@ -177,15 +180,15 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
|||
} else if (l2capinbuf[8] == L2CAP_CMD_CONNECTION_REQUEST) {
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nL2CAP Connection Request - PSM: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
||||
Notify(PSTR(" SCID: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[15], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[15], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
Notify(PSTR(" Identifier: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[9], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
|
||||
#endif
|
||||
if ((l2capinbuf[12] | (l2capinbuf[13] << 8)) == HID_CTRL_PSM) {
|
||||
identifier = l2capinbuf[9];
|
||||
|
@ -220,14 +223,14 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
|||
}
|
||||
} else if (l2capinbuf[8] == L2CAP_CMD_DISCONNECT_REQUEST) {
|
||||
if (l2capinbuf[12] == control_dcid[0] && l2capinbuf[13] == control_dcid[1]) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnect Request: Control Channel"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
pBtd->l2cap_disconnection_response(hci_handle, identifier, control_dcid, control_scid);
|
||||
Reset();
|
||||
} else if (l2capinbuf[12] == interrupt_dcid[0] && l2capinbuf[13] == interrupt_dcid[1]) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnect Request: Interrupt Channel"), 0x80);
|
||||
#endif
|
||||
identifier = l2capinbuf[9];
|
||||
|
@ -249,12 +252,11 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
|||
else {
|
||||
identifier = l2capinbuf[9];
|
||||
Notify(PSTR("\r\nL2CAP Unknown Signaling Command: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[8], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
|
||||
}
|
||||
#endif
|
||||
} else if (l2capinbuf[6] == interrupt_dcid[0] && l2capinbuf[7] == interrupt_dcid[1]) { // l2cap_interrupt
|
||||
//Notify(PSTR("\r\nL2CAP Interrupt"), 0x80);
|
||||
if (wiimoteConnected) {
|
||||
if (l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT
|
||||
if ((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || (l2capinbuf[9] >= 0x30 && l2capinbuf[9] <= 0x37) || l2capinbuf[9] == 0x3e || l2capinbuf[9] == 0x3f) { // These reports include the buttons
|
||||
if ((l2capinbuf[9] >= 0x20 && l2capinbuf[9] <= 0x22) || l2capinbuf[9] == 0x31 || l2capinbuf[9] == 0x33) // These reports have no extensions bytes
|
||||
|
@ -274,7 +276,7 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
|||
ButtonState = (uint32_t)((l2capinbuf[10] & 0x1F) | ((uint16_t)(l2capinbuf[11] & 0x9F) << 8));
|
||||
#ifdef PRINTREPORT
|
||||
Notify(PSTR("ButtonState: "), 0x80);
|
||||
PrintHex<uint32_t > (ButtonState, 0x80);
|
||||
D_PrintHex<uint32_t > (ButtonState, 0x80);
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
#endif
|
||||
if (ButtonState != OldButtonState) {
|
||||
|
@ -291,15 +293,18 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
|||
}
|
||||
switch (l2capinbuf[9]) {
|
||||
case 0x20: // Status Information - (a1) 20 BB BB LF 00 00 VV
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nStatus report was received"), 0x80);
|
||||
#endif
|
||||
wiiState = l2capinbuf[12]; // (0x01: Battery is nearly empty), (0x02: An Extension Controller is connected), (0x04: Speaker enabled), (0x08: IR enabled), (0x10: LED1, 0x20: LED2, 0x40: LED3, 0x80: LED4)
|
||||
batteryLevel = l2capinbuf[15]; // Update battery level
|
||||
if (l2capinbuf[12] & 0x01) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
if (l2capinbuf[12] & 0x01)
|
||||
Notify(PSTR("\r\nWARNING: Battery is nearly empty"), 0x80);
|
||||
#endif
|
||||
}
|
||||
if (checkExtension) { // If this is false it means that the user must have called getBatteryLevel()
|
||||
if (l2capinbuf[12] & 0x02) { // Check if a extension is connected
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
if (!unknownExtensionConnected)
|
||||
Notify(PSTR("\r\nExtension connected"), 0x80);
|
||||
#endif
|
||||
|
@ -309,11 +314,11 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
|||
#endif
|
||||
setReportMode(false, 0x35); // Also read the extension
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nExtension disconnected"), 0x80);
|
||||
#endif
|
||||
if (motionPlusConnected) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR(" - from Motion Plus"), 0x80);
|
||||
#endif
|
||||
l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED;
|
||||
|
@ -321,63 +326,72 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
|||
nunchuckConnected = false;
|
||||
//else if(classicControllerConnected)
|
||||
} else if (nunchuckConnected) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR(" - Nunchuck"), 0x80);
|
||||
#endif
|
||||
nunchuckConnected = false; // It must be the Nunchuck controller then
|
||||
l2cap_event_flag &= ~WII_FLAG_NUNCHUCK_CONNECTED;
|
||||
setLedStatus();
|
||||
setReportMode(false, 0x31); // If there is no extension connected we will read the button and accelerometer
|
||||
} else {
|
||||
setReportMode(false, 0x31); // If there is no extension connected we will read the button and accelerometer
|
||||
}
|
||||
onInit();
|
||||
setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer
|
||||
} else
|
||||
setReportMode(false, 0x31); // If there is no extension connected we will read the buttons and accelerometer
|
||||
}
|
||||
} else
|
||||
checkExtension = true; // Check for extensions by default
|
||||
break;
|
||||
case 0x21: // Read Memory Data
|
||||
if ((l2capinbuf[12] & 0x0F) == 0) { // No error
|
||||
// See: http://wiibrew.org/wiki/Wiimote/Extension_Controllers
|
||||
if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x00) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nNunchuck connected"), 0x80);
|
||||
#endif
|
||||
l2cap_event_flag |= WII_FLAG_NUNCHUCK_CONNECTED;
|
||||
} else if (l2capinbuf[16] == 0x00 && (l2capinbuf[17] == 0xA6 || l2capinbuf[17] == 0xA4) && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x00 && l2capinbuf[20] == 0x05) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nMotion Plus connected"), 0x80);
|
||||
#endif
|
||||
l2cap_event_flag |= WII_FLAG_MOTION_PLUS_CONNECTED;
|
||||
} else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x04 && l2capinbuf[20] == 0x05) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nMotion Plus activated in normal mode"), 0x80);
|
||||
#endif
|
||||
motionPlusConnected = true;
|
||||
#ifdef WIICAMERA
|
||||
if (!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera
|
||||
#endif
|
||||
setReportMode(false, 0x35); // Also read the extension
|
||||
} else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x05 && l2capinbuf[20] == 0x05) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nMotion Plus activated in Nunchuck pass-through mode"), 0x80);
|
||||
#endif
|
||||
activateNunchuck = false;
|
||||
motionPlusConnected = true;
|
||||
nunchuckConnected = true;
|
||||
#ifdef WIICAMERA
|
||||
if (!isIRCameraEnabled()) // Don't activate the Motion Plus if we are trying to initialize the IR camera
|
||||
#endif
|
||||
setReportMode(false, 0x35); // Also read the extension
|
||||
} else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA6 && l2capinbuf[18] == 0x20 && (l2capinbuf[19] == 0x00 || l2capinbuf[19] == 0x04 || l2capinbuf[19] == 0x05 || l2capinbuf[19] == 0x07) && l2capinbuf[20] == 0x05) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nInactive Wii Motion Plus"), 0x80);
|
||||
Notify(PSTR("\r\nPlease unplug the Motion Plus, disconnect the Wiimote and then replug the Motion Plus Extension"), 0x80);
|
||||
#endif
|
||||
stateCounter = 300; // Skip the rest in "L2CAP_CHECK_MOTION_PLUS_STATE"
|
||||
} else if (l2capinbuf[16] == 0x00 && l2capinbuf[17] == 0xA4 && l2capinbuf[18] == 0x20 && l2capinbuf[19] == 0x01 && l2capinbuf[20] == 0x20) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nWii U Pro Controller connected"), 0x80);
|
||||
#endif
|
||||
wiiUProControllerConnected = true;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
else {
|
||||
Notify(PSTR("\r\nUnknown Device: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
Notify(PSTR("\r\nData: "), 0x80);
|
||||
for (uint8_t i = 0; i < ((l2capinbuf[12] >> 4) + 1); i++) { // bit 4-7 is the length-1
|
||||
PrintHex<uint8_t > (l2capinbuf[15 + i], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[15 + i], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
}
|
||||
}
|
||||
|
@ -386,16 +400,16 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
|||
#ifdef EXTRADEBUG
|
||||
else {
|
||||
Notify(PSTR("\r\nReport Error: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[13], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[14], 0x80);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 0x22: // Acknowledge output report, return function result
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
if (l2capinbuf[13] != 0x00) { // Check if there is an error
|
||||
Notify(PSTR("\r\nCommand failed: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[12], 0x80);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
@ -496,7 +510,7 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
|||
*/
|
||||
} else {
|
||||
if ((micros() - timer) > 1000000) { // Loop for 1 sec before resetting the values
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nThe gyro values has been reset"), 0x80);
|
||||
#endif
|
||||
gyroYawZero = (l2capinbuf[15] | ((l2capinbuf[18] & 0xFC) << 6));
|
||||
|
@ -531,7 +545,7 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
|||
if (!extensionConnected) {
|
||||
extensionConnected = true;
|
||||
unknownExtensionConnected = true;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nExtension connected to Motion Plus"), 0x80);
|
||||
#endif
|
||||
}
|
||||
|
@ -539,7 +553,7 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
|||
if (extensionConnected && !unknownExtensionConnected) {
|
||||
extensionConnected = false;
|
||||
unknownExtensionConnected = true;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nExtension disconnected from Motion Plus"), 0x80);
|
||||
#endif
|
||||
nunchuckConnected = false; // There is no extension connected to the Motion Plus if this report is sent
|
||||
|
@ -564,16 +578,15 @@ void WII::ACLData(uint8_t* l2capinbuf) {
|
|||
hatValues[RightHatY] = (l2capinbuf[21] | l2capinbuf[22] << 8);
|
||||
}
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
default:
|
||||
Notify(PSTR("\r\nUnknown Report type: "), 0x80);
|
||||
PrintHex<uint8_t > (l2capinbuf[9], 0x80);
|
||||
D_PrintHex<uint8_t > (l2capinbuf[9], 0x80);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
L2CAP_task();
|
||||
}
|
||||
}
|
||||
|
@ -583,7 +596,7 @@ void WII::L2CAP_task() {
|
|||
/* These states are used if the Wiimote is the host */
|
||||
case L2CAP_CONTROL_SUCCESS:
|
||||
if (l2cap_config_success_control_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nHID Control Successfully Configured"), 0x80);
|
||||
#endif
|
||||
l2cap_state = L2CAP_INTERRUPT_SETUP;
|
||||
|
@ -592,7 +605,7 @@ void WII::L2CAP_task() {
|
|||
|
||||
case L2CAP_INTERRUPT_SETUP:
|
||||
if (l2cap_connection_request_interrupt_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nHID Interrupt Incoming Connection Request"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_connection_response(hci_handle, identifier, interrupt_dcid, interrupt_scid, PENDING);
|
||||
|
@ -609,7 +622,7 @@ void WII::L2CAP_task() {
|
|||
/* These states are used if the Arduino is the host */
|
||||
case L2CAP_CONTROL_CONNECT_REQUEST:
|
||||
if (l2cap_connected_control_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSend HID Control Config Request"), 0x80);
|
||||
#endif
|
||||
identifier++;
|
||||
|
@ -620,7 +633,7 @@ void WII::L2CAP_task() {
|
|||
|
||||
case L2CAP_CONTROL_CONFIG_REQUEST:
|
||||
if (l2cap_config_success_control_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSend HID Interrupt Connection Request"), 0x80);
|
||||
#endif
|
||||
identifier++;
|
||||
|
@ -631,7 +644,7 @@ void WII::L2CAP_task() {
|
|||
|
||||
case L2CAP_INTERRUPT_CONNECT_REQUEST:
|
||||
if (l2cap_connected_interrupt_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSend HID Interrupt Config Request"), 0x80);
|
||||
#endif
|
||||
identifier++;
|
||||
|
@ -642,12 +655,11 @@ void WII::L2CAP_task() {
|
|||
|
||||
case L2CAP_INTERRUPT_CONFIG_REQUEST:
|
||||
if (l2cap_config_success_interrupt_flag) { // Now the HID channels is established
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nHID Channels Established"), 0x80);
|
||||
#endif
|
||||
pBtd->connectToWii = false;
|
||||
pBtd->pairWithWii = false;
|
||||
wiimoteConnected = true;
|
||||
stateCounter = 0;
|
||||
l2cap_state = L2CAP_CHECK_MOTION_PLUS_STATE;
|
||||
}
|
||||
|
@ -656,8 +668,8 @@ void WII::L2CAP_task() {
|
|||
/* The next states are in run() */
|
||||
|
||||
case L2CAP_INTERRUPT_DISCONNECT:
|
||||
if (l2cap_disconnect_response_interrupt_flag) {
|
||||
#ifdef DEBUG
|
||||
if (l2cap_disconnect_response_interrupt_flag && millis() > timer) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnected Interrupt Channel"), 0x80);
|
||||
#endif
|
||||
identifier++;
|
||||
|
@ -668,7 +680,7 @@ void WII::L2CAP_task() {
|
|||
|
||||
case L2CAP_CONTROL_DISCONNECT:
|
||||
if (l2cap_disconnect_response_control_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nDisconnected Control Channel"), 0x80);
|
||||
#endif
|
||||
pBtd->hci_disconnect(hci_handle);
|
||||
|
@ -681,12 +693,16 @@ void WII::L2CAP_task() {
|
|||
}
|
||||
|
||||
void WII::Run() {
|
||||
if (l2cap_state == L2CAP_INTERRUPT_DISCONNECT && millis() > timer)
|
||||
L2CAP_task(); // Call the rest of the disconnection routine after we have waited long enough
|
||||
|
||||
switch (l2cap_state) {
|
||||
case L2CAP_WAIT:
|
||||
if (pBtd->connectToWii && !pBtd->l2capConnectionClaimed && !wiimoteConnected && !activeConnection) {
|
||||
pBtd->l2capConnectionClaimed = true;
|
||||
activeConnection = true;
|
||||
#ifdef DEBUG
|
||||
motionPlusInside = pBtd->motionPlusInside;
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSend HID Control Connection Request"), 0x80);
|
||||
#endif
|
||||
hci_handle = pBtd->hci_handle; // Store the HCI Handle for the connection
|
||||
|
@ -695,7 +711,7 @@ void WII::Run() {
|
|||
pBtd->l2cap_connection_request(hci_handle, identifier, control_dcid, HID_CTRL_PSM);
|
||||
l2cap_state = L2CAP_CONTROL_CONNECT_REQUEST;
|
||||
} else if (l2cap_connection_request_control_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nHID Control Incoming Connection Request"), 0x80);
|
||||
#endif
|
||||
pBtd->l2cap_connection_response(hci_handle, identifier, control_dcid, control_scid, PENDING);
|
||||
|
@ -709,7 +725,7 @@ void WII::Run() {
|
|||
break;
|
||||
|
||||
case L2CAP_CHECK_MOTION_PLUS_STATE:
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
if (stateCounter == 0) // Only print onnce
|
||||
Notify(PSTR("\r\nChecking if a Motion Plus is connected"), 0x80);
|
||||
#endif
|
||||
|
@ -722,14 +738,14 @@ void WII::Run() {
|
|||
timer = micros();
|
||||
|
||||
if (unknownExtensionConnected) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nA extension is also connected"), 0x80);
|
||||
#endif
|
||||
activateNunchuck = true; // For we will just set this to true as this the only extension supported so far
|
||||
}
|
||||
|
||||
} else if (stateCounter == 601) { // We will try three times to check for the motion plus
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nNo Motion Plus was detected"), 0x80);
|
||||
#endif
|
||||
stateCounter = 0;
|
||||
|
@ -738,7 +754,7 @@ void WII::Run() {
|
|||
break;
|
||||
|
||||
case L2CAP_CHECK_EXTENSION_STATE: // This is used to check if there is anything plugged in to the extension port
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
if (stateCounter == 0) // Only print onnce
|
||||
Notify(PSTR("\r\nChecking if there is any extension connected"), 0x80);
|
||||
#endif
|
||||
|
@ -779,13 +795,14 @@ void WII::Run() {
|
|||
case L2CAP_LED_STATE:
|
||||
if (nunchuck_connected_flag)
|
||||
nunchuckConnected = true;
|
||||
setLedStatus();
|
||||
wiimoteConnected = true;
|
||||
onInit();
|
||||
l2cap_state = L2CAP_DONE;
|
||||
break;
|
||||
|
||||
case L2CAP_DONE:
|
||||
if (unknownExtensionConnected) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
if (stateCounter == 0) // Only print once
|
||||
Notify(PSTR("\r\nChecking extension port"), 0x80);
|
||||
#endif
|
||||
|
@ -803,7 +820,7 @@ void WII::Run() {
|
|||
readExtensionType();
|
||||
else if (stateCounter == 250) {
|
||||
if (nunchuck_connected_flag) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nNunchuck was reconnected"), 0x80);
|
||||
#endif
|
||||
activateNunchuck = true;
|
||||
|
@ -813,7 +830,7 @@ void WII::Run() {
|
|||
stateCounter = 449;
|
||||
} else if (stateCounter == 300) {
|
||||
if (motionPlusConnected) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nReactivating the Motion Plus"), 0x80);
|
||||
#endif
|
||||
initMotionPlus();
|
||||
|
@ -824,7 +841,7 @@ void WII::Run() {
|
|||
else if (stateCounter == 400)
|
||||
readExtensionType(); // Check if it has been activated
|
||||
else if (stateCounter == 450) {
|
||||
//setLedStatus();
|
||||
onInit();
|
||||
stateCounter = 0;
|
||||
unknownExtensionConnected = false;
|
||||
}
|
||||
|
@ -839,7 +856,7 @@ void WII::Run() {
|
|||
|
||||
/************************************************************/
|
||||
void WII::HID_Command(uint8_t* data, uint8_t nbytes) {
|
||||
if (pBtd->motionPlusInside)
|
||||
if (motionPlusInside)
|
||||
pBtd->L2CAP_Command(hci_handle, data, nbytes, interrupt_scid[0], interrupt_scid[1]); // It's the new wiimote with the Motion Plus Inside
|
||||
else
|
||||
pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]);
|
||||
|
@ -905,6 +922,12 @@ void WII::setLedStatus() {
|
|||
HID_Command(HIDBuffer, 3);
|
||||
}
|
||||
|
||||
uint8_t WII::getBatteryLevel() {
|
||||
checkExtension = false; // This is needed so the library knows that the status response is a response to this function
|
||||
statusRequest(); // This will update the battery level
|
||||
return batteryLevel;
|
||||
};
|
||||
|
||||
void WII::setReportMode(bool continuous, uint8_t mode) {
|
||||
uint8_t cmd_buf[4];
|
||||
cmd_buf[0] = 0xA2; // HID BT DATA_request (0xA0) | Report Type (Output 0x02)
|
||||
|
@ -967,19 +990,19 @@ void WII::initMotionPlus() {
|
|||
void WII::activateMotionPlus() {
|
||||
uint8_t buf[1];
|
||||
if (pBtd->wiiUProController) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nActivating Wii U Pro Controller"), 0x80);
|
||||
#endif
|
||||
buf[0] = 0x00; // It seems like you can send anything but 0x04, 0x05, and 0x07
|
||||
} else if (activateNunchuck) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nActivating Motion Plus in pass-through mode"), 0x80);
|
||||
#endif
|
||||
buf[0] = 0x05; // Activate nunchuck pass-through mode
|
||||
} //else if(classicControllerConnected && extensionConnected)
|
||||
//buf[0] = 0x07;
|
||||
else {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nActivating Motion Plus in normal mode"), 0x80);
|
||||
#endif
|
||||
buf[0] = 0x04; // Don't use any extension
|
||||
|
@ -1062,6 +1085,14 @@ uint16_t WII::getAnalogHat(AnalogHat a) {
|
|||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
void WII::onInit() {
|
||||
if (pFuncOnInit)
|
||||
pFuncOnInit(); // Call the user function
|
||||
else
|
||||
setLedStatus();
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
/* The following functions are for the IR camera */
|
||||
/************************************************************/
|
||||
|
@ -1071,58 +1102,58 @@ uint16_t WII::getAnalogHat(AnalogHat a) {
|
|||
void WII::IRinitialize() { // Turns on and initialises the IR camera
|
||||
|
||||
enableIRCamera1();
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nEnable IR Camera1 Complete"), 0x80);
|
||||
#endif
|
||||
delay(80);
|
||||
|
||||
enableIRCamera2();
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nEnable IR Camera2 Complete"), 0x80);
|
||||
#endif
|
||||
delay(80);
|
||||
|
||||
write0x08Value();
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nWrote hex number 0x08"), 0x80);
|
||||
#endif
|
||||
delay(80);
|
||||
|
||||
writeSensitivityBlock1();
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nWrote Sensitivity Block 1"), 0x80);
|
||||
#endif
|
||||
delay(80);
|
||||
|
||||
writeSensitivityBlock2();
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nWrote Sensitivity Block 2"), 0x80);
|
||||
#endif
|
||||
delay(80);
|
||||
|
||||
uint8_t mode_num = 0x03;
|
||||
setWiiModeNumber(mode_num); // Change input for whatever mode you want i.e. 0x01, 0x03, or 0x05
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSet Wii Mode Number To 0x"), 0x80);
|
||||
PrintHex<uint8_t > (mode_num, 0x80);
|
||||
D_PrintHex<uint8_t > (mode_num, 0x80);
|
||||
#endif
|
||||
delay(80);
|
||||
|
||||
write0x08Value();
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nWrote Hex Number 0x08"), 0x80);
|
||||
#endif
|
||||
delay(80);
|
||||
|
||||
setReportMode(false, 0x33);
|
||||
//setReportMode(false, 0x3f); // For full reporting mode, doesn't work yet
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nSet Report Mode to 0x33"), 0x80);
|
||||
#endif
|
||||
delay(80);
|
||||
|
||||
statusRequest(); // Used to update wiiState - call isIRCameraEnabled() afterwards to check if it actually worked
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nIR Initialized"), 0x80);
|
||||
#endif
|
||||
}
|
||||
|
|
41
Wii.h
41
Wii.h
|
@ -14,9 +14,7 @@
|
|||
Web : http://www.tkjelectronics.com
|
||||
e-mail : kristianl@tkjelectronics.com
|
||||
|
||||
IR camera support added by:
|
||||
Allan Glover
|
||||
adglover9.81@gmail.com
|
||||
IR camera support added by Allan Glover (adglover9.81@gmail.com) and Kristian Lauszus
|
||||
*/
|
||||
|
||||
#ifndef _wii_h_
|
||||
|
@ -215,17 +213,11 @@ public:
|
|||
*/
|
||||
void setLedStatus();
|
||||
|
||||
/**
|
||||
* Call this to update battery level and Wiimote state
|
||||
*/
|
||||
void statusRequest();
|
||||
/**
|
||||
* Return the battery level of the Wiimote.
|
||||
* @return The battery level in the range 0-255.
|
||||
*/
|
||||
uint8_t getBatteryLevel() {
|
||||
return batteryLevel;
|
||||
};
|
||||
uint8_t getBatteryLevel();
|
||||
/**
|
||||
* Return the Wiimote state.
|
||||
* @return See: http://wiibrew.org/wiki/Wiimote#0x20:_Status.
|
||||
|
@ -233,6 +225,14 @@ public:
|
|||
uint8_t getWiiState() {
|
||||
return wiiState;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to call your own function when the controller is successfully initialized.
|
||||
* @param funcOnInit Function to call.
|
||||
*/
|
||||
void attachOnInit(void (*funcOnInit)(void)) {
|
||||
pFuncOnInit = funcOnInit;
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/**@{*/
|
||||
|
@ -418,8 +418,15 @@ public:
|
|||
#endif
|
||||
|
||||
private:
|
||||
/* Mandatory members */
|
||||
BTD *pBtd;
|
||||
BTD *pBtd; // Pointer to BTD instance
|
||||
|
||||
/**
|
||||
* Called when the controller 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.
|
||||
*/
|
||||
void onInit();
|
||||
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
|
||||
|
||||
void L2CAP_task(); // L2CAP state machine
|
||||
|
||||
|
@ -427,9 +434,9 @@ private:
|
|||
uint16_t hci_handle;
|
||||
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;
|
||||
uint16_t l2cap_event_flag; // l2cap flags of received bluetooth events
|
||||
uint16_t l2cap_event_flag; // l2cap flags of received Bluetooth events
|
||||
|
||||
uint32_t ButtonState;
|
||||
uint32_t OldButtonState;
|
||||
|
@ -441,6 +448,8 @@ private:
|
|||
uint16_t stateCounter;
|
||||
bool unknownExtensionConnected;
|
||||
bool extensionConnected;
|
||||
bool checkExtension; // Set to false when getBatteryLevel() is called otherwise if should be true
|
||||
bool motionPlusInside; // True if it's a new Wiimote with the Motion Plus extension build into it
|
||||
|
||||
/* L2CAP Channels */
|
||||
uint8_t control_scid[2]; // L2CAP source CID for HID_Control
|
||||
|
@ -457,6 +466,8 @@ private:
|
|||
void initExtension1();
|
||||
void initExtension2();
|
||||
|
||||
void statusRequest(); // Used to update the Wiimote state and battery level
|
||||
|
||||
void readData(uint32_t offset, uint16_t size, bool EEPROM);
|
||||
void readExtensionType();
|
||||
void readCalData();
|
||||
|
@ -476,7 +487,7 @@ private:
|
|||
uint8_t batteryLevel;
|
||||
|
||||
#ifdef WIICAMERA
|
||||
/* Private function and variables for the readings from teh IR Camera */
|
||||
/* Private function and variables for the readings from the IR Camera */
|
||||
void enableIRCamera1(); // Sets bit 2 of output report 13
|
||||
void enableIRCamera2(); // Sets bit 2 of output report 1A
|
||||
void writeSensitivityBlock1();
|
||||
|
|
334
XBOXOLD.cpp
Normal file
334
XBOXOLD.cpp
Normal file
|
@ -0,0 +1,334 @@
|
|||
/* Copyright (C) 2013 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 "XBOXOLD.h"
|
||||
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
|
||||
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
||||
//#define PRINTREPORT // Uncomment to print the report send by the Xbox controller
|
||||
|
||||
/** Buttons on the controllers */
|
||||
const uint8_t XBOXOLDBUTTONS[] PROGMEM = {
|
||||
0x01, // UP
|
||||
0x08, // RIGHT
|
||||
0x02, // DOWN
|
||||
0x04, // LEFT
|
||||
|
||||
0x20, // BACK
|
||||
0x10, // START
|
||||
0x40, // L3
|
||||
0x80, // R3
|
||||
|
||||
// A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons
|
||||
4, // BLACK
|
||||
5, // WHTIE
|
||||
6, // L1
|
||||
7, // R1
|
||||
|
||||
1, // B
|
||||
0, // A
|
||||
2, // X
|
||||
3, // Y
|
||||
};
|
||||
|
||||
XBOXOLD::XBOXOLD(USB *p) :
|
||||
pUsb(p), // pointer to USB class instance - mandatory
|
||||
bAddress(0), // device address - mandatory
|
||||
bPollEnable(false) { // don't start polling before dongle is connected
|
||||
for (uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) {
|
||||
epInfo[i].epAddr = 0;
|
||||
epInfo[i].maxPktSize = (i) ? 0 : 8;
|
||||
epInfo[i].epAttribs = 0;
|
||||
epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
|
||||
}
|
||||
|
||||
if (pUsb) // register in USB subsystem
|
||||
pUsb->RegisterDeviceClass(this); //set devConfig[] entry
|
||||
}
|
||||
|
||||
uint8_t XBOXOLD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
|
||||
uint8_t rcode;
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint16_t PID;
|
||||
uint16_t VID;
|
||||
|
||||
// get memory address of USB device address pool
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nXBOXUSB Init"), 0x80);
|
||||
#endif
|
||||
// check if address has already been assigned to an instance
|
||||
if (bAddress) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nAddress in use"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
}
|
||||
|
||||
// Get pointer to pseudo device with address 0 assigned
|
||||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nAddress not found"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
if (!p->epinfo) {
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nepinfo is null"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
}
|
||||
|
||||
// Save old pointer to EP_RECORD of address 0
|
||||
oldep_ptr = p->epinfo;
|
||||
|
||||
// Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
|
||||
p->epinfo = epInfo;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Get device descriptor
|
||||
rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
|
||||
// Restore p->epinfo
|
||||
p->epinfo = oldep_ptr;
|
||||
|
||||
if (rcode)
|
||||
goto FailGetDevDescr;
|
||||
|
||||
VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
|
||||
PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
|
||||
|
||||
if ((VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) || (PID != XBOX_OLD_PID1 && PID != XBOX_OLD_PID2 && PID != XBOX_OLD_PID3 && PID != XBOX_OLD_PID4)) // Check if VID and PID match
|
||||
goto FailUnknownDevice;
|
||||
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
||||
if (!bAddress)
|
||||
return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
|
||||
|
||||
// Extract Max Packet Size from device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||
if (rcode) {
|
||||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nsetAddr: "), 0x80);
|
||||
D_PrintHex<uint8_t > (rcode, 0x80);
|
||||
#endif
|
||||
return rcode;
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nAddr: "), 0x80);
|
||||
D_PrintHex<uint8_t > (bAddress, 0x80);
|
||||
#endif
|
||||
delay(300); // Spec says you should wait at least 200ms
|
||||
|
||||
p->lowspeed = false;
|
||||
|
||||
//get pointer to assigned address record
|
||||
p = addrPool.GetUsbDevicePtr(bAddress);
|
||||
if (!p)
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
|
||||
p->lowspeed = lowspeed;
|
||||
|
||||
// Assign epInfo to epinfo pointer - only EP0 is known
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
/* The application will work in reduced host mode, so we can save program and data
|
||||
memory space. After verifying the VID we will use known values for the
|
||||
configuration values for device, interface, endpoints and HID for the XBOX controllers */
|
||||
|
||||
/* Initialize data structures for endpoints of device */
|
||||
epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX report endpoint
|
||||
epInfo[ XBOX_INPUT_PIPE ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_INPUT_PIPE ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_INPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].epAddr = 0x02; // XBOX output endpoint
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].epAttribs = EP_INTERRUPT;
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].bmSndToggle = bmSNDTOG0;
|
||||
epInfo[ XBOX_OUTPUT_PIPE ].bmRcvToggle = bmRCVTOG0;
|
||||
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
|
||||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
delay(200); // Give time for address change
|
||||
|
||||
rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
|
||||
if (rcode)
|
||||
goto FailSetConfDescr;
|
||||
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nXbox Controller Connected\r\n"), 0x80);
|
||||
#endif
|
||||
if (pFuncOnInit)
|
||||
pFuncOnInit(); // Call the user function
|
||||
XboxConnected = true;
|
||||
bPollEnable = true;
|
||||
return 0; // Successful configuration
|
||||
|
||||
/* Diagnostic messages */
|
||||
FailGetDevDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetDevDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetDevTblEntry:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetDevTblEntry();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetConfDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
FailUnknownDevice:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailUnknownDevice(VID, PID);
|
||||
#endif
|
||||
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
|
||||
Fail:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nXbox Init Failed, error code: "), 0x80);
|
||||
NotifyFail(rcode);
|
||||
#endif
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
||||
/* Performs a cleanup after failed Init() attempt */
|
||||
uint8_t XBOXOLD::Release() {
|
||||
XboxConnected = false;
|
||||
pUsb->GetAddressPool().FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
bPollEnable = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t XBOXOLD::Poll() {
|
||||
if (!bPollEnable)
|
||||
return 0;
|
||||
uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
|
||||
pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1
|
||||
readReport();
|
||||
#ifdef PRINTREPORT
|
||||
printReport(BUFFER_SIZE); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox controller
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void XBOXOLD::readReport() {
|
||||
ButtonState = readBuf[2];
|
||||
|
||||
for (uint8_t i = 0; i < sizeof(buttonValues); i++)
|
||||
buttonValues[i] = readBuf[i + 4]; // A, B, X, Y, BLACK, WHITE, L1, and R1
|
||||
|
||||
hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[12] << 8) | readBuf[13]);
|
||||
hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[14] << 8) | readBuf[15]);
|
||||
hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[16] << 8) | readBuf[17]);
|
||||
hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[18] << 8) | readBuf[19]);
|
||||
|
||||
//Notify(PSTR("\r\nButtonState"), 0x80);
|
||||
//PrintHex<uint8_t>(ButtonState, 0x80);
|
||||
|
||||
if (ButtonState != OldButtonState || memcmp(buttonValues, oldButtonValues, sizeof(buttonValues)) != 0) {
|
||||
ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
|
||||
OldButtonState = ButtonState;
|
||||
|
||||
for (uint8_t i = 0; i < sizeof(buttonValues); i++) {
|
||||
if (oldButtonValues[i] == 0 && buttonValues[i] != 0)
|
||||
buttonClicked[i] = true; // Update A, B, X, Y, BLACK, WHITE, L1, and R1 click state
|
||||
oldButtonValues[i] = buttonValues[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XBOXOLD::printReport(uint16_t length) { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox controller
|
||||
#ifdef PRINTREPORT
|
||||
if (readBuf == NULL)
|
||||
return;
|
||||
for (uint8_t i = 0; i < length; i++) {
|
||||
D_PrintHex<uint8_t > (readBuf[i], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
}
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t XBOXOLD::getButtonPress(Button b) {
|
||||
if (b == A || b == B || b == X || b == Y || b == BLACK || b == WHITE || b == L1 || b == R1) // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons
|
||||
return buttonValues[pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b])]; // Analog buttons
|
||||
return (ButtonState & pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b])); // Digital buttons
|
||||
}
|
||||
|
||||
bool XBOXOLD::getButtonClick(Button b) {
|
||||
uint8_t button;
|
||||
if (b == A || b == B || b == X || b == Y || b == BLACK || b == WHITE || b == L1 || b == R1) { // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons
|
||||
button = pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b]);
|
||||
if (buttonClicked[button])
|
||||
buttonClicked[button] = false;
|
||||
return buttonClicked[button];
|
||||
}
|
||||
|
||||
button = pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b]); // Digital buttons
|
||||
bool click = (ButtonClickState & button);
|
||||
ButtonClickState &= ~button; // clear "click" event
|
||||
return click;
|
||||
}
|
||||
|
||||
int16_t XBOXOLD::getAnalogHat(AnalogHat a) {
|
||||
return hatValue[a];
|
||||
}
|
||||
|
||||
/* Xbox Controller commands */
|
||||
void XBOXOLD::XboxCommand(uint8_t* data, uint16_t nbytes) {
|
||||
//bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x00), Report Type (Output 0x02), interface (0x00), datalength, datalength, data)
|
||||
pUsb->ctrlReq(bAddress, epInfo[XBOX_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x00, 0x02, 0x00, nbytes, nbytes, data, NULL);
|
||||
}
|
||||
|
||||
void XBOXOLD::setRumbleOn(uint8_t lValue, uint8_t rValue) {
|
||||
uint8_t writeBuf[6];
|
||||
|
||||
writeBuf[0] = 0x00;
|
||||
writeBuf[1] = 0x06;
|
||||
writeBuf[2] = 0x00;
|
||||
writeBuf[3] = rValue; // small weight
|
||||
writeBuf[4] = 0x00;
|
||||
writeBuf[5] = lValue; // big weight
|
||||
|
||||
XboxCommand(writeBuf, 6);
|
||||
}
|
192
XBOXOLD.h
Normal file
192
XBOXOLD.h
Normal file
|
@ -0,0 +1,192 @@
|
|||
/* Copyright (C) 2013 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 _xboxold_h_
|
||||
#define _xboxold_h_
|
||||
|
||||
#include "Usb.h"
|
||||
#include "controllerEnums.h"
|
||||
|
||||
/* Data Xbox taken from descriptors */
|
||||
#define EP_MAXPKTSIZE 32 // Max size for data via USB
|
||||
|
||||
/* Endpoint types */
|
||||
#define EP_INTERRUPT 0x03
|
||||
|
||||
/* Names we give to the 3 Xbox pipes */
|
||||
#define XBOX_CONTROL_PIPE 0
|
||||
#define XBOX_INPUT_PIPE 1
|
||||
#define XBOX_OUTPUT_PIPE 2
|
||||
|
||||
// PID and VID of the different devices
|
||||
#define XBOX_VID 0x045E // Microsoft Corporation
|
||||
#define MADCATZ_VID 0x1BAD // For unofficial Mad Catz controllers
|
||||
#define JOYTECH_VID 0x162E // For unofficial Joytech controllers
|
||||
|
||||
#define XBOX_OLD_PID1 0x0202 // Original Microsoft Xbox controller (US)
|
||||
#define XBOX_OLD_PID2 0x0285 // Original Microsoft Xbox controller (Japan)
|
||||
#define XBOX_OLD_PID3 0x0287 // Microsoft Microsoft Xbox Controller S
|
||||
#define XBOX_OLD_PID4 0x0289 // Smaller Microsoft Xbox controller (US)
|
||||
|
||||
// Used in control endpoint header for HID Commands
|
||||
#define bmREQ_HID_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||
#define HID_REQUEST_SET_REPORT 0x09
|
||||
|
||||
#define XBOX_MAX_ENDPOINTS 3
|
||||
|
||||
/** This class implements support for a the original Xbox controller via USB. */
|
||||
class XBOXOLD : public USBDeviceConfig {
|
||||
public:
|
||||
/**
|
||||
* Constructor for the XBOXOLD class.
|
||||
* @param pUsb Pointer to USB class instance.
|
||||
*/
|
||||
XBOXOLD(USB *pUsb);
|
||||
|
||||
/** @name USBDeviceConfig implementation */
|
||||
/**
|
||||
* Initialize the Xbox Controller.
|
||||
* @param parent Hub number.
|
||||
* @param port Port number on the hub.
|
||||
* @param lowspeed Speed of the device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
/**
|
||||
* Release the USB device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Release();
|
||||
/**
|
||||
* Poll the USB Input endpoins and run the state machines.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
virtual uint8_t Poll();
|
||||
|
||||
/**
|
||||
* Get the device address.
|
||||
* @return The device address.
|
||||
*/
|
||||
virtual uint8_t GetAddress() {
|
||||
return bAddress;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to check if the controller has been initialized.
|
||||
* @return True if it's ready.
|
||||
*/
|
||||
virtual bool isReady() {
|
||||
return bPollEnable;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used by the USB core to check what this driver support.
|
||||
* @param vid The device's VID.
|
||||
* @param pid The device's PID.
|
||||
* @return Returns true if the device's VID and PID matches this driver.
|
||||
*/
|
||||
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) {
|
||||
return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID) && (pid == XBOX_OLD_PID1 || pid == XBOX_OLD_PID2 || pid == XBOX_OLD_PID3 || pid == XBOX_OLD_PID4));
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/** @name Xbox Controller functions */
|
||||
/**
|
||||
* getButtonPress(Button b) will return true as long as the button is held down.
|
||||
*
|
||||
* While getButtonClick(Button b) will only return it once.
|
||||
*
|
||||
* So you instance if you need to increase a variable once you would use getButtonClick(Button b),
|
||||
* but if you need to drive a robot forward you would use getButtonPress(Button b).
|
||||
* @param b ::Button to read.
|
||||
* @return getButtonClick(Button b) will return a bool, but getButtonPress(Button b)
|
||||
* will return a byte if reading ::L2 or ::R2.
|
||||
*/
|
||||
uint8_t getButtonPress(Button b);
|
||||
bool getButtonClick(Button b);
|
||||
/**@}*/
|
||||
|
||||
/** @name Xbox Controller functions */
|
||||
/**
|
||||
* Return the analog value from the joysticks on the controller.
|
||||
* @param a Either ::LeftHatX, ::LeftHatY, ::RightHatX or ::RightHatY.
|
||||
* @return Returns a signed 16-bit integer.
|
||||
*/
|
||||
int16_t getAnalogHat(AnalogHat a);
|
||||
|
||||
/** Turn rumble off the controller. */
|
||||
void setRumbleOff() {
|
||||
setRumbleOn(0, 0);
|
||||
};
|
||||
/**
|
||||
* Turn rumble on.
|
||||
* @param lValue Left motor (big weight) inside the controller.
|
||||
* @param rValue Right motor (small weight) inside the controller.
|
||||
*/
|
||||
void setRumbleOn(uint8_t lValue, uint8_t rValue);
|
||||
|
||||
/**
|
||||
* Used to call your own function when the controller is successfully initialized.
|
||||
* @param funcOnInit Function to call.
|
||||
*/
|
||||
void attachOnInit(void (*funcOnInit)(void)) {
|
||||
pFuncOnInit = funcOnInit;
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/** True if a Xbox controller is connected. */
|
||||
bool XboxConnected;
|
||||
|
||||
protected:
|
||||
/** Pointer to USB class instance. */
|
||||
USB *pUsb;
|
||||
/** Device address. */
|
||||
uint8_t bAddress;
|
||||
/** Endpoint info structure. */
|
||||
EpInfo epInfo[XBOX_MAX_ENDPOINTS];
|
||||
|
||||
private:
|
||||
/**
|
||||
* Called when the controller 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.
|
||||
*/
|
||||
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
|
||||
|
||||
bool bPollEnable;
|
||||
|
||||
/* Variables to store the digital buttons */
|
||||
uint8_t ButtonState;
|
||||
uint8_t OldButtonState;
|
||||
uint8_t ButtonClickState;
|
||||
|
||||
/* Variables to store the analog buttons */
|
||||
uint8_t buttonValues[8]; // A, B, X, Y, BLACK, WHITE, L1, and R1
|
||||
uint8_t oldButtonValues[8];
|
||||
bool buttonClicked[8];
|
||||
|
||||
int16_t hatValue[4]; // Joystick values
|
||||
|
||||
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
|
||||
|
||||
void readReport(); // Read incoming data
|
||||
void printReport(uint16_t length); // Print incoming date
|
||||
|
||||
/* Private commands */
|
||||
void XboxCommand(uint8_t* data, uint16_t nbytes);
|
||||
};
|
||||
#endif
|
76
XBOXRECV.cpp
76
XBOXRECV.cpp
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "XBOXRECV.h"
|
||||
#define DEBUG // Uncomment to print data for debugging
|
||||
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
|
||||
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
||||
//#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller
|
||||
|
||||
|
@ -52,7 +52,7 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
#endif
|
||||
// check if address has already been assigned to an instance
|
||||
if (bAddress) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nAddress in use"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
|
@ -62,14 +62,14 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nAddress not found"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
if (!p->epinfo) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nepinfo is null"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
|
@ -94,10 +94,10 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
|
||||
PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
|
||||
|
||||
if (VID != XBOX_VID && VID != MADCATZ_VID) // We just check if it's a xbox receiver using the Vendor ID
|
||||
if (VID != XBOX_VID && VID != MADCATZ_VID) // We just check if it's a Xbox receiver using the Vendor ID
|
||||
goto FailUnknownDevice;
|
||||
else if (PID != XBOX_WIRELESS_RECEIVER_PID && PID != XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) {
|
||||
#ifdef DEBUG
|
||||
else if (PID != XBOX_WIRELESS_RECEIVER_PID && PID != XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) { // Check the PID as well
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nYou'll need a wireless receiver for this libary to work"), 0x80);
|
||||
#endif
|
||||
goto FailUnknownDevice;
|
||||
|
@ -118,16 +118,18 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nsetAddr: "), 0x80);
|
||||
D_PrintHex<uint8_t > (rcode, 0x80);
|
||||
#endif
|
||||
PrintHex<uint8_t > (rcode, 0x80);
|
||||
return rcode;
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nAddr: "), 0x80);
|
||||
PrintHex<uint8_t > (bAddress, 0x80);
|
||||
D_PrintHex<uint8_t > (bAddress, 0x80);
|
||||
#endif
|
||||
delay(300); // Spec says you should wait at least 200ms
|
||||
|
||||
p->lowspeed = false;
|
||||
|
||||
//get pointer to assigned address record
|
||||
|
@ -209,7 +211,7 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
if (rcode)
|
||||
goto FailSetConfDescr;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nXbox Wireless Receiver Connected\r\n"), 0x80);
|
||||
#endif
|
||||
XboxReceiverConnected = true;
|
||||
|
@ -218,26 +220,34 @@ uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
|
||||
/* diagnostic messages */
|
||||
FailGetDevDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetDevDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetDevTblEntry:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetDevTblEntry();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetConfDescr();
|
||||
#endif
|
||||
goto Fail;
|
||||
|
||||
FailUnknownDevice:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailUnknownDevice(VID,PID);
|
||||
#endif
|
||||
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
|
||||
Fail:
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80);
|
||||
#endif
|
||||
NotifyFail(rcode);
|
||||
#endif
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
@ -278,7 +288,7 @@ uint8_t XBOXRECV::Poll() {
|
|||
if (bufferSize > 0) { // The number of received bytes
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("Bytes Received: "), 0x80);
|
||||
PrintHex<uint16_t > (bufferSize, 0x80);
|
||||
D_PrintHex<uint16_t > (bufferSize, 0x80);
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
#endif
|
||||
readReport(i);
|
||||
|
@ -296,12 +306,12 @@ void XBOXRECV::readReport(uint8_t controller) {
|
|||
// This report is send when a controller is connected and disconnected
|
||||
if (readBuf[0] == 0x08 && readBuf[1] != Xbox360Connected[controller]) {
|
||||
Xbox360Connected[controller] = readBuf[1];
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("Controller "), 0x80);
|
||||
Notify(controller, 0x80);
|
||||
#endif
|
||||
if (Xbox360Connected[controller]) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
const char* str = 0;
|
||||
switch (readBuf[1]) {
|
||||
case 0x80: str = PSTR(" as controller\r\n");
|
||||
|
@ -314,20 +324,9 @@ void XBOXRECV::readReport(uint8_t controller) {
|
|||
Notify(PSTR(": connected"), 0x80);
|
||||
Notify(str, 0x80);
|
||||
#endif
|
||||
LED led;
|
||||
switch (controller) {
|
||||
case 0: led = LED1;
|
||||
break;
|
||||
case 1: led = LED2;
|
||||
break;
|
||||
case 2: led = LED3;
|
||||
break;
|
||||
case 3: led = LED4;
|
||||
break;
|
||||
onInit(controller);
|
||||
}
|
||||
setLedOn(led, controller);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
else
|
||||
Notify(PSTR(": disconnected\r\n"), 0x80);
|
||||
#endif
|
||||
|
@ -374,7 +373,7 @@ void XBOXRECV::printReport(uint8_t controller, uint8_t nBytes) { //Uncomment "#d
|
|||
Notify(controller, 0x80);
|
||||
Notify(PSTR(": "), 0x80);
|
||||
for (uint8_t i = 0; i < nBytes; i++) {
|
||||
PrintHex<uint8_t > (readBuf[i], 0x80);
|
||||
D_PrintHex<uint8_t > (readBuf[i], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
}
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
|
@ -521,3 +520,20 @@ void XBOXRECV::setRumbleOn(uint8_t lValue, uint8_t rValue, uint8_t controller) {
|
|||
|
||||
XboxCommand(controller, writeBuf, 7);
|
||||
}
|
||||
|
||||
void XBOXRECV::onInit(uint8_t controller) {
|
||||
if (pFuncOnInit)
|
||||
pFuncOnInit(); // Call the user function
|
||||
else {
|
||||
LED led;
|
||||
if (controller == 0)
|
||||
led = LED1;
|
||||
else if (controller == 1)
|
||||
led = LED2;
|
||||
else if (controller == 2)
|
||||
led = LED3;
|
||||
else
|
||||
led = LED4;
|
||||
setLedOn(led, controller);
|
||||
}
|
||||
}
|
||||
|
|
40
XBOXRECV.h
40
XBOXRECV.h
|
@ -20,12 +20,6 @@
|
|||
#ifndef _xboxrecv_h_
|
||||
#define _xboxrecv_h_
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include "Usb.h"
|
||||
#include "xboxEnums.h"
|
||||
|
||||
|
@ -48,11 +42,12 @@
|
|||
|
||||
// PID and VID of the different devices
|
||||
#define XBOX_VID 0x045E // Microsoft Corporation
|
||||
#define MADCATZ_VID 0x1BAD // For unofficial Mad Catz receivers
|
||||
#define JOYTECH_VID 0x162E // For unofficial Joytech controllers
|
||||
|
||||
#define XBOX_WIRELESS_RECEIVER_PID 0x0719 // Microsoft Wireless Gaming Receiver
|
||||
#define XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID 0x0291 // Third party Wireless Gaming Receiver
|
||||
|
||||
#define MADCATZ_VID 0x1BAD // For unofficial Mad Catz receivers
|
||||
|
||||
#define XBOX_MAX_ENDPOINTS 9
|
||||
|
||||
/**
|
||||
|
@ -103,6 +98,16 @@ public:
|
|||
virtual bool isReady() {
|
||||
return bPollEnable;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used by the USB core to check what this driver support.
|
||||
* @param vid The device's VID.
|
||||
* @param pid The device's PID.
|
||||
* @return Returns true if the device's VID and PID matches this driver.
|
||||
*/
|
||||
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) {
|
||||
return ((vid == XBOX_VID || vid == MADCATZ_VID || vid == JOYTECH_VID) && (pid == XBOX_WIRELESS_RECEIVER_PID || pid == XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID));
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/** @name Xbox Controller functions */
|
||||
|
@ -200,6 +205,14 @@ public:
|
|||
* @return True if a button has changed.
|
||||
*/
|
||||
bool buttonChanged(uint8_t controller = 0);
|
||||
|
||||
/**
|
||||
* Used to call your own function when the controller is successfully initialized.
|
||||
* @param funcOnInit Function to call.
|
||||
*/
|
||||
void attachOnInit(void (*funcOnInit)(void)) {
|
||||
pFuncOnInit = funcOnInit;
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/** True if a wireless receiver is connected. */
|
||||
|
@ -216,6 +229,15 @@ protected:
|
|||
EpInfo epInfo[XBOX_MAX_ENDPOINTS];
|
||||
|
||||
private:
|
||||
/**
|
||||
* Called when the controller 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.
|
||||
* @param controller The initialized controller.
|
||||
*/
|
||||
void onInit(uint8_t controller);
|
||||
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
|
||||
|
||||
bool bPollEnable;
|
||||
|
||||
/* Variables to store the buttons */
|
||||
|
@ -232,7 +254,7 @@ private:
|
|||
unsigned long timer; // Timing for checkStatus() signals
|
||||
|
||||
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
|
||||
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
|
||||
uint8_t writeBuf[7]; // General purpose buffer for output data
|
||||
|
||||
void readReport(uint8_t controller); // read incoming data
|
||||
void printReport(uint8_t controller, uint8_t nBytes); // print incoming date - Uncomment for debugging
|
||||
|
|
58
XBOXUSB.cpp
58
XBOXUSB.cpp
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
#include "XBOXUSB.h"
|
||||
#define DEBUG // Uncomment to print data for debugging
|
||||
// To enable serial debugging uncomment "#define DEBUG_USB_HOST" in message.h
|
||||
//#define EXTRADEBUG // Uncomment to get even more debugging data
|
||||
//#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller
|
||||
|
||||
|
@ -50,7 +50,7 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
#endif
|
||||
// check if address has already been assigned to an instance
|
||||
if (bAddress) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nAddress in use"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
|
||||
|
@ -60,14 +60,14 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
p = addrPool.GetUsbDevicePtr(0);
|
||||
|
||||
if (!p) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nAddress not found"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
|
||||
}
|
||||
|
||||
if (!p->epinfo) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nepinfo is null"), 0x80);
|
||||
#endif
|
||||
return USB_ERROR_EPINFO_IS_NULL;
|
||||
|
@ -92,19 +92,20 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
|
||||
PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
|
||||
|
||||
if (VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) // We just check if it's a xbox controller using the Vendor ID
|
||||
if (VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID && VID != GAMESTOP_VID) // Check VID
|
||||
goto FailUnknownDevice;
|
||||
if (PID == XBOX_WIRELESS_PID) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nYou have plugged in a wireless Xbox 360 controller - it doesn't support USB communication"), 0x80);
|
||||
#endif
|
||||
goto FailUnknownDevice;
|
||||
} else if (PID == XBOX_WIRELESS_RECEIVER_PID || PID == XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nThis library only supports Xbox 360 controllers via USB"), 0x80);
|
||||
#endif
|
||||
goto FailUnknownDevice;
|
||||
}
|
||||
} else if (PID != XBOX_WIRED_PID && PID != GAMESTOP_WIRED_PID) // Check PID
|
||||
goto FailUnknownDevice;
|
||||
|
||||
// Allocate new address according to device class
|
||||
bAddress = addrPool.AllocAddress(parent, false, port);
|
||||
|
@ -121,16 +122,18 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
p->lowspeed = false;
|
||||
addrPool.FreeAddress(bAddress);
|
||||
bAddress = 0;
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nsetAddr: "), 0x80);
|
||||
D_PrintHex<uint8_t > (rcode, 0x80);
|
||||
#endif
|
||||
PrintHex<uint8_t > (rcode, 0x80);
|
||||
return rcode;
|
||||
}
|
||||
#ifdef EXTRADEBUG
|
||||
Notify(PSTR("\r\nAddr: "), 0x80);
|
||||
PrintHex<uint8_t > (bAddress, 0x80);
|
||||
D_PrintHex<uint8_t > (bAddress, 0x80);
|
||||
#endif
|
||||
delay(300); // Spec says you should wait at least 200ms
|
||||
|
||||
p->lowspeed = false;
|
||||
|
||||
//get pointer to assigned address record
|
||||
|
@ -167,41 +170,49 @@ uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
if (rcode)
|
||||
goto FailSetDevTblEntry;
|
||||
|
||||
delay(200); //Give time for address change
|
||||
delay(200); // Give time for address change
|
||||
|
||||
rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
|
||||
if (rcode)
|
||||
goto FailSetConfDescr;
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nXbox 360 Controller Connected\r\n"), 0x80);
|
||||
#endif
|
||||
setLedOn(LED1);
|
||||
onInit();
|
||||
Xbox360Connected = true;
|
||||
bPollEnable = true;
|
||||
return 0; // successful configuration
|
||||
return 0; // Successful configuration
|
||||
|
||||
/* diagnostic messages */
|
||||
/* Diagnostic messages */
|
||||
FailGetDevDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetDevDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetDevTblEntry:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetDevTblEntry();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetConfDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
FailUnknownDevice:
|
||||
NotifyFailUnknownDevice(VID,PID);
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailUnknownDevice(VID, PID);
|
||||
#endif
|
||||
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
|
||||
Fail:
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG_USB_HOST
|
||||
Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80);
|
||||
#endif
|
||||
NotifyFail(rcode);
|
||||
#endif
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
@ -259,7 +270,7 @@ void XBOXUSB::printReport() { //Uncomment "#define PRINTREPORT" to print the rep
|
|||
if (readBuf == NULL)
|
||||
return;
|
||||
for (uint8_t i = 0; i < XBOX_REPORT_BUFFER_SIZE; i++) {
|
||||
PrintHex<uint8_t > (readBuf[i], 0x80);
|
||||
D_PrintHex<uint8_t > (readBuf[i], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
}
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
|
@ -337,3 +348,10 @@ void XBOXUSB::setRumbleOn(uint8_t lValue, uint8_t rValue) {
|
|||
|
||||
XboxCommand(writeBuf, 8);
|
||||
}
|
||||
|
||||
void XBOXUSB::onInit() {
|
||||
if (pFuncOnInit)
|
||||
pFuncOnInit(); // Call the user function
|
||||
else
|
||||
setLedOn(LED1);
|
||||
}
|
||||
|
|
43
XBOXUSB.h
43
XBOXUSB.h
|
@ -18,12 +18,6 @@
|
|||
#ifndef _xboxusb_h_
|
||||
#define _xboxusb_h_
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include "Usb.h"
|
||||
#include "xboxEnums.h"
|
||||
|
||||
|
@ -40,12 +34,15 @@
|
|||
|
||||
// PID and VID of the different devices
|
||||
#define XBOX_VID 0x045E // Microsoft Corporation
|
||||
#define MADCATZ_VID 0x1BAD // For unofficial Mad Catz controllers
|
||||
#define JOYTECH_VID 0x162E // For unofficial Joytech controllers
|
||||
#define GAMESTOP_VID 0x0E6F // Gamestop controller
|
||||
|
||||
#define XBOX_WIRED_PID 0x028E // Microsoft 360 Wired controller
|
||||
#define XBOX_WIRELESS_PID 0x028F // Wireless controller only support charging
|
||||
#define XBOX_WIRELESS_RECEIVER_PID 0x0719 // Microsoft Wireless Gaming Receiver
|
||||
#define XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID 0x0291 // Third party Wireless Gaming Receiver
|
||||
|
||||
#define MADCATZ_VID 0x1BAD // For unofficial Mad Catz controllers
|
||||
#define JOYTECH_VID 0x162E // For unofficial Joytech controllers
|
||||
#define GAMESTOP_WIRED_PID 0x0401 // Gamestop wired controller
|
||||
|
||||
#define XBOX_REPORT_BUFFER_SIZE 14 // Size of the input report buffer
|
||||
|
||||
|
@ -99,6 +96,16 @@ public:
|
|||
virtual bool isReady() {
|
||||
return bPollEnable;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used by the USB core to check what this driver support.
|
||||
* @param vid The device's VID.
|
||||
* @param pid The device's PID.
|
||||
* @return Returns true if the device's VID and PID matches this driver.
|
||||
*/
|
||||
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 == GAMESTOP_WIRED_PID));
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/** @name Xbox Controller functions */
|
||||
|
@ -168,6 +175,14 @@ public:
|
|||
* @param lm See ::LEDMode.
|
||||
*/
|
||||
void setLedMode(LEDMode lm);
|
||||
|
||||
/**
|
||||
* Used to call your own function when the controller is successfully initialized.
|
||||
* @param funcOnInit Function to call.
|
||||
*/
|
||||
void attachOnInit(void (*funcOnInit)(void)) {
|
||||
pFuncOnInit = funcOnInit;
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/** True if a Xbox 360 controller is connected. */
|
||||
|
@ -182,6 +197,14 @@ protected:
|
|||
EpInfo epInfo[XBOX_MAX_ENDPOINTS];
|
||||
|
||||
private:
|
||||
/**
|
||||
* Called when the controller 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.
|
||||
*/
|
||||
void onInit();
|
||||
void (*pFuncOnInit)(void); // Pointer to function called in onInit()
|
||||
|
||||
bool bPollEnable;
|
||||
|
||||
/* Variables to store the buttons */
|
||||
|
@ -195,7 +218,7 @@ private:
|
|||
bool R2Clicked;
|
||||
|
||||
uint8_t readBuf[EP_MAXPKTSIZE]; // General purpose buffer for input data
|
||||
uint8_t writeBuf[EP_MAXPKTSIZE]; // General purpose buffer for output data
|
||||
uint8_t writeBuf[8]; // General purpose buffer for output data
|
||||
|
||||
void readReport(); // read incoming data
|
||||
void printReport(); // print incoming date - Uncomment for debugging
|
||||
|
|
23
address.h
23
address.h
|
@ -14,12 +14,12 @@ Circuits At Home, LTD
|
|||
Web : http://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#if !defined(__ADDRESS_H__)
|
||||
|
||||
#if !defined(_usb_h_) || defined(__ADDRESS_H__)
|
||||
#error "Never include address.h directly; include Usb.h instead"
|
||||
#else
|
||||
#define __ADDRESS_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include "max3421e.h"
|
||||
|
||||
|
||||
/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
|
||||
|
@ -194,7 +194,7 @@ public:
|
|||
|
||||
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
|
||||
/* if (parent != 0 && port == 0)
|
||||
Serial.println("PRT:0"); */
|
||||
USB_HOST_SERIAL.println("PRT:0"); */
|
||||
|
||||
if(parent > 127 || port > 7)
|
||||
return 0;
|
||||
|
@ -219,6 +219,7 @@ public:
|
|||
}
|
||||
|
||||
UsbDeviceAddress addr;
|
||||
addr.devAddress = 0; // Ensure all bits are zero
|
||||
|
||||
addr.bmParent = ((UsbDeviceAddress*) & parent)->bmAddress;
|
||||
|
||||
|
@ -231,12 +232,12 @@ public:
|
|||
}
|
||||
thePool[index].address = *((uint8_t*) & addr);
|
||||
/*
|
||||
Serial.print("Addr:");
|
||||
Serial.print(addr.bmHub, HEX);
|
||||
Serial.print(".");
|
||||
Serial.print(addr.bmParent, HEX);
|
||||
Serial.print(".");
|
||||
Serial.println(addr.bmAddress, HEX);
|
||||
USB_HOST_SERIAL.print("Addr:");
|
||||
USB_HOST_SERIAL.print(addr.bmHub, HEX);
|
||||
USB_HOST_SERIAL.print(".");
|
||||
USB_HOST_SERIAL.print(addr.bmParent, HEX);
|
||||
USB_HOST_SERIAL.print(".");
|
||||
USB_HOST_SERIAL.println(addr.bmAddress, HEX);
|
||||
*/
|
||||
return thePool[index].address;
|
||||
};
|
||||
|
|
38
adk.cpp
38
adk.cpp
|
@ -58,14 +58,18 @@ ready(false) {
|
|||
}
|
||||
}
|
||||
|
||||
uint8_t ADK::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
return Init(parent, port, lowspeed); // Just call Init. Yes, really!
|
||||
}
|
||||
|
||||
/* Connection initialization of an Android phone */
|
||||
uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
||||
|
||||
uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
|
||||
uint8_t rcode;
|
||||
uint8_t num_of_conf; // number of configurations
|
||||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint8_t num_of_conf; // number of configurations
|
||||
|
||||
// get memory address of USB device address pool
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
|
@ -114,7 +118,6 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
|
||||
// Extract Max Packet Size from device descriptor
|
||||
epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
|
||||
|
||||
// Assign new address to the device
|
||||
rcode = pUsb->setAddr(0, 0, bAddress);
|
||||
if (rcode) {
|
||||
|
@ -126,6 +129,8 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
}//if (rcode...
|
||||
|
||||
//USBTRACE2("\r\nAddr:", bAddress);
|
||||
// Spec says you should wait at least 200ms.
|
||||
delay(300);
|
||||
|
||||
p->lowspeed = false;
|
||||
|
||||
|
@ -222,39 +227,52 @@ uint8_t ADK::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
if (rcode) {
|
||||
goto FailSwAcc; //init fails
|
||||
}
|
||||
rcode = -1;
|
||||
rcode = USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET;
|
||||
delay(1000); // Give Android a chance to do its reset. This is a guess, and possibly could be lower.
|
||||
goto SwAttempt; //switch to accessory mode attempted
|
||||
|
||||
/* diagnostic messages */
|
||||
FailGetDevDescr:
|
||||
NotifyFailGetDevDescr();
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetDevDescr(rcode);
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetDevTblEntry:
|
||||
NotifyFailSetDevTblEntry();
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetDevTblEntry(rcode);
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailGetConfDescr:
|
||||
NotifyFailGetConfDescr();
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetConfDescr(rcode);
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetConfDescr:
|
||||
NotifyFailSetConfDescr();
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetConfDescr(rcode);
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailGetProto:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
USBTRACE("\r\ngetProto:");
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSwAcc:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
USBTRACE("\r\nswAcc:");
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
SwAttempt:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
USBTRACE("\r\nAccessory mode switch attempt");
|
||||
// goto Fail;
|
||||
|
||||
//FailOnInit:
|
||||
#endif
|
||||
//FailOnInit:
|
||||
// USBTRACE("OnInit:");
|
||||
// goto Fail;
|
||||
//
|
||||
|
|
23
adk.h
23
adk.h
|
@ -20,26 +20,8 @@ e-mail : support@circuitsathome.com
|
|||
#if !defined(_ADK_H_)
|
||||
#define _ADK_H_
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >=100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "avrpins.h"
|
||||
#include "max3421e.h"
|
||||
#include "usbhost.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "Usb.h"
|
||||
|
||||
#include "printhex.h"
|
||||
#include "hexdump.h"
|
||||
#include "message.h"
|
||||
|
||||
#include "confdescparser.h"
|
||||
|
||||
#define ADK_VID 0x18D1
|
||||
#define ADK_PID 0x2D00
|
||||
#define ADB_PID 0x2D01
|
||||
|
@ -110,6 +92,7 @@ public:
|
|||
|
||||
|
||||
// USBDeviceConfig implementation
|
||||
virtual uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
virtual uint8_t Release();
|
||||
|
||||
|
@ -125,6 +108,10 @@ public:
|
|||
return ready;
|
||||
};
|
||||
|
||||
virtual boolean VIDPIDOK(uint16_t vid, uint16_t pid) {
|
||||
return (vid == ADK_VID && (pid == ADK_PID || pid == ADB_PID));
|
||||
};
|
||||
|
||||
//UsbConfigXtracter implementation
|
||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||
}; //class ADK : public USBDeviceConfig ...
|
||||
|
|
117
avrpins.h
117
avrpins.h
|
@ -17,7 +17,9 @@ e-mail : support@circuitsathome.com
|
|||
|
||||
/* derived from Konstantin Chizhov's AVR port templates */
|
||||
|
||||
#ifndef _avrpins_h_
|
||||
#if !defined(_usb_h_) || defined(_avrpins_h_)
|
||||
#error "Never include avrpins.h directly; include Usb.h instead"
|
||||
#else
|
||||
#define _avrpins_h_
|
||||
|
||||
#if defined(__AVR__)
|
||||
|
@ -25,19 +27,13 @@ e-mail : support@circuitsathome.com
|
|||
// pointers are 16 bits on AVR
|
||||
#define pgm_read_pointer(p) pgm_read_word(p)
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__)
|
||||
/* Uncomment the following if you have Arduino Mega ADK board with MAX3421e built-in */
|
||||
//#define BOARD_MEGA_ADK
|
||||
// Support for these boards needs to be manually activated in settings.h or in a makefile
|
||||
#if !defined(BOARD_MEGA_ADK) && defined(__AVR_ATmega2560__) && USE_UHS_MEGA_ADK
|
||||
#define BOARD_MEGA_ADK
|
||||
#elif !defined(BOARD_BLACK_WIDDOW) && USE_UHS_BLACK_WIDDOW
|
||||
#define BOARD_BLACK_WIDDOW
|
||||
#endif
|
||||
|
||||
/* Uncomment the following if you are using a Teensy 2.0 */
|
||||
//#define BOARD_TEENSY
|
||||
|
||||
/* Uncomment the following if you are using a Sanguino */
|
||||
//#define BOARD_SANGUINO
|
||||
|
||||
#include <avr/io.h>
|
||||
|
||||
#ifdef PORTA
|
||||
#define USE_PORTA
|
||||
#endif
|
||||
|
@ -453,8 +449,7 @@ public:
|
|||
//typedef Tp_Tc<Pb3, Tc2a> P11; //Arduino pin 11
|
||||
|
||||
/* Arduino pin definitions */
|
||||
#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__)
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
// "Mega" Arduino pin numbers
|
||||
|
||||
#define P0 Pe0
|
||||
|
@ -517,10 +512,10 @@ public:
|
|||
#define P53 Pb0
|
||||
#define P54 Pe6 // INT on Arduino ADK
|
||||
|
||||
#endif //"Mega" pin numbers
|
||||
// "Mega" pin numbers
|
||||
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
|
||||
//"Classic" Arduino pin numbers
|
||||
#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
|
||||
// "Classic" Arduino pin numbers
|
||||
|
||||
#define P0 Pd0
|
||||
#define P1 Pd1
|
||||
|
@ -545,9 +540,39 @@ public:
|
|||
#define P18 Pc4
|
||||
#define P19 Pc5
|
||||
|
||||
#endif // "Classic" Arduino pin numbers
|
||||
// "Classic" Arduino pin numbers
|
||||
|
||||
#if !defined(BOARD_TEENSY) && defined(__AVR_ATmega32U4__)
|
||||
#elif defined(CORE_TEENSY) && defined(__AVR_ATmega32U4__)
|
||||
// Teensy 2.0 pin numbers
|
||||
// http://www.pjrc.com/teensy/pinout.html
|
||||
#define P0 Pb0
|
||||
#define P1 Pb1
|
||||
#define P2 Pb2
|
||||
#define P3 Pb3
|
||||
#define P4 Pb7
|
||||
#define P5 Pd0
|
||||
#define P6 Pd1
|
||||
#define P7 Pd2
|
||||
#define P8 Pd3
|
||||
#define P9 Pc6
|
||||
#define P10 Pc7
|
||||
#define P11 Pd6
|
||||
#define P12 Pd7
|
||||
#define P13 Pb4
|
||||
#define P14 Pb5
|
||||
#define P15 Pb6
|
||||
#define P16 Pf7
|
||||
#define P17 Pf6
|
||||
#define P18 Pf5
|
||||
#define P19 Pf4
|
||||
#define P20 Pf1
|
||||
#define P21 Pf0
|
||||
#define P22 Pd4
|
||||
#define P23 Pd5
|
||||
#define P24 Pe6
|
||||
// Teensy 2.0
|
||||
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
// Arduino Leonardo pin numbers
|
||||
|
||||
#define P0 Pd2 // D0 - PD2
|
||||
|
@ -585,39 +610,9 @@ public:
|
|||
#define P28 Pb6 // D28 / D10 - A10 - PB6
|
||||
#define P29 Pd6 // D29 / D12 - A11 - PD6
|
||||
|
||||
#endif // Arduino Leonardo pin numbers
|
||||
// Arduino Leonardo pin numbers
|
||||
|
||||
#if defined(BOARD_TEENSY) && defined(__AVR_ATmega32U4__)
|
||||
// Teensy 2.0 pin numbers
|
||||
// http://www.pjrc.com/teensy/pinout.html
|
||||
#define P0 Pb0
|
||||
#define P1 Pb1
|
||||
#define P2 Pb2
|
||||
#define P3 Pb3
|
||||
#define P4 Pb7
|
||||
#define P5 Pd0
|
||||
#define P6 Pd1
|
||||
#define P7 Pd2
|
||||
#define P8 Pd3
|
||||
#define P9 Pc6
|
||||
#define P10 Pc7
|
||||
#define P11 Pd6
|
||||
#define P12 Pd7
|
||||
#define P13 Pb4
|
||||
#define P14 Pb5
|
||||
#define P15 Pb6
|
||||
#define P16 Pf7
|
||||
#define P17 Pf6
|
||||
#define P18 Pf5
|
||||
#define P19 Pf4
|
||||
#define P20 Pf1
|
||||
#define P21 Pf0
|
||||
#define P22 Pd4
|
||||
#define P23 Pd5
|
||||
#define P24 Pe6
|
||||
#endif // Teensy 2.0
|
||||
|
||||
#if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||
#elif defined(CORE_TEENSY) && (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__))
|
||||
// Teensy++ 2.0 pin numbers
|
||||
// http://www.pjrc.com/teensy/pinout.html
|
||||
#define P0 Pd0
|
||||
|
@ -666,10 +661,9 @@ public:
|
|||
#define P43 Pf5
|
||||
#define P44 Pf6
|
||||
#define P45 Pf7
|
||||
#endif // Teensy++ 2.0
|
||||
// Teensy++ 2.0
|
||||
|
||||
#if !defined(BOARD_SANGUINO) && (defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__))
|
||||
#define BOARD_BALANDUINO
|
||||
#elif defined(ARDUINO_AVR_BALANDUINO) && (defined(__AVR_ATmega644__) || defined(__AVR_ATmega1284P__))
|
||||
// Balanduino pin numbers
|
||||
// http://balanduino.net/
|
||||
#define P0 Pd0 /* 0 - PD0 */
|
||||
|
@ -685,8 +679,8 @@ public:
|
|||
#define P10 Pa3 /* 10 - PA3 */
|
||||
#define P11 Pa4 /* 11 - PA4 */
|
||||
#define P12 Pa5 /* 12 - PA5 */
|
||||
#define P13 Pc0 /* 13 - PC0 */
|
||||
#define P14 Pc1 /* 14 - PC1 */
|
||||
#define P13 Pc1 /* 13 - PC1 */
|
||||
#define P14 Pc0 /* 14 - PC0 */
|
||||
#define P15 Pd2 /* 15 - PD2 */
|
||||
#define P16 Pd3 /* 16 - PD3 */
|
||||
#define P17 Pd4 /* 17 - PD4 */
|
||||
|
@ -704,11 +698,12 @@ public:
|
|||
#define P29 Pb7 /* 29 - PB7 */
|
||||
#define P30 Pa6 /* 30 - PA6 */
|
||||
#define P31 Pa7 /* 31 - PA7 */
|
||||
#endif // Balanduino
|
||||
// Balanduino
|
||||
|
||||
#if defined(BOARD_SANGUINO) && (defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__))
|
||||
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
|
||||
// Sanguino pin numbers
|
||||
// http://sanguino.cc/hardware
|
||||
// Homepage: http://sanguino.cc/hardware
|
||||
// Hardware add-on: https://github.com/Lauszus/Sanguino
|
||||
#define P0 Pb0
|
||||
#define P1 Pb1
|
||||
#define P2 Pb2
|
||||
|
@ -741,7 +736,9 @@ public:
|
|||
#define P29 Pa5
|
||||
#define P30 Pa6
|
||||
#define P31 Pa7
|
||||
#endif // Sanguino
|
||||
// Sanguino
|
||||
|
||||
#endif // Arduino pin definitions
|
||||
|
||||
#endif // __AVR__
|
||||
|
||||
|
|
14
cdcacm.cpp
14
cdcacm.cpp
|
@ -183,26 +183,38 @@ uint8_t ACM::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
return 0;
|
||||
|
||||
FailGetDevDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetDevDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetDevTblEntry:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetDevTblEntry();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailGetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetConfDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetConfDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailOnInit:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
USBTRACE("OnInit:");
|
||||
#endif
|
||||
|
||||
Fail:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFail(rcode);
|
||||
#endif
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
@ -276,7 +288,7 @@ uint8_t ACM::Poll() {
|
|||
// for (uint8_t i=0; i<read; i++)
|
||||
// {
|
||||
// PrintHex<uint8_t>(buf[i]);
|
||||
// Serial.print(" ");
|
||||
// USB_HOST_SERIAL.print(" ");
|
||||
// }
|
||||
// USBTRACE("\r\n");
|
||||
//}
|
||||
|
|
18
cdcacm.h
18
cdcacm.h
|
@ -17,26 +17,8 @@ e-mail : support@circuitsathome.com
|
|||
#if !defined(__CDCACM_H__)
|
||||
#define __CDCACM_H__
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >=100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "avrpins.h"
|
||||
#include "max3421e.h"
|
||||
#include "usbhost.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "Usb.h"
|
||||
|
||||
#include "printhex.h"
|
||||
#include "hexdump.h"
|
||||
#include "message.h"
|
||||
|
||||
#include "confdescparser.h"
|
||||
|
||||
#define bmREQ_CDCOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||
#define bmREQ_CDCIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||
|
||||
|
|
14
cdcftdi.cpp
14
cdcftdi.cpp
|
@ -178,26 +178,38 @@ uint8_t FTDI::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
return 0;
|
||||
|
||||
FailGetDevDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetDevDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetDevTblEntry:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetDevTblEntry();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailGetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetConfDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetConfDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailOnInit:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
USBTRACE("OnInit:");
|
||||
#endif
|
||||
|
||||
Fail:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFail(rcode);
|
||||
#endif
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
@ -247,7 +259,7 @@ uint8_t FTDI::Poll() {
|
|||
|
||||
//if (qNextPollTime <= millis())
|
||||
//{
|
||||
// Serial.println(bAddress, HEX);
|
||||
// USB_HOST_SERIAL.println(bAddress, HEX);
|
||||
|
||||
// qNextPollTime = millis() + 100;
|
||||
//}
|
||||
|
|
18
cdcftdi.h
18
cdcftdi.h
|
@ -17,26 +17,8 @@ e-mail : support@circuitsathome.com
|
|||
#if !defined(__CDCFTDI_H__)
|
||||
#define __CDCFTDI_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "avrpins.h"
|
||||
#include "max3421e.h"
|
||||
#include "usbhost.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "Usb.h"
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >=100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
#include "printhex.h"
|
||||
#include "hexdump.h"
|
||||
#include "message.h"
|
||||
|
||||
#include "confdescparser.h"
|
||||
|
||||
#define bmREQ_FTDI_OUT 0x40
|
||||
#define bmREQ_FTDI_IN 0xc0
|
||||
|
||||
|
|
|
@ -151,30 +151,43 @@ uint8_t PL2303::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
|
||||
USBTRACE("PL configured\r\n");
|
||||
|
||||
bPollEnable = true;
|
||||
//bPollEnable = true;
|
||||
ready = true;
|
||||
return 0;
|
||||
|
||||
FailGetDevDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetDevDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetDevTblEntry:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetDevTblEntry();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailGetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetConfDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetConfDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailOnInit:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
USBTRACE("OnInit:");
|
||||
#endif
|
||||
|
||||
Fail:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFail(rcode);
|
||||
#endif
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
@ -188,7 +201,7 @@ Fail:
|
|||
//
|
||||
// //if (qNextPollTime <= millis())
|
||||
// //{
|
||||
// // Serial.println(bAddress, HEX);
|
||||
// // USB_HOST_SERIAL.println(bAddress, HEX);
|
||||
//
|
||||
// // qNextPollTime = millis() + 100;
|
||||
// //}
|
||||
|
|
|
@ -17,25 +17,6 @@ e-mail : support@circuitsathome.com
|
|||
#if !defined(__CDCPROLIFIC_H__)
|
||||
#define __CDCPROLIFIC_H__
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >=100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "avrpins.h"
|
||||
#include "max3421e.h"
|
||||
#include "usbhost.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "Usb.h"
|
||||
|
||||
#include "printhex.h"
|
||||
#include "hexdump.h"
|
||||
#include "message.h"
|
||||
|
||||
#include "confdescparser.h"
|
||||
#include "cdcacm.h"
|
||||
|
||||
#define PL_VID 0x067B
|
||||
|
|
|
@ -14,16 +14,12 @@ Circuits At Home, LTD
|
|||
Web : http://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#if !defined(__CONFDESCPARSER_H__)
|
||||
#if !defined(_usb_h_) || defined(__CONFDESCPARSER_H__)
|
||||
#error "Never include confdescparser.h directly; include Usb.h instead"
|
||||
#else
|
||||
|
||||
#define __CONFDESCPARSER_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include "message.h"
|
||||
#include "parsetools.h"
|
||||
|
||||
//#include "hid.h"
|
||||
|
||||
class UsbConfigXtracter {
|
||||
public:
|
||||
|
@ -104,10 +100,10 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
|
|||
dscrType = *((uint8_t*) theBuffer.pValue + 1);
|
||||
stateParseDescr = 2;
|
||||
case 2:
|
||||
// This is a sort of hack. Assuming that two bytes are allready in the buffer
|
||||
// This is a sort of hack. Assuming that two bytes are all ready in the buffer
|
||||
// the pointer is positioned two bytes ahead in order for the rest of descriptor
|
||||
// to be read right after the size and the type fields.
|
||||
// This should be used carefuly. varBuffer should be used directly to handle data
|
||||
// This should be used carefully. varBuffer should be used directly to handle data
|
||||
// in the buffer.
|
||||
theBuffer.pValue = varBuffer + 2;
|
||||
stateParseDescr = 3;
|
||||
|
|
|
@ -100,6 +100,8 @@ enum Button {
|
|||
Y = 15,
|
||||
XBOX = 16,
|
||||
SYNC = 17,
|
||||
BLACK = 8, // Available on the original Xbox controller
|
||||
WHITE = 9, // Available on the original Xbox controller
|
||||
/**@}*/
|
||||
};
|
||||
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
*/
|
||||
|
||||
#include <PS3BT.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
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 class in two ways */
|
||||
PS3BT PS3(&Btd); // This will just create the instance
|
||||
|
|
|
@ -6,20 +6,21 @@
|
|||
*/
|
||||
|
||||
#include <PS3BT.h>
|
||||
USB Usb;
|
||||
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
|
||||
PS3BT PS3_1(&Btd);
|
||||
PS3BT PS3_2(&Btd);
|
||||
//PS3BT PS3_3(&Btd); // You can create as many instances as you like, but it will take up a lot of RAM!!
|
||||
#include <usbhub.h>
|
||||
|
||||
PS3BT* PS3[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like
|
||||
USB Usb;
|
||||
USBHub Hub1(&Usb); // Some dongles have a hub inside
|
||||
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
|
||||
PS3BT *PS3[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like, but it will use a lot of RAM!
|
||||
const uint8_t length = sizeof(PS3)/sizeof(PS3[0]); // Get the lenght of the array
|
||||
boolean printAngle[length];
|
||||
boolean oldControllerState[length];
|
||||
|
||||
void setup() {
|
||||
PS3[0] = &PS3_1; // This will point to the first controller
|
||||
PS3[1] = &PS3_2; // This will point to the second controller
|
||||
//PS3[2] = &PS3_3; // You only need to uncomment this if you wanted to use another controller
|
||||
for (uint8_t i=0;i<length;i++) {
|
||||
PS3[i] = new PS3BT(&Btd); // Create the instances
|
||||
PS3[i]->attachOnInit(onInit); // onInit() is called upon a new connection - you can call the function whatever you like
|
||||
}
|
||||
|
||||
Serial.begin(115200);
|
||||
if (Usb.Init() == -1) {
|
||||
|
@ -32,7 +33,6 @@ void loop() {
|
|||
Usb.Task();
|
||||
|
||||
for(uint8_t i=0;i<length;i++) {
|
||||
if(!PS3[i]) continue; // Skip if it hasn't been defined
|
||||
if(PS3[i]->PS3Connected || PS3[i]->PS3NavigationConnected) {
|
||||
if(PS3[i]->getAnalogHat(LeftHatX) > 137 || PS3[i]->getAnalogHat(LeftHatX) < 117 || PS3[i]->getAnalogHat(LeftHatY) > 137 || PS3[i]->getAnalogHat(LeftHatY) < 117 || PS3[i]->getAnalogHat(RightHatX) > 137 || PS3[i]->getAnalogHat(RightHatX) < 117 || PS3[i]->getAnalogHat(RightHatY) > 137 || PS3[i]->getAnalogHat(RightHatY) < 117) {
|
||||
Serial.print(F("\r\nLeftHatX: "));
|
||||
|
@ -58,6 +58,7 @@ void loop() {
|
|||
if(PS3[i]->getButtonClick(PS)) {
|
||||
Serial.print(F("\r\nPS"));
|
||||
PS3[i]->disconnect();
|
||||
oldControllerState[i] = false; // Reset value
|
||||
}
|
||||
else {
|
||||
if(PS3[i]->getButtonClick(TRIANGLE))
|
||||
|
@ -127,3 +128,12 @@ void loop() {
|
|||
//else if(PS3[i]->PS3MoveConnected) {
|
||||
}
|
||||
}
|
||||
|
||||
void onInit() {
|
||||
for (uint8_t i=0;i<length;i++) {
|
||||
if ((PS3[i]->PS3Connected || PS3[i]->PS3NavigationConnected) && !oldControllerState[i]) {
|
||||
oldControllerState[i] = true; // Used to check which is the new controller
|
||||
PS3[i]->setLedOn((LED)i); // Cast directly to LED enum - see: "controllerEnums.h"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,10 @@
|
|||
|
||||
#include <PS3BT.h>
|
||||
#include <SPP.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
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 instances of the bluetooth services in two ways */
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
*/
|
||||
|
||||
#include <SPP.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
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 class in two ways */
|
||||
SPP SerialBT(&Btd); // This will set the name to the defaults: "Arduino" and the pin to "1234"
|
||||
|
|
|
@ -5,26 +5,19 @@
|
|||
*/
|
||||
|
||||
#include <SPP.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
USB Usb;
|
||||
USBHub Hub1(&Usb); // Some dongles have a hub inside
|
||||
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
|
||||
|
||||
// This will set the name to the defaults: "Arduino" and the pin to "1234" for both connections
|
||||
SPP SPP_1(&Btd); // This will allow you to communicate with two SPP devices simultaneously
|
||||
SPP SPP_2(&Btd);
|
||||
//SPP SPP_3(&Btd); // You can create as many instances as you like, but it will take up a lot of RAM!!
|
||||
|
||||
// You can also set the name and pin like so
|
||||
//SPP SerialBT(&Btd, "Lauszus's Arduino","0000");
|
||||
|
||||
SPP* SerialBT[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like
|
||||
SPP* SerialBT[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like, but it will use a lot of RAM!
|
||||
const uint8_t length = sizeof(SerialBT)/sizeof(SerialBT[0]); // Get the lenght of the array
|
||||
boolean firstMessage[length] = { true }; // Set all to true
|
||||
uint8_t buffer[50];
|
||||
|
||||
void setup() {
|
||||
SerialBT[0] = &SPP_1; // This will point to the first instance
|
||||
SerialBT[1] = &SPP_2; // This will point to the second instance
|
||||
//SerialBT[2] = &SPP_3; // You only need to uncomment this if you wanted to use another instance
|
||||
for(uint8_t i=0;i<length;i++)
|
||||
SerialBT[i] = new SPP(&Btd); // This will set the name to the default: "Arduino" and the pin to "1234" for all connections
|
||||
|
||||
Serial.begin(115200);
|
||||
if (Usb.Init() == -1) {
|
||||
|
@ -51,7 +44,7 @@ void loop() {
|
|||
if(Serial.available()) {
|
||||
delay(10); // Wait for the rest of the data to arrive
|
||||
uint8_t i = 0;
|
||||
while(Serial.available()) // Read the data
|
||||
while(Serial.available() && i < sizeof(buffer)) // Read the data
|
||||
buffer[i++] = Serial.read();
|
||||
/*
|
||||
Set the connection you want to send to using the first character
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
*/
|
||||
|
||||
#include <Wii.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
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 class in two ways */
|
||||
WII Wii(&Btd,PAIR); // This will start an inquiry and then pair with your Wiimote - you only have to do this once
|
||||
|
|
|
@ -2,24 +2,28 @@
|
|||
Example sketch for the Wii libary showing the IR camera functionality. This example
|
||||
is for the Bluetooth Wii library developed for the USB shield from Circuits@Home
|
||||
|
||||
Created by Allan Glover and includes much from what Kristian Lauszus wrote in the existing
|
||||
Wii example. Contact Kristian: http://blog.tkjelectronics.dk/ or send email at kristianl@tkjelectronics.com.
|
||||
Created by Allan Glover and Kristian Lauszus.
|
||||
Contact Kristian: http://blog.tkjelectronics.dk/ or send an email at kristianl@tkjelectronics.com.
|
||||
Contact Allan at adglover9.81@gmail.com
|
||||
|
||||
To test the Wiimote IR camera, you will need access to an IR source. Sunlight will work but is not ideal.
|
||||
The simpleist solution is to use the Wii sensor bar, i.e. emitter bar, supplied by the Wii system. Otherwise,
|
||||
wire up a IR LED yourself.
|
||||
The simpleist solution is to use the Wii sensor bar, i.e. emitter bar, supplied by the Wii system.
|
||||
Otherwise, wire up a IR LED yourself.
|
||||
*/
|
||||
|
||||
#include <Wii.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
#ifndef WIICAMERA // Used to check if WIICAMERA is defined
|
||||
#error "Uncomment WIICAMERA in Wii.h to use this example"
|
||||
#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 class in two ways */
|
||||
WII Wii(&Btd,PAIR); // This will start an inquiry and then pair with your Wiimote - you only have to do this once
|
||||
//WII Wii(&Btd); // After the wiimote pairs once with the line of code above, you can simply create the instance like so and re upload and then press any button on the Wiimote
|
||||
//WII Wii(&Btd); // After the Wiimote pairs once with the line of code above, you can simply create the instance like so and re upload and then press any button on the Wiimote
|
||||
|
||||
bool printAngle;
|
||||
uint8_t printObjects;
|
||||
|
@ -109,7 +113,7 @@ void loop() {
|
|||
}
|
||||
}
|
||||
}
|
||||
if(printAngle) { // There is no extension bytes avaliable, so the Motionplus or Nunchuck can't be read
|
||||
if(printAngle) { // There is no extension bytes available, so the MotionPlus or Nunchuck can't be read
|
||||
Serial.print(F("\r\nPitch: "));
|
||||
Serial.print(Wii.getPitch());
|
||||
Serial.print(F("\tRoll: "));
|
||||
|
|
|
@ -6,21 +6,21 @@
|
|||
*/
|
||||
|
||||
#include <Wii.h>
|
||||
USB Usb;
|
||||
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
|
||||
//WII Wii(&Btd,PAIR); // You will have to pair each controller with the dongle before you can define the instances like below
|
||||
WII Wii_1(&Btd);
|
||||
WII Wii_2(&Btd);
|
||||
//WII Wii_3(&Btd); // You can create as many instances as you like, but it will take up a lot of RAM!!
|
||||
#include <usbhub.h>
|
||||
|
||||
WII* Wii[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like
|
||||
USB Usb;
|
||||
USBHub Hub1(&Usb); // Some dongles have a hub inside
|
||||
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so
|
||||
WII *Wii[2]; // We will use this pointer to store the two instance, you can easily make it larger if you like, but it will use a lot of RAM!
|
||||
const uint8_t length = sizeof(Wii)/sizeof(Wii[0]); // Get the lenght of the array
|
||||
bool printAngle[length];
|
||||
boolean printAngle[length];
|
||||
boolean oldControllerState[length];
|
||||
|
||||
void setup() {
|
||||
Wii[0] = &Wii_1;
|
||||
Wii[1] = &Wii_2;
|
||||
//Wii[2] = &Wii_3; // You only need to uncomment this if you wanted to use another controller
|
||||
for (uint8_t i=0;i<length;i++) {
|
||||
Wii[i] = new WII(&Btd); // You will have to pair each controller with the dongle before you can define the instances like so, just add PAIR as the second argument
|
||||
Wii[i]->attachOnInit(onInit); // onInit() is called upon a new connection - you can call the function whatever you like
|
||||
}
|
||||
|
||||
Serial.begin(115200);
|
||||
if (Usb.Init() == -1) {
|
||||
|
@ -33,12 +33,11 @@ void loop() {
|
|||
Usb.Task();
|
||||
|
||||
for(uint8_t i=0;i<length;i++) {
|
||||
if(!Wii[i]) continue; // Skip if it hasn't been defined
|
||||
if(Wii[i]->wiimoteConnected) {
|
||||
if(Wii[i]->getButtonClick(HOME)) { // You can use getButtonPress to see if the button is held down
|
||||
Serial.print(F("\r\nHOME"));
|
||||
Wii[i]->disconnect();
|
||||
delay(1000); // This delay is needed for some Wiimotes, so it doesn't try to reconnect right away
|
||||
oldControllerState[i] = false; // Reset value
|
||||
}
|
||||
else {
|
||||
if(Wii[i]->getButtonClick(LEFT)) {
|
||||
|
@ -112,3 +111,12 @@ void loop() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onInit() {
|
||||
for (uint8_t i=0;i<length;i++) {
|
||||
if (Wii[i]->wiimoteConnected && !oldControllerState[i]) {
|
||||
oldControllerState[i] = true; // Used to check which is the new controller
|
||||
Wii[i]->setLedOn((LED)i); // Cast directly to LED enum - see: "controllerEnums.h"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
*/
|
||||
|
||||
#include <Wii.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
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 class in two ways */
|
||||
WII Wii(&Btd,PAIR); // This will start an inquiry and then pair with your Wiimote - you only have to do this once
|
||||
|
|
|
@ -1,19 +1,5 @@
|
|||
#include <avr/pgmspace.h>
|
||||
|
||||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
#include <hidboot.h>
|
||||
|
||||
#include <printhex.h>
|
||||
#include <message.h>
|
||||
#include <hexdump.h>
|
||||
#include <parsetools.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
class KbdRptParser : public KeyboardReportParser
|
||||
{
|
||||
|
|
30
examples/HID/USBHIDBootKbdAndMouse/Makefile
Normal file
30
examples/HID/USBHIDBootKbdAndMouse/Makefile
Normal file
|
@ -0,0 +1,30 @@
|
|||
#
|
||||
# These are set for a mega 1280 + quadram plus my serial patch.
|
||||
# If you lack quadram, or want to disable LFN, just change _FS_TINY=1 _USE_LFN=0
|
||||
#
|
||||
# If your board is a mega 2560 uncomment the following two lines
|
||||
# BOARD = mega2560
|
||||
# PROGRAMMER = wiring
|
||||
# ...and then comment out the following two lines
|
||||
BOARD = mega
|
||||
PROGRAMMER = arduino
|
||||
|
||||
# set your Arduino tty port here
|
||||
PORT = /dev/ttyUSB0
|
||||
|
||||
|
||||
# uncomment the next line to enable debugging
|
||||
#EXTRA_FLAGS += -D DEBUG_USB_HOST=1
|
||||
|
||||
#
|
||||
# Advanced debug on Serial3
|
||||
#
|
||||
|
||||
# uncomment the next line to enable debug on Serial3
|
||||
#EXTRA_FLAGS += -D USB_HOST_SERIAL=Serial3
|
||||
|
||||
# The following are the libraries used.
|
||||
LIB_DIRS =
|
||||
LIB_DIRS += ../libraries/USB_Host_Shield_2_0
|
||||
# And finally, the part that brings everything together for you.
|
||||
include ../Arduino_Makefile_master/_Makefile.master
|
170
examples/HID/USBHIDBootKbdAndMouse/USBHIDBootKbdAndMouse.ino
Normal file
170
examples/HID/USBHIDBootKbdAndMouse/USBHIDBootKbdAndMouse.ino
Normal file
|
@ -0,0 +1,170 @@
|
|||
#include <hidboot.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
class MouseRptParser : public MouseReportParser
|
||||
{
|
||||
protected:
|
||||
virtual void OnMouseMove (MOUSEINFO *mi);
|
||||
virtual void OnLeftButtonUp (MOUSEINFO *mi);
|
||||
virtual void OnLeftButtonDown (MOUSEINFO *mi);
|
||||
virtual void OnRightButtonUp (MOUSEINFO *mi);
|
||||
virtual void OnRightButtonDown (MOUSEINFO *mi);
|
||||
virtual void OnMiddleButtonUp (MOUSEINFO *mi);
|
||||
virtual void OnMiddleButtonDown (MOUSEINFO *mi);
|
||||
};
|
||||
void MouseRptParser::OnMouseMove(MOUSEINFO *mi)
|
||||
{
|
||||
Serial.print("dx=");
|
||||
Serial.print(mi->dX, DEC);
|
||||
Serial.print(" dy=");
|
||||
Serial.println(mi->dY, DEC);
|
||||
};
|
||||
void MouseRptParser::OnLeftButtonUp (MOUSEINFO *mi)
|
||||
{
|
||||
Serial.println("L Butt Up");
|
||||
};
|
||||
void MouseRptParser::OnLeftButtonDown (MOUSEINFO *mi)
|
||||
{
|
||||
Serial.println("L Butt Dn");
|
||||
};
|
||||
void MouseRptParser::OnRightButtonUp (MOUSEINFO *mi)
|
||||
{
|
||||
Serial.println("R Butt Up");
|
||||
};
|
||||
void MouseRptParser::OnRightButtonDown (MOUSEINFO *mi)
|
||||
{
|
||||
Serial.println("R Butt Dn");
|
||||
};
|
||||
void MouseRptParser::OnMiddleButtonUp (MOUSEINFO *mi)
|
||||
{
|
||||
Serial.println("M Butt Up");
|
||||
};
|
||||
void MouseRptParser::OnMiddleButtonDown (MOUSEINFO *mi)
|
||||
{
|
||||
Serial.println("M Butt Dn");
|
||||
};
|
||||
|
||||
class KbdRptParser : public KeyboardReportParser
|
||||
{
|
||||
void PrintKey(uint8_t mod, uint8_t key);
|
||||
|
||||
protected:
|
||||
virtual void OnControlKeysChanged(uint8_t before, uint8_t after);
|
||||
|
||||
virtual void OnKeyDown (uint8_t mod, uint8_t key);
|
||||
virtual void OnKeyUp (uint8_t mod, uint8_t key);
|
||||
virtual void OnKeyPressed(uint8_t key);
|
||||
};
|
||||
|
||||
void KbdRptParser::PrintKey(uint8_t m, uint8_t key)
|
||||
{
|
||||
MODIFIERKEYS mod;
|
||||
*((uint8_t*)&mod) = m;
|
||||
Serial.print((mod.bmLeftCtrl == 1) ? "C" : " ");
|
||||
Serial.print((mod.bmLeftShift == 1) ? "S" : " ");
|
||||
Serial.print((mod.bmLeftAlt == 1) ? "A" : " ");
|
||||
Serial.print((mod.bmLeftGUI == 1) ? "G" : " ");
|
||||
|
||||
Serial.print(" >");
|
||||
PrintHex<uint8_t>(key, 0x80);
|
||||
Serial.print("< ");
|
||||
|
||||
Serial.print((mod.bmRightCtrl == 1) ? "C" : " ");
|
||||
Serial.print((mod.bmRightShift == 1) ? "S" : " ");
|
||||
Serial.print((mod.bmRightAlt == 1) ? "A" : " ");
|
||||
Serial.println((mod.bmRightGUI == 1) ? "G" : " ");
|
||||
};
|
||||
|
||||
void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key)
|
||||
{
|
||||
Serial.print("DN ");
|
||||
PrintKey(mod, key);
|
||||
uint8_t c = OemToAscii(mod, key);
|
||||
|
||||
if (c)
|
||||
OnKeyPressed(c);
|
||||
}
|
||||
|
||||
void KbdRptParser::OnControlKeysChanged(uint8_t before, uint8_t after) {
|
||||
|
||||
MODIFIERKEYS beforeMod;
|
||||
*((uint8_t*)&beforeMod) = before;
|
||||
|
||||
MODIFIERKEYS afterMod;
|
||||
*((uint8_t*)&afterMod) = after;
|
||||
|
||||
if (beforeMod.bmLeftCtrl != afterMod.bmLeftCtrl) {
|
||||
Serial.println("LeftCtrl changed");
|
||||
}
|
||||
if (beforeMod.bmLeftShift != afterMod.bmLeftShift) {
|
||||
Serial.println("LeftShift changed");
|
||||
}
|
||||
if (beforeMod.bmLeftAlt != afterMod.bmLeftAlt) {
|
||||
Serial.println("LeftAlt changed");
|
||||
}
|
||||
if (beforeMod.bmLeftGUI != afterMod.bmLeftGUI) {
|
||||
Serial.println("LeftGUI changed");
|
||||
}
|
||||
|
||||
if (beforeMod.bmRightCtrl != afterMod.bmRightCtrl) {
|
||||
Serial.println("RightCtrl changed");
|
||||
}
|
||||
if (beforeMod.bmRightShift != afterMod.bmRightShift) {
|
||||
Serial.println("RightShift changed");
|
||||
}
|
||||
if (beforeMod.bmRightAlt != afterMod.bmRightAlt) {
|
||||
Serial.println("RightAlt changed");
|
||||
}
|
||||
if (beforeMod.bmRightGUI != afterMod.bmRightGUI) {
|
||||
Serial.println("RightGUI changed");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void KbdRptParser::OnKeyUp(uint8_t mod, uint8_t key)
|
||||
{
|
||||
Serial.print("UP ");
|
||||
PrintKey(mod, key);
|
||||
}
|
||||
|
||||
void KbdRptParser::OnKeyPressed(uint8_t key)
|
||||
{
|
||||
Serial.print("ASCII: ");
|
||||
Serial.println((char)key);
|
||||
};
|
||||
|
||||
USB Usb;
|
||||
USBHub Hub(&Usb);
|
||||
|
||||
HIDBoot<HID_PROTOCOL_KEYBOARD | HID_PROTOCOL_MOUSE> HidComposite(&Usb);
|
||||
HIDBoot<HID_PROTOCOL_KEYBOARD> HidKeyboard(&Usb);
|
||||
HIDBoot<HID_PROTOCOL_MOUSE> HidMouse(&Usb);
|
||||
|
||||
//uint32_t next_time;
|
||||
|
||||
KbdRptParser KbdPrs;
|
||||
MouseRptParser MousePrs;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin( 115200 );
|
||||
Serial.println("Start");
|
||||
|
||||
if (Usb.Init() == -1)
|
||||
Serial.println("OSC did not start.");
|
||||
|
||||
delay( 200 );
|
||||
|
||||
//next_time = millis() + 5000;
|
||||
|
||||
HidComposite.SetReportParser(0, (HIDReportParser*)&KbdPrs);
|
||||
HidComposite.SetReportParser(1,(HIDReportParser*)&MousePrs);
|
||||
HidKeyboard.SetReportParser(0, (HIDReportParser*)&KbdPrs);
|
||||
HidMouse.SetReportParser(0,(HIDReportParser*)&MousePrs);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
Usb.Task();
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
#!/bin/bash -x
|
||||
|
||||
#
|
||||
# Generated - do not edit!
|
||||
#
|
||||
|
||||
# Macros
|
||||
TOP=`pwd`
|
||||
CND_PLATFORM=AVR-Linux-x86
|
||||
CND_CONF=Default
|
||||
CND_DISTDIR=dist
|
||||
CND_BUILDDIR=build
|
||||
NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging
|
||||
TMPDIRNAME=tmp-packaging
|
||||
OUTPUT_PATH=MissingOutputInProject
|
||||
OUTPUT_BASENAME=MissingOutputInProject
|
||||
PACKAGE_TOP_DIR=USBHIDBootKbdAndMouse/
|
||||
|
||||
# Functions
|
||||
function checkReturnCode
|
||||
{
|
||||
rc=$?
|
||||
if [ $rc != 0 ]
|
||||
then
|
||||
exit $rc
|
||||
fi
|
||||
}
|
||||
function makeDirectory
|
||||
# $1 directory path
|
||||
# $2 permission (optional)
|
||||
{
|
||||
mkdir -p "$1"
|
||||
checkReturnCode
|
||||
if [ "$2" != "" ]
|
||||
then
|
||||
chmod $2 "$1"
|
||||
checkReturnCode
|
||||
fi
|
||||
}
|
||||
function copyFileToTmpDir
|
||||
# $1 from-file path
|
||||
# $2 to-file path
|
||||
# $3 permission
|
||||
{
|
||||
cp "$1" "$2"
|
||||
checkReturnCode
|
||||
if [ "$3" != "" ]
|
||||
then
|
||||
chmod $3 "$2"
|
||||
checkReturnCode
|
||||
fi
|
||||
}
|
||||
|
||||
# Setup
|
||||
cd "${TOP}"
|
||||
mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package
|
||||
rm -rf ${NBTMPDIR}
|
||||
mkdir -p ${NBTMPDIR}
|
||||
|
||||
# Copy files and create directories and links
|
||||
cd "${TOP}"
|
||||
makeDirectory "${NBTMPDIR}/USBHIDBootKbdAndMouse"
|
||||
copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755
|
||||
|
||||
|
||||
# Generate tar file
|
||||
cd "${TOP}"
|
||||
rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/USBHIDBootKbdAndMouse.tar
|
||||
cd ${NBTMPDIR}
|
||||
tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/USBHIDBootKbdAndMouse.tar *
|
||||
checkReturnCode
|
||||
|
||||
# Cleanup
|
||||
cd "${TOP}"
|
||||
rm -rf ${NBTMPDIR}
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configurationDescriptor version="80">
|
||||
<logicalFolder name="root" displayName="root" projectFiles="true" kind="ROOT">
|
||||
<df name="USBHIDBootKbd" root=".">
|
||||
<df name="build">
|
||||
<in>USBHIDBootKbdAndMouse_ino.cpp</in>
|
||||
</df>
|
||||
<in>USBHIDBootKbdAndMouse.ino</in>
|
||||
</df>
|
||||
<logicalFolder name="ExternalFiles"
|
||||
displayName="Important Files"
|
||||
projectFiles="false"
|
||||
kind="IMPORTANT_FILES_FOLDER">
|
||||
<itemPath>Makefile</itemPath>
|
||||
</logicalFolder>
|
||||
</logicalFolder>
|
||||
<sourceFolderFilter>^(nbproject)$</sourceFolderFilter>
|
||||
<sourceRootList>
|
||||
<Elem>.</Elem>
|
||||
</sourceRootList>
|
||||
<projectmakefile>Makefile</projectmakefile>
|
||||
<confs>
|
||||
<conf name="Default" type="0">
|
||||
<toolsSet>
|
||||
<remote-sources-mode>LOCAL_SOURCES</remote-sources-mode>
|
||||
<compilerSet>default</compilerSet>
|
||||
</toolsSet>
|
||||
<makefileType>
|
||||
<makeTool>
|
||||
<buildCommandWorkingDir>.</buildCommandWorkingDir>
|
||||
<buildCommand>${MAKE} -f Makefile</buildCommand>
|
||||
<cleanCommand>${MAKE} -f Makefile clean</cleanCommand>
|
||||
<executablePath></executablePath>
|
||||
</makeTool>
|
||||
</makefileType>
|
||||
</conf>
|
||||
</confs>
|
||||
</configurationDescriptor>
|
23
examples/HID/USBHIDBootKbdAndMouse/nbproject/project.xml
Normal file
23
examples/HID/USBHIDBootKbdAndMouse/nbproject/project.xml
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||
<type>org.netbeans.modules.cnd.makeproject</type>
|
||||
<configuration>
|
||||
<data xmlns="http://www.netbeans.org/ns/make-project/1">
|
||||
<name>USBHIDBootKbdAndMouse</name>
|
||||
<c-extensions/>
|
||||
<cpp-extensions>cpp,ino</cpp-extensions>
|
||||
<header-extensions/>
|
||||
<sourceEncoding>UTF-8</sourceEncoding>
|
||||
<make-dep-projects/>
|
||||
<sourceRootList>
|
||||
<sourceRootElem>.</sourceRootElem>
|
||||
</sourceRootList>
|
||||
<confList>
|
||||
<confElem>
|
||||
<name>Default</name>
|
||||
<type>0</type>
|
||||
</confElem>
|
||||
</confList>
|
||||
</data>
|
||||
</configuration>
|
||||
</project>
|
|
@ -1,17 +1,5 @@
|
|||
#include <avr/pgmspace.h>
|
||||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
#include <hidboot.h>
|
||||
#include <printhex.h>
|
||||
#include <message.h>
|
||||
#include <hexdump.h>
|
||||
#include <parsetools.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
class MouseRptParser : public MouseReportParser
|
||||
{
|
30
examples/HID/USBHIDJoystick/Makefile
Normal file
30
examples/HID/USBHIDJoystick/Makefile
Normal file
|
@ -0,0 +1,30 @@
|
|||
#
|
||||
# These are set for a mega 1280 + quadram plus my serial patch.
|
||||
# If you lack quadram, or want to disable LFN, just change _FS_TINY=1 _USE_LFN=0
|
||||
#
|
||||
# If your board is a mega 2560 uncomment the following two lines
|
||||
# BOARD = mega2560
|
||||
# PROGRAMMER = wiring
|
||||
# ...and then comment out the following two lines
|
||||
BOARD = mega
|
||||
PROGRAMMER = arduino
|
||||
|
||||
# set your Arduino tty port here
|
||||
PORT = /dev/ttyUSB0
|
||||
|
||||
|
||||
# uncomment the next line to enable debugging
|
||||
#EXTRA_FLAGS += -D DEBUG_USB_HOST=1
|
||||
|
||||
#
|
||||
# Advanced debug on Serial3
|
||||
#
|
||||
|
||||
# uncomment the next line to enable debug on Serial3
|
||||
#EXTRA_FLAGS += -D USB_HOST_SERIAL=Serial3
|
||||
|
||||
# The following are the libraries used.
|
||||
LIB_DIRS =
|
||||
LIB_DIRS += ../libraries/USB_Host_Shield_2_0
|
||||
# And finally, the part that brings everything together for you.
|
||||
include ../Arduino_Makefile_master/_Makefile.master
|
|
@ -1,46 +1,29 @@
|
|||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
#include <hid.h>
|
||||
#include <hiduniversal.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
#include "hidjoystickrptparser.h"
|
||||
|
||||
#include <printhex.h>
|
||||
#include <message.h>
|
||||
#include <hexdump.h>
|
||||
#include <parsetools.h>
|
||||
|
||||
USB Usb;
|
||||
USBHub Hub(&Usb);
|
||||
HIDUniversal Hid(&Usb);
|
||||
JoystickEvents JoyEvents;
|
||||
JoystickReportParser Joy(&JoyEvents);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin( 115200 );
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Start");
|
||||
|
||||
if (Usb.Init() == -1)
|
||||
Serial.println("OSC did not start.");
|
||||
|
||||
delay( 200 );
|
||||
delay(200);
|
||||
|
||||
if (!Hid.SetReportParser(0, &Joy))
|
||||
ErrorMessage<uint8_t>(PSTR("SetReportParser"), 1 );
|
||||
ErrorMessage<uint8_t > (PSTR("SetReportParser"), 1);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
void loop() {
|
||||
Usb.Task();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,39 +1,34 @@
|
|||
#include "hidjoystickrptparser.h"
|
||||
|
||||
JoystickReportParser::JoystickReportParser(JoystickEvents *evt) :
|
||||
joyEvents(evt),
|
||||
oldHat(0xDE),
|
||||
oldButtons(0)
|
||||
{
|
||||
for (uint8_t i=0; i<RPT_GEMEPAD_LEN; i++)
|
||||
joyEvents(evt),
|
||||
oldHat(0xDE),
|
||||
oldButtons(0) {
|
||||
for (uint8_t i = 0; i < RPT_GEMEPAD_LEN; i++)
|
||||
oldPad[i] = 0xD;
|
||||
}
|
||||
|
||||
void JoystickReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
|
||||
{
|
||||
void JoystickReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
|
||||
bool match = true;
|
||||
|
||||
// Checking if there are changes in report since the method was last called
|
||||
for (uint8_t i=0; i<RPT_GEMEPAD_LEN; i++)
|
||||
if (buf[i] != oldPad[i])
|
||||
{
|
||||
for (uint8_t i = 0; i < RPT_GEMEPAD_LEN; i++)
|
||||
if (buf[i] != oldPad[i]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Calling Game Pad event handler
|
||||
if (!match && joyEvents)
|
||||
{
|
||||
if (!match && joyEvents) {
|
||||
joyEvents->OnGamePadChanged((const GamePadEventData*)buf);
|
||||
|
||||
for (uint8_t i=0; i<RPT_GEMEPAD_LEN; i++) oldPad[i] = buf[i];
|
||||
for (uint8_t i = 0; i < RPT_GEMEPAD_LEN; i++) oldPad[i] = buf[i];
|
||||
}
|
||||
|
||||
uint8_t hat = (buf[5] & 0xF);
|
||||
|
||||
// Calling Hat Switch event handler
|
||||
if (hat != oldHat && joyEvents)
|
||||
{
|
||||
if (hat != oldHat && joyEvents) {
|
||||
joyEvents->OnHatSwitch(hat);
|
||||
oldHat = hat;
|
||||
}
|
||||
|
@ -44,52 +39,46 @@ void JoystickReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t
|
|||
uint16_t changes = (buttons ^ oldButtons);
|
||||
|
||||
// Calling Button Event Handler for every button changed
|
||||
if (changes)
|
||||
{
|
||||
for (uint8_t i=0; i<0x0C; i++)
|
||||
{
|
||||
if (changes) {
|
||||
for (uint8_t i = 0; i < 0x0C; i++) {
|
||||
uint16_t mask = (0x0001 << i);
|
||||
|
||||
if (((mask & changes) > 0) && joyEvents)
|
||||
if ((buttons & mask) > 0)
|
||||
joyEvents->OnButtonDn(i+1);
|
||||
joyEvents->OnButtonDn(i + 1);
|
||||
else
|
||||
joyEvents->OnButtonUp(i+1);
|
||||
joyEvents->OnButtonUp(i + 1);
|
||||
}
|
||||
oldButtons = buttons;
|
||||
}
|
||||
}
|
||||
|
||||
void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt)
|
||||
{
|
||||
Serial.print("X: ");
|
||||
PrintHex<uint8_t>(evt->X, 0x80);
|
||||
Serial.print("\tY: ");
|
||||
PrintHex<uint8_t>(evt->Y, 0x80);
|
||||
Serial.print("\tZ: ");
|
||||
PrintHex<uint8_t>(evt->Z1, 0x80);
|
||||
Serial.print("\tZ: ");
|
||||
PrintHex<uint8_t>(evt->Z2, 0x80);
|
||||
void JoystickEvents::OnGamePadChanged(const GamePadEventData *evt) {
|
||||
Serial.print("X1: ");
|
||||
PrintHex<uint8_t > (evt->X, 0x80);
|
||||
Serial.print("\tY1: ");
|
||||
PrintHex<uint8_t > (evt->Y, 0x80);
|
||||
Serial.print("\tX2: ");
|
||||
PrintHex<uint8_t > (evt->Z1, 0x80);
|
||||
Serial.print("\tY2: ");
|
||||
PrintHex<uint8_t > (evt->Z2, 0x80);
|
||||
Serial.print("\tRz: ");
|
||||
PrintHex<uint8_t>(evt->Rz, 0x80);
|
||||
PrintHex<uint8_t > (evt->Rz, 0x80);
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
void JoystickEvents::OnHatSwitch(uint8_t hat)
|
||||
{
|
||||
void JoystickEvents::OnHatSwitch(uint8_t hat) {
|
||||
Serial.print("Hat Switch: ");
|
||||
PrintHex<uint8_t>(hat, 0x80);
|
||||
PrintHex<uint8_t > (hat, 0x80);
|
||||
Serial.println("");
|
||||
}
|
||||
|
||||
void JoystickEvents::OnButtonUp(uint8_t but_id)
|
||||
{
|
||||
void JoystickEvents::OnButtonUp(uint8_t but_id) {
|
||||
Serial.print("Up: ");
|
||||
Serial.println(but_id, DEC);
|
||||
}
|
||||
|
||||
void JoystickEvents::OnButtonDn(uint8_t but_id)
|
||||
{
|
||||
void JoystickEvents::OnButtonDn(uint8_t but_id) {
|
||||
Serial.print("Dn: ");
|
||||
Serial.println(but_id, DEC);
|
||||
}
|
||||
|
|
|
@ -1,33 +1,13 @@
|
|||
#if !defined(__HIDJOYSTICKRPTPARSER_H__)
|
||||
#define __HIDJOYSTICKRPTPARSER_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "avrpins.h"
|
||||
#include "max3421e.h"
|
||||
#include "usbhost.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "Usb.h"
|
||||
#include <hid.h>
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >=100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
#include "printhex.h"
|
||||
#include "hexdump.h"
|
||||
#include "message.h"
|
||||
#include "confdescparser.h"
|
||||
#include "hid.h"
|
||||
|
||||
struct GamePadEventData
|
||||
{
|
||||
struct GamePadEventData {
|
||||
uint8_t X, Y, Z1, Z2, Rz;
|
||||
};
|
||||
|
||||
class JoystickEvents
|
||||
{
|
||||
class JoystickEvents {
|
||||
public:
|
||||
virtual void OnGamePadChanged(const GamePadEventData *evt);
|
||||
virtual void OnHatSwitch(uint8_t hat);
|
||||
|
@ -37,8 +17,7 @@ public:
|
|||
|
||||
#define RPT_GEMEPAD_LEN 5
|
||||
|
||||
class JoystickReportParser : public HIDReportParser
|
||||
{
|
||||
class JoystickReportParser : public HIDReportParser {
|
||||
JoystickEvents *joyEvents;
|
||||
|
||||
uint8_t oldPad[RPT_GEMEPAD_LEN];
|
||||
|
|
75
examples/HID/USBHIDJoystick/nbproject/Package-Default.bash
Normal file
75
examples/HID/USBHIDJoystick/nbproject/Package-Default.bash
Normal file
|
@ -0,0 +1,75 @@
|
|||
#!/bin/bash -x
|
||||
|
||||
#
|
||||
# Generated - do not edit!
|
||||
#
|
||||
|
||||
# Macros
|
||||
TOP=`pwd`
|
||||
CND_PLATFORM=AVR-Linux-x86
|
||||
CND_CONF=Default
|
||||
CND_DISTDIR=dist
|
||||
CND_BUILDDIR=build
|
||||
NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging
|
||||
TMPDIRNAME=tmp-packaging
|
||||
OUTPUT_PATH=MissingOutputInProject
|
||||
OUTPUT_BASENAME=MissingOutputInProject
|
||||
PACKAGE_TOP_DIR=USBHIDJoystick/
|
||||
|
||||
# Functions
|
||||
function checkReturnCode
|
||||
{
|
||||
rc=$?
|
||||
if [ $rc != 0 ]
|
||||
then
|
||||
exit $rc
|
||||
fi
|
||||
}
|
||||
function makeDirectory
|
||||
# $1 directory path
|
||||
# $2 permission (optional)
|
||||
{
|
||||
mkdir -p "$1"
|
||||
checkReturnCode
|
||||
if [ "$2" != "" ]
|
||||
then
|
||||
chmod $2 "$1"
|
||||
checkReturnCode
|
||||
fi
|
||||
}
|
||||
function copyFileToTmpDir
|
||||
# $1 from-file path
|
||||
# $2 to-file path
|
||||
# $3 permission
|
||||
{
|
||||
cp "$1" "$2"
|
||||
checkReturnCode
|
||||
if [ "$3" != "" ]
|
||||
then
|
||||
chmod $3 "$2"
|
||||
checkReturnCode
|
||||
fi
|
||||
}
|
||||
|
||||
# Setup
|
||||
cd "${TOP}"
|
||||
mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package
|
||||
rm -rf ${NBTMPDIR}
|
||||
mkdir -p ${NBTMPDIR}
|
||||
|
||||
# Copy files and create directories and links
|
||||
cd "${TOP}"
|
||||
makeDirectory "${NBTMPDIR}/USBHIDJoystick"
|
||||
copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755
|
||||
|
||||
|
||||
# Generate tar file
|
||||
cd "${TOP}"
|
||||
rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/USBHIDJoystick.tar
|
||||
cd ${NBTMPDIR}
|
||||
tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/USBHIDJoystick.tar *
|
||||
checkReturnCode
|
||||
|
||||
# Cleanup
|
||||
cd "${TOP}"
|
||||
rm -rf ${NBTMPDIR}
|
55
examples/HID/USBHIDJoystick/nbproject/configurations.xml
Normal file
55
examples/HID/USBHIDJoystick/nbproject/configurations.xml
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configurationDescriptor version="80">
|
||||
<logicalFolder name="root" displayName="root" projectFiles="true" kind="ROOT">
|
||||
<df name="USBHIDJoystick" root=".">
|
||||
<df name="build">
|
||||
<in>CDC.lst</in>
|
||||
<in>HID.lst</in>
|
||||
<in>HardwareSerial.lst</in>
|
||||
<in>IPAddress.lst</in>
|
||||
<in>Print.lst</in>
|
||||
<in>Stream.lst</in>
|
||||
<in>Tone.lst</in>
|
||||
<in>USBCore.lst</in>
|
||||
<in>WInterrupts.lst</in>
|
||||
<in>WMath.lst</in>
|
||||
<in>WString.lst</in>
|
||||
<in>wiring.lst</in>
|
||||
<in>wiring_analog.lst</in>
|
||||
<in>wiring_digital.lst</in>
|
||||
<in>wiring_pulse.lst</in>
|
||||
<in>wiring_shift.lst</in>
|
||||
</df>
|
||||
<in>USBHIDJoystick.ino</in>
|
||||
<in>hidjoystickrptparser.cpp</in>
|
||||
<in>hidjoystickrptparser.h</in>
|
||||
</df>
|
||||
<logicalFolder name="ExternalFiles"
|
||||
displayName="Important Files"
|
||||
projectFiles="false"
|
||||
kind="IMPORTANT_FILES_FOLDER">
|
||||
<itemPath>Makefile</itemPath>
|
||||
</logicalFolder>
|
||||
</logicalFolder>
|
||||
<sourceFolderFilter>^(nbproject)$</sourceFolderFilter>
|
||||
<sourceRootList>
|
||||
<Elem>.</Elem>
|
||||
</sourceRootList>
|
||||
<projectmakefile>Makefile</projectmakefile>
|
||||
<confs>
|
||||
<conf name="Default" type="0">
|
||||
<toolsSet>
|
||||
<remote-sources-mode>LOCAL_SOURCES</remote-sources-mode>
|
||||
<compilerSet>default</compilerSet>
|
||||
</toolsSet>
|
||||
<makefileType>
|
||||
<makeTool>
|
||||
<buildCommandWorkingDir>.</buildCommandWorkingDir>
|
||||
<buildCommand>${MAKE} -f Makefile</buildCommand>
|
||||
<cleanCommand>${MAKE} -f Makefile clean</cleanCommand>
|
||||
<executablePath></executablePath>
|
||||
</makeTool>
|
||||
</makefileType>
|
||||
</conf>
|
||||
</confs>
|
||||
</configurationDescriptor>
|
23
examples/HID/USBHIDJoystick/nbproject/project.xml
Normal file
23
examples/HID/USBHIDJoystick/nbproject/project.xml
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||
<type>org.netbeans.modules.cnd.makeproject</type>
|
||||
<configuration>
|
||||
<data xmlns="http://www.netbeans.org/ns/make-project/1">
|
||||
<name>USBHIDJoystick</name>
|
||||
<c-extensions/>
|
||||
<cpp-extensions>cpp,ino</cpp-extensions>
|
||||
<header-extensions>h</header-extensions>
|
||||
<sourceEncoding>UTF-8</sourceEncoding>
|
||||
<make-dep-projects/>
|
||||
<sourceRootList>
|
||||
<sourceRootElem>.</sourceRootElem>
|
||||
</sourceRootList>
|
||||
<confList>
|
||||
<confElem>
|
||||
<name>Default</name>
|
||||
<type>0</type>
|
||||
</confElem>
|
||||
</confList>
|
||||
</data>
|
||||
</configuration>
|
||||
</project>
|
|
@ -1,21 +1,7 @@
|
|||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
#include <hid.h>
|
||||
#include <hiduniversal.h>
|
||||
#include <hidescriptorparser.h>
|
||||
#include <printhex.h>
|
||||
#include <message.h>
|
||||
#include <hexdump.h>
|
||||
#include <parsetools.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
#include "pgmstrings.h"
|
||||
|
|
@ -1,25 +1,11 @@
|
|||
/* Simplified Logitech Extreme 3D Pro Joystick Report Parser */
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
#include <hid.h>
|
||||
#include <hiduniversal.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
#include "le3dp_rptparser.h"
|
||||
|
||||
#include <printhex.h>
|
||||
#include <message.h>
|
||||
#include <hexdump.h>
|
||||
#include <parsetools.h>
|
||||
|
||||
USB Usb;
|
||||
USBHub Hub(&Usb);
|
||||
HIDUniversal Hid(&Usb);
|
||||
|
|
|
@ -1,25 +1,7 @@
|
|||
#if !defined(__HIDJOYSTICKRPTPARSER_H__)
|
||||
#define __HIDJOYSTICKRPTPARSER_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "avrpins.h"
|
||||
#include "max3421e.h"
|
||||
#include "usbhost.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "Usb.h"
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >=100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
#include "printhex.h"
|
||||
#include "hexdump.h"
|
||||
#include "message.h"
|
||||
#include "confdescparser.h"
|
||||
#include "hid.h"
|
||||
#include <hid.h>
|
||||
|
||||
struct GamePadEventData
|
||||
{
|
||||
|
|
42
examples/HID/scale/scale.ino
Normal file
42
examples/HID/scale/scale.ino
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* Digital Scale Output. Written for Stamps.com Model 510 */
|
||||
/* 5lb Digital Scale; any HID scale with Usage page 0x8d should work */
|
||||
|
||||
#include <hid.h>
|
||||
#include <hiduniversal.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
#include "scale_rptparser.h"
|
||||
|
||||
USB Usb;
|
||||
USBHub Hub(&Usb);
|
||||
HIDUniversal Hid(&Usb);
|
||||
Max_LCD LCD(&Usb);
|
||||
ScaleEvents ScaleEvents(&LCD);
|
||||
ScaleReportParser Scale(&ScaleEvents);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin( 115200 );
|
||||
Serial.println("Start");
|
||||
|
||||
if (Usb.Init() == -1)
|
||||
Serial.println("OSC did not start.");
|
||||
|
||||
// set up the LCD's number of rows and columns:
|
||||
LCD.begin(16, 2);
|
||||
LCD.clear();
|
||||
LCD.home();
|
||||
LCD.setCursor(0,0);
|
||||
LCD.write('R');
|
||||
|
||||
delay( 200 );
|
||||
|
||||
if (!Hid.SetReportParser(0, &Scale))
|
||||
ErrorMessage<uint8_t>(PSTR("SetReportParser"), 1 );
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
Usb.Task();
|
||||
}
|
||||
|
150
examples/HID/scale/scale_rptparser.cpp
Normal file
150
examples/HID/scale/scale_rptparser.cpp
Normal file
|
@ -0,0 +1,150 @@
|
|||
/* Parser for standard HID scale (usage page 0x8d) data input report (ID 3) */
|
||||
#include "scale_rptparser.h"
|
||||
|
||||
const char* UNITS[13] = {
|
||||
"units", // unknown unit
|
||||
"mg", // milligram
|
||||
"g", // gram
|
||||
"kg", // kilogram
|
||||
"cd", // carat
|
||||
"taels", // lian
|
||||
"gr", // grain
|
||||
"dwt", // pennyweight
|
||||
"tonnes", // metric tons
|
||||
"tons", // avoir ton
|
||||
"ozt", // troy ounce
|
||||
"oz", // ounce
|
||||
"lbs" // pound
|
||||
};
|
||||
|
||||
ScaleReportParser::ScaleReportParser(ScaleEvents *evt) :
|
||||
scaleEvents(evt)
|
||||
{}
|
||||
|
||||
void ScaleReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf)
|
||||
{
|
||||
bool match = true;
|
||||
|
||||
// Checking if there are changes in report since the method was last called
|
||||
for (uint8_t i=0; i<RPT_SCALE_LEN; i++) {
|
||||
if( buf[i] != oldScale[i] ) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Calling Game Pad event handler
|
||||
if (!match && scaleEvents) {
|
||||
scaleEvents->OnScaleChanged((const ScaleEventData*)buf);
|
||||
|
||||
for (uint8_t i=0; i<RPT_SCALE_LEN; i++) oldScale[i] = buf[i];
|
||||
}
|
||||
}
|
||||
|
||||
ScaleEvents::ScaleEvents( Max_LCD* pLCD ) :
|
||||
|
||||
pLcd( pLCD )
|
||||
|
||||
{}
|
||||
|
||||
void ScaleEvents::LcdPrint( const char* str )
|
||||
{
|
||||
|
||||
while( *str ) {
|
||||
|
||||
pLcd->write( *str++ );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ScaleEvents::OnScaleChanged(const ScaleEventData *evt)
|
||||
{
|
||||
|
||||
pLcd->clear();
|
||||
pLcd->home();
|
||||
pLcd->setCursor(0,0);
|
||||
|
||||
if( evt->reportID != 3 ) {
|
||||
|
||||
const char inv_report[]="Invalid report!";
|
||||
|
||||
Serial.println(inv_report);
|
||||
LcdPrint(inv_report);
|
||||
|
||||
return;
|
||||
|
||||
}//if( evt->reportID != 3...
|
||||
|
||||
switch( evt->status ) {
|
||||
|
||||
case REPORT_FAULT:
|
||||
Serial.println(F("Report fault"));
|
||||
break;
|
||||
|
||||
case ZEROED:
|
||||
Serial.println(F("Scale zero set"));
|
||||
break;
|
||||
|
||||
case WEIGHING: {
|
||||
|
||||
const char progress[] = "Weighing...";
|
||||
Serial.println(progress);
|
||||
LcdPrint(progress);
|
||||
break;
|
||||
}
|
||||
|
||||
case WEIGHT_VALID: {
|
||||
|
||||
char buf[10];
|
||||
double weight = evt->weight * pow( 10, evt->exp );
|
||||
|
||||
|
||||
|
||||
Serial.print(F("Weight: "));
|
||||
Serial.print( weight );
|
||||
Serial.print(F(" "));
|
||||
Serial.println( UNITS[ evt->unit ]);
|
||||
|
||||
LcdPrint("Weight: ");
|
||||
dtostrf( weight, 4, 2, buf );
|
||||
LcdPrint( buf );
|
||||
LcdPrint( UNITS[ evt->unit ]);
|
||||
|
||||
break;
|
||||
|
||||
}//case WEIGHT_VALID...
|
||||
|
||||
case WEIGHT_NEGATIVE: {
|
||||
|
||||
const char negweight[] = "Negative weight";
|
||||
Serial.println(negweight);
|
||||
LcdPrint(negweight);
|
||||
break;
|
||||
}
|
||||
|
||||
case OVERWEIGHT: {
|
||||
|
||||
const char overweight[] = "Max.weight reached";
|
||||
Serial.println(overweight);
|
||||
LcdPrint( overweight );
|
||||
break;
|
||||
}
|
||||
|
||||
case CALIBRATE_ME:
|
||||
|
||||
Serial.println(F("Scale calibration required"));
|
||||
break;
|
||||
|
||||
case ZERO_ME:
|
||||
|
||||
Serial.println(F("Scale zeroing required"));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
Serial.print(F("Undefined status code: "));
|
||||
Serial.println( evt->status );
|
||||
break;
|
||||
|
||||
}//switch( evt->status...
|
||||
|
||||
}
|
55
examples/HID/scale/scale_rptparser.h
Normal file
55
examples/HID/scale/scale_rptparser.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
#if !defined(__SCALERPTPARSER_H__)
|
||||
#define __SCALERPTPARSER_H__
|
||||
|
||||
#include <Max_LCD.h>
|
||||
#include <hid.h>
|
||||
|
||||
/* Scale status constants */
|
||||
#define REPORT_FAULT 0x01
|
||||
#define ZEROED 0x02
|
||||
#define WEIGHING 0x03
|
||||
#define WEIGHT_VALID 0x04
|
||||
#define WEIGHT_NEGATIVE 0x05
|
||||
#define OVERWEIGHT 0x06
|
||||
#define CALIBRATE_ME 0x07
|
||||
#define ZERO_ME 0x08
|
||||
|
||||
/* input data report */
|
||||
struct ScaleEventData
|
||||
{
|
||||
uint8_t reportID; //must be 3
|
||||
uint8_t status;
|
||||
uint8_t unit;
|
||||
int8_t exp; //scale factor for the weight
|
||||
uint16_t weight; //
|
||||
};
|
||||
|
||||
class ScaleEvents
|
||||
{
|
||||
|
||||
Max_LCD* pLcd;
|
||||
|
||||
void LcdPrint( const char* str );
|
||||
|
||||
public:
|
||||
|
||||
ScaleEvents( Max_LCD* pLCD );
|
||||
|
||||
virtual void OnScaleChanged(const ScaleEventData *evt);
|
||||
};
|
||||
|
||||
#define RPT_SCALE_LEN sizeof(ScaleEventData)/sizeof(uint8_t)
|
||||
|
||||
class ScaleReportParser : public HIDReportParser
|
||||
{
|
||||
ScaleEvents *scaleEvents;
|
||||
|
||||
uint8_t oldScale[RPT_SCALE_LEN];
|
||||
|
||||
public:
|
||||
ScaleReportParser(ScaleEvents *evt);
|
||||
|
||||
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
|
||||
};
|
||||
|
||||
#endif // __SCALERPTPARSER_H__
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <PS3USB.h>
|
||||
|
||||
USB Usb;
|
||||
/* You can create the instance of the class in two ways */
|
||||
PS3USB PS3(&Usb); // This will just create the instance
|
||||
|
|
|
@ -1,11 +1,4 @@
|
|||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
|
||||
#include "pgmstrings.h"
|
||||
|
100
examples/Xbox/XBOXOLD/XBOXOLD.ino
Normal file
100
examples/Xbox/XBOXOLD/XBOXOLD.ino
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
Example sketch for the original Xbox 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 <XBOXOLD.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
USB Usb;
|
||||
USBHub Hub1(&Usb); // The controller has a built in hub, so this instance is needed
|
||||
XBOXOLD Xbox(&Usb);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
if (Usb.Init() == -1) {
|
||||
Serial.print(F("\r\nOSC did not start"));
|
||||
while(1); // halt
|
||||
}
|
||||
Serial.print(F("\r\nXBOX Library Started"));
|
||||
}
|
||||
void loop() {
|
||||
Usb.Task();
|
||||
if(Xbox.XboxConnected) {
|
||||
if(Xbox.getButtonPress(BLACK) || Xbox.getButtonPress(WHITE)) {
|
||||
Serial.print("BLACK: ");
|
||||
Serial.print(Xbox.getButtonPress(BLACK));
|
||||
Serial.print("\tWHITE: ");
|
||||
Serial.println(Xbox.getButtonPress(WHITE));
|
||||
Xbox.setRumbleOn(Xbox.getButtonPress(BLACK),Xbox.getButtonPress(WHITE));
|
||||
} else
|
||||
Xbox.setRumbleOn(0,0);
|
||||
if(Xbox.getAnalogHat(LeftHatX) > 7500 || Xbox.getAnalogHat(LeftHatX) < -7500 || Xbox.getAnalogHat(LeftHatY) > 7500 || Xbox.getAnalogHat(LeftHatY) < -7500 || Xbox.getAnalogHat(RightHatX) > 7500 || Xbox.getAnalogHat(RightHatX) < -7500 || Xbox.getAnalogHat(RightHatY) > 7500 || Xbox.getAnalogHat(RightHatY) < -7500) {
|
||||
if(Xbox.getAnalogHat(LeftHatX) > 7500 || Xbox.getAnalogHat(LeftHatX) < -7500) {
|
||||
Serial.print(F("LeftHatX: "));
|
||||
Serial.print(Xbox.getAnalogHat(LeftHatX));
|
||||
Serial.print("\t");
|
||||
}
|
||||
if(Xbox.getAnalogHat(LeftHatY) > 7500 || Xbox.getAnalogHat(LeftHatY) < -7500) {
|
||||
Serial.print(F("LeftHatY: "));
|
||||
Serial.print(Xbox.getAnalogHat(LeftHatY));
|
||||
Serial.print("\t");
|
||||
}
|
||||
if(Xbox.getAnalogHat(RightHatX) > 7500 || Xbox.getAnalogHat(RightHatX) < -7500) {
|
||||
Serial.print(F("RightHatX: "));
|
||||
Serial.print(Xbox.getAnalogHat(RightHatX));
|
||||
Serial.print("\t");
|
||||
}
|
||||
if(Xbox.getAnalogHat(RightHatY) > 7500 || Xbox.getAnalogHat(RightHatY) < -7500) {
|
||||
Serial.print(F("RightHatY: "));
|
||||
Serial.print(Xbox.getAnalogHat(RightHatY));
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
if(Xbox.getButtonClick(UP))
|
||||
Serial.println(F("Up"));
|
||||
if(Xbox.getButtonClick(DOWN))
|
||||
Serial.println(F("Down"));
|
||||
if(Xbox.getButtonClick(LEFT))
|
||||
Serial.println(F("Left"));
|
||||
if(Xbox.getButtonClick(RIGHT))
|
||||
Serial.println(F("Right"));
|
||||
|
||||
if(Xbox.getButtonClick(START))
|
||||
Serial.println(F("Start"));
|
||||
if(Xbox.getButtonClick(BACK))
|
||||
Serial.println(F("Back"));
|
||||
if(Xbox.getButtonClick(L3))
|
||||
Serial.println(F("L3"));
|
||||
if(Xbox.getButtonClick(R3))
|
||||
Serial.println(F("R3"));
|
||||
|
||||
if(Xbox.getButtonPress(A)) {
|
||||
Serial.print(F("A: "));
|
||||
Serial.println(Xbox.getButtonPress(A));
|
||||
}
|
||||
if(Xbox.getButtonPress(B)) {
|
||||
Serial.print(F("B: "));
|
||||
Serial.println(Xbox.getButtonPress(B));
|
||||
}
|
||||
if(Xbox.getButtonPress(X)) {
|
||||
Serial.print(F("X: "));
|
||||
Serial.println(Xbox.getButtonPress(X));
|
||||
}
|
||||
if(Xbox.getButtonPress(Y)) {
|
||||
Serial.print(F("Y: "));
|
||||
Serial.println(Xbox.getButtonPress(Y));
|
||||
}
|
||||
if(Xbox.getButtonPress(L1)) {
|
||||
Serial.print(F("L1: "));
|
||||
Serial.println(Xbox.getButtonPress(L1));
|
||||
}
|
||||
if(Xbox.getButtonPress(R1)) {
|
||||
Serial.print(F("R1: "));
|
||||
Serial.println(Xbox.getButtonPress(R1));
|
||||
}
|
||||
}
|
||||
delay(1);
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include <XBOXRECV.h>
|
||||
|
||||
USB Usb;
|
||||
XBOXRECV Xbox(&Usb);
|
||||
|
||||
|
@ -27,7 +28,7 @@ void loop() {
|
|||
Serial.print(Xbox.getButtonPress(L2,i));
|
||||
Serial.print("\tR2: ");
|
||||
Serial.println(Xbox.getButtonPress(R2,i));
|
||||
Xbox.setRumbleOn(Xbox.getButtonPress(L2,i),Xbox.getButtonPress(R2,i));
|
||||
Xbox.setRumbleOn(Xbox.getButtonPress(L2,i),Xbox.getButtonPress(R2,i),i);
|
||||
}
|
||||
if(Xbox.getAnalogHat(LeftHatX,i) > 7500 || Xbox.getAnalogHat(LeftHatX,i) < -7500 || Xbox.getAnalogHat(LeftHatY,i) > 7500 || Xbox.getAnalogHat(LeftHatY,i) < -7500 || Xbox.getAnalogHat(RightHatX,i) > 7500 || Xbox.getAnalogHat(RightHatX,i) < -7500 || Xbox.getAnalogHat(RightHatY,i) > 7500 || Xbox.getAnalogHat(RightHatY,i) < -7500) {
|
||||
if(Xbox.getAnalogHat(LeftHatX,i) > 7500 || Xbox.getAnalogHat(LeftHatX,i) < -7500) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <XBOXUSB.h>
|
||||
|
||||
USB Usb;
|
||||
XBOXUSB Xbox(&Usb);
|
||||
|
||||
|
|
|
@ -1,18 +1,5 @@
|
|||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
|
||||
#include <cdcacm.h>
|
||||
|
||||
#include <printhex.h>
|
||||
#include <message.h>
|
||||
#include <hexdump.h>
|
||||
#include <parsetools.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
#include "pgmstrings.h"
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
// The source for the Android application can be found at the following link: https://github.com/Lauszus/ArduinoBlinkLED
|
||||
// The code for the Android application is heavily based on this guide: http://allaboutee.com/2011/12/31/arduino-adk-board-blink-an-led-with-your-phone-code-and-explanation/ by Miguel
|
||||
|
||||
#include <Usb.h>
|
||||
#include <adk.h>
|
||||
|
||||
USB Usb;
|
||||
|
|
|
@ -1,18 +1,9 @@
|
|||
/**/
|
||||
/* A sketch demonstrating data exchange between two USB devices - a HID barcode scanner and ADK-compatible Android phone */
|
||||
/**/
|
||||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
|
||||
#include <adk.h>
|
||||
|
||||
#include <hidboot.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
USB Usb;
|
||||
USBHub Hub1(&Usb);
|
|
@ -1,18 +1,5 @@
|
|||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
|
||||
#include <adk.h>
|
||||
|
||||
#include <printhex.h>
|
||||
#include <message.h>
|
||||
#include <hexdump.h>
|
||||
#include <parsetools.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
USB Usb;
|
||||
USBHub hub0(&Usb);
|
|
@ -1,13 +1,5 @@
|
|||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
|
||||
#include <adk.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
USB Usb;
|
||||
//USBHub Hub(&Usb);
|
|
@ -1,13 +1,5 @@
|
|||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
|
||||
#include <adk.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
USB Usb;
|
||||
|
|
@ -1,16 +1,9 @@
|
|||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
/* USB Host Shield 2.0 board quality control routine */
|
||||
/* To see the output set your terminal speed to 115200 */
|
||||
/* for GPIO test to pass you need to connect GPIN0 to GPOUT7, GPIN1 to GPOUT6, etc. */
|
||||
/* otherwise press any key after getting GPIO error to complete the test */
|
||||
/**/
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
|
||||
#include <printhex.h>
|
||||
#include <message.h>
|
||||
#include <hexdump.h>
|
||||
#include <parsetools.h>
|
||||
|
||||
/* variables */
|
||||
uint8_t rcode;
|
||||
|
@ -26,24 +19,24 @@ USB Usb;
|
|||
void setup()
|
||||
{
|
||||
Serial.begin( 115200 );
|
||||
Notify(PSTR("\r\nCircuits At Home 2011"),0x80);
|
||||
Notify(PSTR("\r\nUSB Host Shield Quality Control Routine"),0x80);
|
||||
E_Notify(PSTR("\r\nCircuits At Home 2011"),0x80);
|
||||
E_Notify(PSTR("\r\nUSB Host Shield Quality Control Routine"),0x80);
|
||||
/* SPI quick test - check revision register */
|
||||
Notify(PSTR("\r\nReading REVISION register... Die revision "),0x80);
|
||||
E_Notify(PSTR("\r\nReading REVISION register... Die revision "),0x80);
|
||||
{
|
||||
uint8_t tmpbyte = Usb.regRd( rREVISION );
|
||||
switch( tmpbyte ) {
|
||||
case( 0x01): //rev.01
|
||||
Notify(PSTR("01"),0x80);
|
||||
E_Notify(PSTR("01"),0x80);
|
||||
break;
|
||||
case( 0x12): //rev.02
|
||||
Notify(PSTR("02"),0x80);
|
||||
E_Notify(PSTR("02"),0x80);
|
||||
break;
|
||||
case( 0x13): //rev.03
|
||||
Notify(PSTR("03"),0x80);
|
||||
E_Notify(PSTR("03"),0x80);
|
||||
break;
|
||||
default:
|
||||
Notify(PSTR("invalid. Value returned: "),0x80);
|
||||
E_Notify(PSTR("invalid. Value returned: "),0x80);
|
||||
print_hex( tmpbyte, 8 );
|
||||
halt55();
|
||||
break;
|
||||
|
@ -51,7 +44,7 @@ void setup()
|
|||
}//check revision register
|
||||
/* SPI long test */
|
||||
{
|
||||
Notify(PSTR("\r\nSPI long test. Transfers 1MB of data. Each dot is 64K"),0x80);
|
||||
E_Notify(PSTR("\r\nSPI long test. Transfers 1MB of data. Each dot is 64K"),0x80);
|
||||
uint8_t sample_wr = 0;
|
||||
uint8_t sample_rd = 0;
|
||||
uint8_t gpinpol_copy = Usb.regRd( rGPINPOL );
|
||||
|
@ -60,73 +53,73 @@ void setup()
|
|||
Usb.regWr( rGPINPOL, sample_wr );
|
||||
sample_rd = Usb.regRd( rGPINPOL );
|
||||
if( sample_rd != sample_wr ) {
|
||||
Notify(PSTR("\r\nTest failed. "),0x80);
|
||||
Notify(PSTR("Value written: "),0x80);
|
||||
E_Notify(PSTR("\r\nTest failed. "),0x80);
|
||||
E_Notify(PSTR("Value written: "),0x80);
|
||||
print_hex( sample_wr, 8 );
|
||||
Notify(PSTR(" read: "),0x80);
|
||||
E_Notify(PSTR(" read: "),0x80);
|
||||
print_hex( sample_rd, 8 );
|
||||
halt55();
|
||||
}//if( sample_rd != sample_wr..
|
||||
sample_wr++;
|
||||
}//for( uint16_t j...
|
||||
Notify(PSTR("."),0x80);
|
||||
E_Notify(PSTR("."),0x80);
|
||||
}//for( uint8_t i...
|
||||
Usb.regWr( rGPINPOL, gpinpol_copy );
|
||||
Notify(PSTR(" SPI long test passed"),0x80);
|
||||
E_Notify(PSTR(" SPI long test passed"),0x80);
|
||||
}//SPI long test
|
||||
/* GPIO test */
|
||||
/* in order to simplify board layout, GPIN pins on text fixture are connected to GPOUT */
|
||||
/* in reverse order, i.e, GPIN0 is connected to GPOUT7, GPIN1 to GPOUT6, etc. */
|
||||
{
|
||||
uint8_t tmpbyte;
|
||||
Notify(PSTR("\r\nGPIO test. Connect GPIN0 to GPOUT7, GPIN1 to GPOUT6, and so on"),0x80);
|
||||
E_Notify(PSTR("\r\nGPIO test. Connect GPIN0 to GPOUT7, GPIN1 to GPOUT6, and so on"),0x80);
|
||||
for( uint8_t sample_gpio = 0; sample_gpio < 255; sample_gpio++ ) {
|
||||
Usb.gpioWr( sample_gpio );
|
||||
tmpbyte = Usb.gpioRd();
|
||||
/* bit reversing code copied vetbatim from http://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious */
|
||||
tmpbyte = ((tmpbyte * 0x0802LU & 0x22110LU) | (tmpbyte * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
|
||||
if( sample_gpio != tmpbyte ) {
|
||||
Notify(PSTR("\r\nTest failed. Value written: "),0x80);
|
||||
E_Notify(PSTR("\r\nTest failed. Value written: "),0x80);
|
||||
print_hex( sample_gpio, 8 );
|
||||
Notify(PSTR(" Value read: "),0x80);
|
||||
E_Notify(PSTR(" Value read: "),0x80);
|
||||
print_hex( tmpbyte , 8 );
|
||||
Notify(PSTR(" "),0x80);
|
||||
E_Notify(PSTR(" "),0x80);
|
||||
press_any_key();
|
||||
break;
|
||||
}//if( sample_gpio != tmpbyte...
|
||||
}//for( uint8_t sample_gpio...
|
||||
Notify(PSTR("\r\nGPIO test passed."),0x80);
|
||||
E_Notify(PSTR("\r\nGPIO test passed."),0x80);
|
||||
}//GPIO test
|
||||
/* PLL test. Stops/starts MAX3421E oscillator several times */
|
||||
{
|
||||
Notify(PSTR("\r\nPLL test. 100 chip resets will be performed"),0x80);
|
||||
E_Notify(PSTR("\r\nPLL test. 100 chip resets will be performed"),0x80);
|
||||
/* check current state of the oscillator */
|
||||
if(!( Usb.regRd( rUSBIRQ ) & bmOSCOKIRQ )) { //wrong state - should be on
|
||||
Notify(PSTR("\r\nCurrent oscillator state unexpected."),0x80);
|
||||
E_Notify(PSTR("\r\nCurrent oscillator state unexpected."),0x80);
|
||||
press_any_key();
|
||||
}
|
||||
/* Restart oscillator */
|
||||
Notify(PSTR("\r\nResetting oscillator"),0x80);
|
||||
E_Notify(PSTR("\r\nResetting oscillator"),0x80);
|
||||
for( uint16_t i = 0; i < 101; i++ ) {
|
||||
Notify(PSTR("\rReset number "),0x80);
|
||||
E_Notify(PSTR("\rReset number "),0x80);
|
||||
Serial.print( i, DEC );
|
||||
Usb.regWr( rUSBCTL, bmCHIPRES ); //reset
|
||||
if( Usb.regRd( rUSBIRQ ) & bmOSCOKIRQ ) { //wrong state - should be off
|
||||
Notify(PSTR("\r\nCurrent oscillator state unexpected."),0x80);
|
||||
E_Notify(PSTR("\r\nCurrent oscillator state unexpected."),0x80);
|
||||
halt55();
|
||||
}
|
||||
Usb.regWr( rUSBCTL, 0x00 ); //release from reset
|
||||
uint16_t j = 0;
|
||||
for( j = 0; j < 65535; j++ ) { //tracking off to on time
|
||||
if( Usb.regRd( rUSBIRQ ) & bmOSCOKIRQ ) {
|
||||
Notify(PSTR(" Time to stabilize - "),0x80);
|
||||
E_Notify(PSTR(" Time to stabilize - "),0x80);
|
||||
Serial.print( j, DEC );
|
||||
Notify(PSTR(" cycles"),0x80);
|
||||
E_Notify(PSTR(" cycles"),0x80);
|
||||
break;
|
||||
}
|
||||
}//for( uint16_t j = 0; j < 65535; j++
|
||||
if( j == 0 ) {
|
||||
Notify(PSTR("PLL failed to stabilize"),0x80);
|
||||
E_Notify(PSTR("PLL failed to stabilize"),0x80);
|
||||
press_any_key();
|
||||
}
|
||||
}//for( uint8_t i = 0; i < 255; i++
|
||||
|
@ -134,10 +127,10 @@ void setup()
|
|||
}//PLL test
|
||||
/* initializing USB stack */
|
||||
if (Usb.Init() == -1) {
|
||||
Notify(PSTR("\r\nOSCOKIRQ failed to assert"),0x80);
|
||||
E_Notify(PSTR("\r\nOSCOKIRQ failed to assert"),0x80);
|
||||
halt55();
|
||||
}
|
||||
Notify(PSTR("\r\nChecking USB device communication.\r\n"),0x80);
|
||||
E_Notify(PSTR("\r\nChecking USB device communication.\r\n"),0x80);
|
||||
}
|
||||
|
||||
void loop()
|
||||
|
@ -148,65 +141,65 @@ void loop()
|
|||
/**/
|
||||
switch( usbstate ) {
|
||||
case( USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE ):
|
||||
Notify(PSTR("\rWaiting for device ..."),0x80);
|
||||
E_Notify(PSTR("\rWaiting for device ..."),0x80);
|
||||
break;
|
||||
case( USB_ATTACHED_SUBSTATE_RESET_DEVICE ):
|
||||
Notify(PSTR("\r\nDevice connected. Resetting"),0x80);
|
||||
E_Notify(PSTR("\r\nDevice connected. Resetting"),0x80);
|
||||
break;
|
||||
case( USB_ATTACHED_SUBSTATE_WAIT_SOF ):
|
||||
Notify(PSTR("\rReset complete. Waiting for the first SOF..."),0x80);
|
||||
E_Notify(PSTR("\rReset complete. Waiting for the first SOF..."),0x80);
|
||||
break;
|
||||
case( USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE ):
|
||||
Notify(PSTR("\r\nSOF generation started. Enumerating device."),0x80);
|
||||
E_Notify(PSTR("\r\nSOF generation started. Enumerating device."),0x80);
|
||||
break;
|
||||
case( USB_STATE_ADDRESSING ):
|
||||
Notify(PSTR("\r\nSetting device address"),0x80);
|
||||
E_Notify(PSTR("\r\nSetting device address"),0x80);
|
||||
break;
|
||||
case( USB_STATE_RUNNING ):
|
||||
Notify(PSTR("\r\nGetting device descriptor"),0x80);
|
||||
E_Notify(PSTR("\r\nGetting device descriptor"),0x80);
|
||||
rcode = Usb.getDevDescr( 1, 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)&buf );
|
||||
|
||||
if( rcode ) {
|
||||
Notify(PSTR("\rError reading device descriptor. Error code "),0x80);
|
||||
E_Notify(PSTR("\rError reading device descriptor. Error code "),0x80);
|
||||
print_hex( rcode, 8 );
|
||||
}
|
||||
else {
|
||||
/**/
|
||||
Notify(PSTR("\r\nDescriptor Length:\t"),0x80);
|
||||
E_Notify(PSTR("\r\nDescriptor Length:\t"),0x80);
|
||||
print_hex( buf.bLength, 8 );
|
||||
Notify(PSTR("\r\nDescriptor type:\t"),0x80);
|
||||
E_Notify(PSTR("\r\nDescriptor type:\t"),0x80);
|
||||
print_hex( buf.bDescriptorType, 8 );
|
||||
Notify(PSTR("\r\nUSB version:\t\t"),0x80);
|
||||
E_Notify(PSTR("\r\nUSB version:\t\t"),0x80);
|
||||
print_hex( buf.bcdUSB, 16 );
|
||||
Notify(PSTR("\r\nDevice class:\t\t"),0x80);
|
||||
E_Notify(PSTR("\r\nDevice class:\t\t"),0x80);
|
||||
print_hex( buf.bDeviceClass, 8 );
|
||||
Notify(PSTR("\r\nDevice Subclass:\t"),0x80);
|
||||
E_Notify(PSTR("\r\nDevice Subclass:\t"),0x80);
|
||||
print_hex( buf.bDeviceSubClass, 8 );
|
||||
Notify(PSTR("\r\nDevice Protocol:\t"),0x80);
|
||||
E_Notify(PSTR("\r\nDevice Protocol:\t"),0x80);
|
||||
print_hex( buf.bDeviceProtocol, 8 );
|
||||
Notify(PSTR("\r\nMax.packet size:\t"),0x80);
|
||||
E_Notify(PSTR("\r\nMax.packet size:\t"),0x80);
|
||||
print_hex( buf.bMaxPacketSize0, 8 );
|
||||
Notify(PSTR("\r\nVendor ID:\t\t"),0x80);
|
||||
E_Notify(PSTR("\r\nVendor ID:\t\t"),0x80);
|
||||
print_hex( buf.idVendor, 16 );
|
||||
Notify(PSTR("\r\nProduct ID:\t\t"),0x80);
|
||||
E_Notify(PSTR("\r\nProduct ID:\t\t"),0x80);
|
||||
print_hex( buf.idProduct, 16 );
|
||||
Notify(PSTR("\r\nRevision ID:\t\t"),0x80);
|
||||
E_Notify(PSTR("\r\nRevision ID:\t\t"),0x80);
|
||||
print_hex( buf.bcdDevice, 16 );
|
||||
Notify(PSTR("\r\nMfg.string index:\t"),0x80);
|
||||
E_Notify(PSTR("\r\nMfg.string index:\t"),0x80);
|
||||
print_hex( buf.iManufacturer, 8 );
|
||||
Notify(PSTR("\r\nProd.string index:\t"),0x80);
|
||||
E_Notify(PSTR("\r\nProd.string index:\t"),0x80);
|
||||
print_hex( buf.iProduct, 8 );
|
||||
Notify(PSTR("\r\nSerial number index:\t"),0x80);
|
||||
E_Notify(PSTR("\r\nSerial number index:\t"),0x80);
|
||||
print_hex( buf.iSerialNumber, 8 );
|
||||
Notify(PSTR("\r\nNumber of conf.:\t"),0x80);
|
||||
E_Notify(PSTR("\r\nNumber of conf.:\t"),0x80);
|
||||
print_hex( buf.bNumConfigurations, 8 );
|
||||
/**/
|
||||
Notify(PSTR("\r\n\nAll tests passed. Press RESET to restart test"),0x80);
|
||||
E_Notify(PSTR("\r\n\nAll tests passed. Press RESET to restart test"),0x80);
|
||||
while(1);
|
||||
}
|
||||
break;
|
||||
case( USB_STATE_ERROR ):
|
||||
Notify(PSTR("\rUSB state machine reached error state"),0x80);
|
||||
E_Notify(PSTR("\rUSB state machine reached error state"),0x80);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -219,9 +212,9 @@ void loop()
|
|||
void halt55()
|
||||
{
|
||||
|
||||
Notify(PSTR("\r\nUnrecoverable error - test halted!!"),0x80);
|
||||
Notify(PSTR("\r\n0x55 pattern is transmitted via SPI"),0x80);
|
||||
Notify(PSTR("\r\nPress RESET to restart test"),0x80);
|
||||
E_Notify(PSTR("\r\nUnrecoverable error - test halted!!"),0x80);
|
||||
E_Notify(PSTR("\r\n0x55 pattern is transmitted via SPI"),0x80);
|
||||
E_Notify(PSTR("\r\nPress RESET to restart test"),0x80);
|
||||
|
||||
while( 1 ) {
|
||||
Usb.regWr( 0x55, 0x55 );
|
||||
|
@ -249,7 +242,7 @@ void print_hex(int v, int num_places)
|
|||
/* prints "Press any key" and returns when key is pressed */
|
||||
void press_any_key()
|
||||
{
|
||||
Notify(PSTR("\r\nPress any key to continue..."),0x80);
|
||||
E_Notify(PSTR("\r\nPress any key to continue..."),0x80);
|
||||
while( Serial.available() <= 0 ); //wait for input
|
||||
Serial.read(); //empty input buffer
|
||||
return;
|
||||
|
|
|
@ -1,18 +1,5 @@
|
|||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
|
||||
#include <cdcftdi.h>
|
||||
|
||||
#include <printhex.h>
|
||||
#include <message.h>
|
||||
#include <hexdump.h>
|
||||
#include <parsetools.h>
|
||||
#include <usbhub.h>
|
||||
|
||||
#include "pgmstrings.h"
|
||||
|
|
@ -1,11 +1,4 @@
|
|||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
#include "pgmstrings.h"
|
||||
|
||||
USB Usb;
|
|
@ -1,21 +1,9 @@
|
|||
/* Arduino terminal for PL2303 USB to serial converter and DealeXtreme GPRS modem. */
|
||||
/* USB support */
|
||||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
/* CDC support */
|
||||
#include <cdcacm.h>
|
||||
#include <cdcprolific.h>
|
||||
/* Debug support */
|
||||
#include <printhex.h>
|
||||
#include <message.h>
|
||||
#include <hexdump.h>
|
||||
#include <parsetools.h>
|
||||
|
||||
class PLAsyncOper : public CDCAsyncOper
|
||||
{
|
|
@ -1,22 +1,10 @@
|
|||
/* USB Host to PL2303-based USB GPS unit interface */
|
||||
/* Navibee GM720 receiver - Sirf Star III */
|
||||
/* USB support */
|
||||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
/* CDC support */
|
||||
#include <cdcacm.h>
|
||||
#include <cdcprolific.h>
|
||||
/* Debug support */
|
||||
#include <printhex.h>
|
||||
#include <message.h>
|
||||
#include <hexdump.h>
|
||||
#include <parsetools.h>
|
||||
|
||||
class PLAsyncOper : public CDCAsyncOper
|
||||
{
|
|
@ -4,25 +4,12 @@
|
|||
/* test_with_gps_device library example modified for PL2302 access */
|
||||
|
||||
/* USB support */
|
||||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
|
||||
/* CDC support */
|
||||
#include <cdcacm.h>
|
||||
#include <cdcprolific.h>
|
||||
|
||||
/* Debug support */
|
||||
#include <printhex.h>
|
||||
#include <message.h>
|
||||
#include <hexdump.h>
|
||||
#include <parsetools.h>
|
||||
|
||||
#include <TinyGPS.h>
|
||||
|
||||
/* This sample code demonstrates the normal use of a TinyGPS object.
|
|
@ -1,22 +1,10 @@
|
|||
/* Arduino terminal for PL2303 USB to serial converter and XBee radio. */
|
||||
/* Inserts linefeed after carriage return in data sent to and received from Xbee */
|
||||
/* USB support */
|
||||
#include <avrpins.h>
|
||||
#include <max3421e.h>
|
||||
#include <usbhost.h>
|
||||
#include <usb_ch9.h>
|
||||
#include <Usb.h>
|
||||
#include <usbhub.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <address.h>
|
||||
/* CDC support */
|
||||
#include <cdcacm.h>
|
||||
#include <cdcprolific.h>
|
||||
/* Debug support */
|
||||
#include <printhex.h>
|
||||
#include <message.h>
|
||||
#include <hexdump.h>
|
||||
#include <parsetools.h>
|
||||
|
||||
class PLAsyncOper : public CDCAsyncOper
|
||||
{
|
1
examples/testusbhostFAT/Arduino_Makefile_master
Submodule
1
examples/testusbhostFAT/Arduino_Makefile_master
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 658535d0706aabf2d5a08db065b2b6c6a7a65f38
|
54
examples/testusbhostFAT/Makefile
Normal file
54
examples/testusbhostFAT/Makefile
Normal file
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
# These are set for a mega 1280 + quadram plus my serial patch.
|
||||
# If you lack quadram, or want to disable LFN, just change _FS_TINY=1 _USE_LFN=0
|
||||
#
|
||||
# If your board is a mega 2560 uncomment the following two lines
|
||||
# BOARD = mega2560
|
||||
# PROGRAMMER = wiring
|
||||
# ...and then comment out the following two lines
|
||||
BOARD = mega
|
||||
PROGRAMMER = arduino
|
||||
|
||||
# set your Arduino tty port here
|
||||
PORT = /dev/ttyUSB0
|
||||
|
||||
EXTRA_FLAGS = -D _USE_LFN=3
|
||||
|
||||
# change to 0 if you have quadram to take advantage of caching FAT
|
||||
EXTRA_FLAGS += -D _FS_TINY=1
|
||||
|
||||
|
||||
EXTRA_FLAGS += -D _MAX_SS=512
|
||||
|
||||
|
||||
# Don't worry if you don't have external RAM, xmem2 detects this situation.
|
||||
# You *WILL* be wanting to get some kind of external ram on your mega in order to
|
||||
# do anything that is intense.
|
||||
EXTRA_FLAGS += -D EXT_RAM_STACK=1
|
||||
EXTRA_FLAGS += -D EXT_RAM_HEAP=1
|
||||
|
||||
|
||||
# These are no longer needed for the demo to work.
|
||||
# In the event you need more ram, uncomment these 3 lines.
|
||||
#EXTRA_FLAGS += -D DISABLE_SERIAL1
|
||||
#EXTRA_FLAGS += -D DISABLE_SERIAL2
|
||||
#EXTRA_FLAGS += -D DISABLE_SERIAL3
|
||||
|
||||
#
|
||||
# Advanced debug on Serial3
|
||||
#
|
||||
|
||||
# uncomment the next two to enable debug on Serial3
|
||||
EXTRA_FLAGS += -D USB_HOST_SERIAL=Serial3
|
||||
#EXTRA_FLAGS += -D DEBUG_USB_HOST
|
||||
|
||||
# The following are the libraries used.
|
||||
LIB_DIRS =
|
||||
LIB_DIRS += ../libraries/xmem
|
||||
LIB_DIRS += ../libraries/USB_Host_Shield_2_0
|
||||
LIB_DIRS += ../libraries/generic_storage
|
||||
LIB_DIRS += ../libraries/RTClib
|
||||
LIB_DIRS += $(ARD_HOME)/libraries/Wire
|
||||
LIB_DIRS += $(ARD_HOME)/libraries/Wire/utility
|
||||
# And finally, the part that brings everything together for you.
|
||||
include ../Arduino_Makefile_master/_Makefile.master
|
29
examples/testusbhostFAT/README.md
Normal file
29
examples/testusbhostFAT/README.md
Normal file
|
@ -0,0 +1,29 @@
|
|||
This small sketch tests the USB host shield mass storage library.
|
||||
|
||||
__Note:__ This will not run a Arduino Uno due to the limited ram available in the ATmega328p.
|
||||
|
||||
The Arduino Mega (ATmega1280) and the Arduino Mega 2560 (ATmega2560) are confirmed to work with this test code.
|
||||
|
||||
To compile this example you will need the following libraries as well:
|
||||
|
||||
* [xmem2](https://github.com/xxxajk/xmem2)
|
||||
* [generic_storage FATfs](https://github.com/xxxajk/generic_storage)
|
||||
* [RTClib](https://github.com/xxxajk/RTClib)
|
||||
|
||||
The following shield is recommended for larger projects: <http://ruggedcircuits.com/html/quadram.html>.
|
||||
|
||||
You may use the bundled [Makefile](Makefile) to compile the code instead of the Arduino IDE if you have problems or want a smaller binary. The master makefile is bundled as a submodule, but can also be downloaded manually at the following link: <https://github.com/xxxajk/Arduino_Makefile_master>.
|
||||
|
||||
To download the USB Host library and all the needed libraries for this test.
|
||||
|
||||
Run the following command in a terminal application:
|
||||
|
||||
```
|
||||
git clone --recursive https://github.com/felis/USB_Host_Shield_2.0
|
||||
```
|
||||
|
||||
If you want to update all the submodules run:
|
||||
|
||||
```
|
||||
git submodule foreach --recursive git pull origin master
|
||||
```
|
1
examples/testusbhostFAT/RTClib
Submodule
1
examples/testusbhostFAT/RTClib
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 3e700203de5e1bdc21e9aa0b329363d588e4bd5d
|
6
examples/testusbhostFAT/avr-gdb.conf
Normal file
6
examples/testusbhostFAT/avr-gdb.conf
Normal file
|
@ -0,0 +1,6 @@
|
|||
file build/testusbhostFAT.elf
|
||||
target remote localhost:4242
|
||||
set {int}0x802200 = 0xffff
|
||||
set {int}0x802220 = 0x0000
|
||||
#graph display `x /3xh 0x802200`
|
||||
|
1
examples/testusbhostFAT/generic_storage
Submodule
1
examples/testusbhostFAT/generic_storage
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit f09c4417ac1cce29edaf7259efaeccf2325764ba
|
615
examples/testusbhostFAT/testusbhostFAT.ino
Normal file
615
examples/testusbhostFAT/testusbhostFAT.ino
Normal file
|
@ -0,0 +1,615 @@
|
|||
/*
|
||||
* Mega + USB storage + optional DS1307 + optional expansion RAM + funky status LED,
|
||||
* Includes interactive debug level setting, and supports hot-plug.
|
||||
*
|
||||
* IMPORTANT! PLEASE USE Arduino 1.0.5 or better!
|
||||
* Older versions HAVE MAJOR BUGS AND WILL NOT WORK AT ALL!
|
||||
* Use of gcc-avr and lib-c that is newer than the Arduino version is even better.
|
||||
* If you experience random crashes, use make.
|
||||
* The options that the IDE use can generate bad code and cause the AVR to crash.
|
||||
*
|
||||
* This sketch requires the following libraries:
|
||||
* https://github.com/felis/USB_Host_Shield_2.0 Install as 'USB_Host_Shield_2_0'
|
||||
* https://github.com/xxxajk/xmem2 Install as 'xmem', provides memory services.
|
||||
* https://github.com/xxxajk/generic_storage provides access to FAT file system.
|
||||
* https://github.com/xxxajk/RTClib provides access to DS1307, or fake clock.
|
||||
*
|
||||
* Optional, to use the Makefile (Recommended! See above!):
|
||||
* https://github.com/xxxajk/Arduino_Makefile_master
|
||||
*
|
||||
*/
|
||||
|
||||
// You can set this to 0 if you are not using a USB hub.
|
||||
// It will save a little bit of flash and RAM.
|
||||
// Set to 1 if you want to use a hub.
|
||||
#define WANT_HUB_TEST 0
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Please Note: This section is for Arduino IDE ONLY. //
|
||||
// Use of Make creates a flash image that is 3.3KB smaller //
|
||||
/////////////////////////////////////////////////////////////
|
||||
#ifndef USING_MAKEFILE
|
||||
// Uncomment to enable debugging
|
||||
//#define DEBUG_USB_HOST
|
||||
// This is where stderr/USB debugging goes to
|
||||
#define USB_HOST_SERIAL Serial3
|
||||
// If you have external memory, setting this to 0 enables FAT table caches.
|
||||
// The 0 setting is recommended only if you have external memory.
|
||||
#define _FS_TINY 1
|
||||
|
||||
// These you can safely leave alone.
|
||||
#define _USE_LFN 3
|
||||
#define EXT_RAM_STACK 1
|
||||
#define EXT_RAM_HEAP 1
|
||||
#define _MAX_SS 512
|
||||
#endif
|
||||
/////////////////////////////////////////////////////////////
|
||||
// End of Arduino IDE specific hacks //
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
#include <xmem.h>
|
||||
#if WANT_HUB_TEST
|
||||
#include <usbhub.h>
|
||||
#endif
|
||||
#include <masstorage.h>
|
||||
#include <Storage.h>
|
||||
#include <PCpartition/PCPartition.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <FAT/FAT.h>
|
||||
#include <Wire.h>
|
||||
#include <RTClib.h>
|
||||
|
||||
static FILE tty_stdio;
|
||||
static FILE tty_stderr;
|
||||
USB Usb;
|
||||
|
||||
#define LED 13 // the pin that the LED is attached to
|
||||
|
||||
volatile int brightness = 0; // how bright the LED is
|
||||
volatile int fadeAmount = 80; // how many points to fade the LED by
|
||||
volatile uint8_t current_state = 1;
|
||||
volatile uint32_t LEDnext_time; // fade timeout
|
||||
volatile uint8_t last_state = 0;
|
||||
volatile boolean fatready = false;
|
||||
volatile boolean partsready = false;
|
||||
volatile boolean notified = false;
|
||||
volatile uint32_t HEAPnext_time; // when to print out next heap report
|
||||
volatile boolean runtest = false;
|
||||
volatile boolean usbon = false;
|
||||
volatile uint32_t usbon_time;
|
||||
volatile boolean change = false;
|
||||
volatile boolean reportlvl = false;
|
||||
int cpart = 0;
|
||||
PCPartition *PT;
|
||||
|
||||
#if WANT_HUB_TEST
|
||||
#define MAX_HUBS 1
|
||||
USBHub *Hubs[MAX_HUBS];
|
||||
#endif
|
||||
|
||||
static PFAT *Fats[_VOLUMES];
|
||||
static part_t parts[_VOLUMES];
|
||||
static storage_t sto[_VOLUMES];
|
||||
|
||||
/*make sure this is a power of two. */
|
||||
#define mbxs 128
|
||||
static uint8_t My_Buff_x[mbxs]; /* File read buffer */
|
||||
|
||||
|
||||
#define prescale1 ((1 << WGM12) | (1 << CS10))
|
||||
#define prescale8 ((1 << WGM12) | (1 << CS11))
|
||||
#define prescale64 ((1 << WGM12) | (1 << CS10) | (1 << CS11))
|
||||
#define prescale256 ((1 << WGM12) | (1 << CS12))
|
||||
#define prescale1024 ((1 << WGM12) | (1 << CS12) | (1 << CS10))
|
||||
|
||||
extern "C" unsigned int freeHeap();
|
||||
|
||||
static int tty_stderr_putc(char c, FILE *t) {
|
||||
USB_HOST_SERIAL.write(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tty_std_putc(char c, FILE *t) {
|
||||
Serial.write(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tty_std_getc(FILE *t) {
|
||||
while (!Serial.available());
|
||||
return Serial.read();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
boolean serr = false;
|
||||
for (int i = 0; i < _VOLUMES; i++) {
|
||||
Fats[i] = NULL;
|
||||
sto[i].private_data = new pvt_t;
|
||||
((pvt_t *)sto[i].private_data)->B = 255; // impossible
|
||||
}
|
||||
// Set this to higher values to enable more debug information
|
||||
// minimum 0x00, maximum 0xff
|
||||
UsbDEBUGlvl = 0x51;
|
||||
// make LED pin as an output:
|
||||
pinMode(LED, OUTPUT);
|
||||
pinMode(2, OUTPUT);
|
||||
// Ensure TX is off
|
||||
_SFR_BYTE(UCSR0B) &= ~_BV(TXEN0);
|
||||
// Initialize 'debug' serial port
|
||||
USB_HOST_SERIAL.begin(115200);
|
||||
// Do not start primary Serial port if already started.
|
||||
if (bit_is_clear(UCSR0B, TXEN0)) {
|
||||
Serial.begin(115200);
|
||||
serr = true;
|
||||
}
|
||||
|
||||
// Set up stdio/stderr
|
||||
tty_stdio.put = tty_std_putc;
|
||||
tty_stdio.get = tty_std_getc;
|
||||
tty_stdio.flags = _FDEV_SETUP_RW;
|
||||
tty_stdio.udata = 0;
|
||||
stdout = &tty_stdio;
|
||||
stdin = &tty_stdio;
|
||||
|
||||
tty_stderr.put = tty_stderr_putc;
|
||||
tty_stderr.get = NULL;
|
||||
tty_stderr.flags = _FDEV_SETUP_WRITE;
|
||||
tty_stderr.udata = 0;
|
||||
stderr = &tty_stderr;
|
||||
|
||||
// Blink LED
|
||||
delay(500);
|
||||
analogWrite(LED, 255);
|
||||
delay(500);
|
||||
analogWrite(LED, 0);
|
||||
delay(500);
|
||||
printf_P(PSTR("\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nStart\r\n"));
|
||||
printf_P(PSTR("Current UsbDEBUGlvl %02x\r\n"), UsbDEBUGlvl);
|
||||
printf_P(PSTR("'+' and '-' increase/decrease by 0x01\r\n"));
|
||||
printf_P(PSTR("'.' and ',' increase/decrease by 0x10\r\n"));
|
||||
printf_P(PSTR("'t' will run a 10MB write/read test and print out the time it took.\r\n"));
|
||||
printf_P(PSTR("'e' will toggle vbus off for a few moments.\r\n\r\n"));
|
||||
printf_P(PSTR("Long filename support: "
|
||||
#if _USE_LFN
|
||||
"Enabled"
|
||||
#else
|
||||
"Disabled"
|
||||
#endif
|
||||
"\r\n"));
|
||||
if (serr) {
|
||||
fprintf_P(stderr, PSTR("\r\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nStart\r\n"));
|
||||
fprintf_P(stderr, PSTR("Current UsbDEBUGlvl %02x\r\n"), UsbDEBUGlvl);
|
||||
fprintf_P(stderr, PSTR("Long filename support: "
|
||||
#if _USE_LFN
|
||||
"Enabled"
|
||||
#else
|
||||
"Disabled"
|
||||
#endif
|
||||
"\r\n"));
|
||||
}
|
||||
analogWrite(LED, 255);
|
||||
delay(500);
|
||||
analogWrite(LED, 0);
|
||||
delay(500);
|
||||
analogWrite(LED, 255);
|
||||
delay(500);
|
||||
analogWrite(LED, 0);
|
||||
delay(500);
|
||||
analogWrite(LED, 255);
|
||||
delay(500);
|
||||
analogWrite(LED, 0);
|
||||
delay(500);
|
||||
|
||||
LEDnext_time = millis() + 1;
|
||||
#ifdef EXT_RAM
|
||||
printf_P(PSTR("Total EXT RAM banks %i\r\n"), xmem::getTotalBanks());
|
||||
#endif
|
||||
printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
|
||||
printf_P(PSTR("SP %x\r\n"), (uint8_t *)(SP));
|
||||
|
||||
// Even though I'm not going to actually be deleting,
|
||||
// I want to be able to have slightly more control.
|
||||
// Besides, it is easier to initialize stuff...
|
||||
#if WANT_HUB_TEST
|
||||
for (int i = 0; i < MAX_HUBS; i++) {
|
||||
Hubs[i] = new USBHub(&Usb);
|
||||
printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
|
||||
}
|
||||
#endif
|
||||
// Initialize generic storage. This must be done before USB starts.
|
||||
InitStorage();
|
||||
|
||||
while (Usb.Init(1000) == -1) {
|
||||
printf_P(PSTR("No USB HOST Shield?\r\n"));
|
||||
Notify(PSTR("OSC did not start."), 0x40);
|
||||
}
|
||||
// usb VBUS _OFF_
|
||||
//Usb.gpioWr(0x00);
|
||||
//digitalWrite(2, 0);
|
||||
//usbon_time = millis() + 2000;
|
||||
cli();
|
||||
TCCR3A = 0;
|
||||
TCCR3B = 0;
|
||||
// (0.01/(1/((16 *(10^6)) / 8))) - 1 = 19999
|
||||
OCR3A = 19999;
|
||||
TCCR3B |= prescale8;
|
||||
TIMSK3 |= (1 << OCIE1A);
|
||||
sei();
|
||||
|
||||
HEAPnext_time = millis() + 10000;
|
||||
}
|
||||
|
||||
void serialEvent() {
|
||||
// Adjust UsbDEBUGlvl level on-the-fly.
|
||||
// + to increase, - to decrease, * to display current level.
|
||||
// . to increase by 16, , to decrease by 16
|
||||
// e to flick VBUS
|
||||
// * to report debug level
|
||||
if (Serial.available()) {
|
||||
int inByte = Serial.read();
|
||||
switch (inByte) {
|
||||
case '+':
|
||||
if (UsbDEBUGlvl < 0xff) UsbDEBUGlvl++;
|
||||
reportlvl = true;
|
||||
break;
|
||||
case '-':
|
||||
if (UsbDEBUGlvl > 0x00) UsbDEBUGlvl--;
|
||||
reportlvl = true;
|
||||
break;
|
||||
case '.':
|
||||
if (UsbDEBUGlvl < 0xf0) UsbDEBUGlvl += 16;
|
||||
reportlvl = true;
|
||||
break;
|
||||
case ',':
|
||||
if (UsbDEBUGlvl > 0x0f) UsbDEBUGlvl -= 16;
|
||||
reportlvl = true;
|
||||
break;
|
||||
case '*':
|
||||
reportlvl = true;
|
||||
break;
|
||||
case 't':
|
||||
runtest = true;
|
||||
break;
|
||||
case 'e':
|
||||
change = true;
|
||||
usbon = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ISR(TIMER3_COMPA_vect) {
|
||||
if (millis() >= LEDnext_time) {
|
||||
LEDnext_time = millis() + 30;
|
||||
|
||||
// set the brightness of LED
|
||||
analogWrite(LED, brightness);
|
||||
|
||||
// change the brightness for next time through the loop:
|
||||
brightness = brightness + fadeAmount;
|
||||
|
||||
// reverse the direction of the fading at the ends of the fade:
|
||||
if (brightness <= 0) {
|
||||
brightness = 0;
|
||||
fadeAmount = -fadeAmount;
|
||||
}
|
||||
if (brightness >= 255) {
|
||||
brightness = 255;
|
||||
fadeAmount = -fadeAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isfat(uint8_t t) {
|
||||
return (t == 0x01 || t == 0x04 || t == 0x06 || t == 0x0b || t == 0x0c || t == 0x0e || t == 0x1);
|
||||
}
|
||||
|
||||
void die(FRESULT rc) {
|
||||
printf_P(PSTR("Failed with rc=%u.\r\n"), rc);
|
||||
//for (;;);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
FIL My_File_Object_x; /* File object */
|
||||
|
||||
// Print a heap status report about every 10 seconds.
|
||||
if (millis() >= HEAPnext_time) {
|
||||
if (UsbDEBUGlvl > 0x50) {
|
||||
printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
|
||||
}
|
||||
HEAPnext_time = millis() + 10000;
|
||||
}
|
||||
|
||||
// Horrid! This sort of thing really belongs in an ISR, not here!
|
||||
// We also will be needing to test each hub port, we don't do this yet!
|
||||
if (!change && !usbon && millis() >= usbon_time) {
|
||||
change = true;
|
||||
usbon = true;
|
||||
}
|
||||
|
||||
if (change) {
|
||||
change = false;
|
||||
if (usbon) {
|
||||
Usb.vbusPower(vbus_on);
|
||||
printf_P(PSTR("VBUS on\r\n"));
|
||||
} else {
|
||||
Usb.vbusPower(vbus_off);
|
||||
usbon_time = millis() + 2000;
|
||||
}
|
||||
}
|
||||
Usb.Task();
|
||||
current_state = Usb.getUsbTaskState();
|
||||
if (current_state != last_state) {
|
||||
if (UsbDEBUGlvl > 0x50)
|
||||
printf_P(PSTR("USB state = %x\r\n"), current_state);
|
||||
if (current_state == USB_STATE_RUNNING) {
|
||||
fadeAmount = 30;
|
||||
}
|
||||
if (current_state == USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE) {
|
||||
fadeAmount = 80;
|
||||
partsready = false;
|
||||
for (int i = 0; i < cpart; i++) {
|
||||
if (Fats[i] != NULL)
|
||||
delete Fats[i];
|
||||
Fats[i] = NULL;
|
||||
}
|
||||
fatready = false;
|
||||
notified = false;
|
||||
cpart = 0;
|
||||
}
|
||||
last_state = current_state;
|
||||
}
|
||||
|
||||
// only do any of this if usb is on
|
||||
if (usbon) {
|
||||
if (partsready && !fatready) {
|
||||
if (cpart > 0) fatready = true;
|
||||
}
|
||||
|
||||
// This is horrible, and needs to be moved elsewhere!
|
||||
for (int B = 0; B < MAX_USB_MS_DRIVERS; B++) {
|
||||
if (!partsready && Bulk[B]->GetAddress() != NULL) {
|
||||
// Build a list.
|
||||
int ML = Bulk[B]->GetbMaxLUN();
|
||||
//printf("MAXLUN = %i\r\n", ML);
|
||||
ML++;
|
||||
for (int i = 0; i < ML; i++) {
|
||||
if (Bulk[B]->LUNIsGood(i)) {
|
||||
partsready = true;
|
||||
((pvt_t *)sto[i].private_data)->lun = i;
|
||||
((pvt_t *)sto[i].private_data)->B = B;
|
||||
sto[i].Read = *PRead;
|
||||
sto[i].Write = *PWrite;
|
||||
sto[i].Reads = *PReads;
|
||||
sto[i].Writes = *PWrites;
|
||||
sto[i].Status = *PStatus;
|
||||
sto[i].TotalSectors = Bulk[B]->GetCapacity(i);
|
||||
sto[i].SectorSize = Bulk[B]->GetSectorSize(i);
|
||||
printf_P(PSTR("LUN:\t\t%u\r\n"), i);
|
||||
printf_P(PSTR("Total Sectors:\t%08lx\t%lu\r\n"), sto[i].TotalSectors, sto[i].TotalSectors);
|
||||
printf_P(PSTR("Sector Size:\t%04x\t\t%u\r\n"), sto[i].SectorSize, sto[i].SectorSize);
|
||||
// get the partition data...
|
||||
PT = new PCPartition;
|
||||
|
||||
if (!PT->Init(&sto[i])) {
|
||||
part_t *apart;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
apart = PT->GetPart(j);
|
||||
if (apart != NULL && apart->type != 0x00) {
|
||||
memcpy(&(parts[cpart]), apart, sizeof (part_t));
|
||||
printf_P(PSTR("Partition %u type %#02x\r\n"), j, parts[cpart].type);
|
||||
// for now
|
||||
if (isfat(parts[cpart].type)) {
|
||||
Fats[cpart] = new PFAT(&sto[i], cpart, parts[cpart].firstSector);
|
||||
//int r = Fats[cpart]->Good();
|
||||
if (Fats[cpart]->Good()) {
|
||||
delete Fats[cpart];
|
||||
Fats[cpart] = NULL;
|
||||
} else cpart++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// try superblock
|
||||
Fats[cpart] = new PFAT(&sto[i], cpart, 0);
|
||||
//int r = Fats[cpart]->Good();
|
||||
if (Fats[cpart]->Good()) {
|
||||
//printf_P(PSTR("Superblock error %x\r\n"), r);
|
||||
delete Fats[cpart];
|
||||
Fats[cpart] = NULL;
|
||||
} else cpart++;
|
||||
|
||||
}
|
||||
delete PT;
|
||||
} else {
|
||||
sto[i].Read = NULL;
|
||||
sto[i].Write = NULL;
|
||||
sto[i].Writes = NULL;
|
||||
sto[i].Reads = NULL;
|
||||
sto[i].TotalSectors = 0UL;
|
||||
sto[i].SectorSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (fatready) {
|
||||
if (Fats[0] != NULL) {
|
||||
struct Pvt * p;
|
||||
p = ((struct Pvt *)(Fats[0]->storage->private_data));
|
||||
if (!Bulk[p->B]->LUNIsGood(p->lun)) {
|
||||
// media change
|
||||
fadeAmount = 80;
|
||||
partsready = false;
|
||||
for (int i = 0; i < cpart; i++) {
|
||||
if (Fats[i] != NULL)
|
||||
delete Fats[i];
|
||||
Fats[cpart] = NULL;
|
||||
}
|
||||
fatready = false;
|
||||
notified = false;
|
||||
cpart = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (fatready) {
|
||||
FRESULT rc; /* Result code */
|
||||
UINT bw, br, i;
|
||||
|
||||
if (!notified) {
|
||||
fadeAmount = 5;
|
||||
notified = true;
|
||||
printf_P(PSTR("\r\nOpen an existing file (message.txt).\r\n"));
|
||||
rc = f_open(&My_File_Object_x, "0:/MESSAGE.TXT", FA_READ);
|
||||
if (rc) printf_P(PSTR("Error %i, message.txt not found.\r\n"));
|
||||
else {
|
||||
printf_P(PSTR("\r\nType the file content.\r\n"));
|
||||
for (;;) {
|
||||
rc = f_read(&My_File_Object_x, My_Buff_x, mbxs, &br); /* Read a chunk of file */
|
||||
if (rc || !br) break; /* Error or end of file */
|
||||
for (i = 0; i < br; i++) {
|
||||
/* Type the data */
|
||||
if (My_Buff_x[i] == '\n')
|
||||
Serial.write('\r');
|
||||
if (My_Buff_x[i] != '\r')
|
||||
Serial.write(My_Buff_x[i]);
|
||||
Serial.flush();
|
||||
}
|
||||
}
|
||||
if (rc) {
|
||||
f_close(&My_File_Object_x);
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf_P(PSTR("\r\nClose the file.\r\n"));
|
||||
rc = f_close(&My_File_Object_x);
|
||||
if (rc) goto out;
|
||||
}
|
||||
printf_P(PSTR("\r\nCreate a new file (hello.txt).\r\n"));
|
||||
rc = f_open(&My_File_Object_x, "0:/Hello.TxT", FA_WRITE | FA_CREATE_ALWAYS);
|
||||
if (rc) {
|
||||
die(rc);
|
||||
goto outdir;
|
||||
}
|
||||
printf_P(PSTR("\r\nWrite a text data. (Hello world!)\r\n"));
|
||||
rc = f_write(&My_File_Object_x, "Hello world!\r\n", 14, &bw);
|
||||
if (rc) {
|
||||
goto out;
|
||||
}
|
||||
printf_P(PSTR("%u bytes written.\r\n"), bw);
|
||||
|
||||
printf_P(PSTR("\r\nClose the file.\r\n"));
|
||||
rc = f_close(&My_File_Object_x);
|
||||
if (rc) {
|
||||
die(rc);
|
||||
goto out;
|
||||
}
|
||||
outdir:
|
||||
{
|
||||
#if _USE_LFN
|
||||
char lfn[_MAX_LFN + 1];
|
||||
FILINFO My_File_Info_Object_x; /* File information object */
|
||||
My_File_Info_Object_x.lfname = lfn;
|
||||
#endif
|
||||
DIR My_Dir_Object_x; /* Directory object */
|
||||
printf_P(PSTR("\r\nOpen root directory.\r\n"));
|
||||
rc = f_opendir(&My_Dir_Object_x, "0:/");
|
||||
if (rc) {
|
||||
die(rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf_P(PSTR("\r\nDirectory listing...\r\n"));
|
||||
printf_P(PSTR("Available heap: %u Bytes\r\n"), freeHeap());
|
||||
for (;;) {
|
||||
#if _USE_LFN
|
||||
My_File_Info_Object_x.lfsize = _MAX_LFN;
|
||||
#endif
|
||||
|
||||
rc = f_readdir(&My_Dir_Object_x, &My_File_Info_Object_x); /* Read a directory item */
|
||||
if (rc || !My_File_Info_Object_x.fname[0]) break; /* Error or end of dir */
|
||||
|
||||
if (My_File_Info_Object_x.fattrib & AM_DIR) {
|
||||
Serial.write('d');
|
||||
} else {
|
||||
Serial.write('-');
|
||||
}
|
||||
Serial.write('r');
|
||||
|
||||
if (My_File_Info_Object_x.fattrib & AM_RDO) {
|
||||
Serial.write('-');
|
||||
} else {
|
||||
Serial.write('w');
|
||||
}
|
||||
if (My_File_Info_Object_x.fattrib & AM_HID) {
|
||||
Serial.write('h');
|
||||
} else {
|
||||
Serial.write('-');
|
||||
}
|
||||
|
||||
if (My_File_Info_Object_x.fattrib & AM_SYS) {
|
||||
Serial.write('s');
|
||||
} else {
|
||||
Serial.write('-');
|
||||
}
|
||||
|
||||
if (My_File_Info_Object_x.fattrib & AM_ARC) {
|
||||
Serial.write('a');
|
||||
} else {
|
||||
Serial.write('-');
|
||||
}
|
||||
|
||||
#if _USE_LFN
|
||||
if (*My_File_Info_Object_x.lfname)
|
||||
printf_P(PSTR(" %8lu %s (%s)\r\n"), My_File_Info_Object_x.fsize, My_File_Info_Object_x.fname, My_File_Info_Object_x.lfname);
|
||||
else
|
||||
#endif
|
||||
printf_P(PSTR(" %8lu %s\r\n"), My_File_Info_Object_x.fsize, &(My_File_Info_Object_x.fname[0]));
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (rc) die(rc);
|
||||
printf_P(PSTR("\r\nTest completed.\r\n"));
|
||||
|
||||
}
|
||||
|
||||
if (runtest) {
|
||||
ULONG ii, wt, rt, start, end;
|
||||
runtest = false;
|
||||
f_unlink("0:/10MB.bin");
|
||||
printf_P(PSTR("\r\nCreate a new 10MB test file (10MB.bin).\r\n"));
|
||||
rc = f_open(&My_File_Object_x, "0:/10MB.bin", FA_WRITE | FA_CREATE_ALWAYS);
|
||||
if (rc) goto failed;
|
||||
for (bw = 0; bw < mbxs; bw++) My_Buff_x[bw] = bw & 0xff;
|
||||
start = millis();
|
||||
for (ii = 10485760LU / mbxs; ii > 0LU; ii--) {
|
||||
rc = f_write(&My_File_Object_x, My_Buff_x, mbxs, &bw);
|
||||
if (rc || !bw) goto failed;
|
||||
}
|
||||
rc = f_close(&My_File_Object_x);
|
||||
if (rc) goto failed;
|
||||
end = millis();
|
||||
wt = end - start;
|
||||
printf_P(PSTR("Time to write 10485760 bytes: %lu ms (%lu sec) \r\n"), wt, (500 + wt) / 1000UL);
|
||||
rc = f_open(&My_File_Object_x, "0:/10MB.bin", FA_READ);
|
||||
start = millis();
|
||||
if (rc) goto failed;
|
||||
for (;;) {
|
||||
rc = f_read(&My_File_Object_x, My_Buff_x, mbxs, &bw); /* Read a chunk of file */
|
||||
if (rc || !bw) break; /* Error or end of file */
|
||||
}
|
||||
end = millis();
|
||||
if (rc) goto failed;
|
||||
rc = f_close(&My_File_Object_x);
|
||||
if (rc) goto failed;
|
||||
rt = end - start;
|
||||
printf_P(PSTR("Time to read 10485760 bytes: %lu ms (%lu sec)\r\nDelete test file\r\n"), rt, (500 + rt) / 1000UL);
|
||||
failed:
|
||||
if (rc) die(rc);
|
||||
printf_P(PSTR("10MB timing test finished.\r\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
examples/testusbhostFAT/xmem2
Submodule
1
examples/testusbhostFAT/xmem2
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 24f521e27cea025b38bc9e2615018e96478de1be
|
15
hexdump.h
15
hexdump.h
|
@ -14,11 +14,12 @@ Circuits At Home, LTD
|
|||
Web : http://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
#if !defined(__HEXDUMP_H__)
|
||||
#if !defined(_usb_h_) || defined(__HEXDUMP_H__)
|
||||
#error "Never include hexdump.h directly; include Usb.h instead"
|
||||
#else
|
||||
#define __HEXDUMP_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/pgmspace.h>
|
||||
extern int UsbDEBUGlvl;
|
||||
|
||||
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
|
||||
class HexDumper : public BASE_CLASS {
|
||||
|
@ -40,23 +41,21 @@ public:
|
|||
|
||||
template <class BASE_CLASS, class LEN_TYPE, class OFFSET_TYPE>
|
||||
void HexDumper<BASE_CLASS, LEN_TYPE, OFFSET_TYPE>::Parse(const LEN_TYPE len, const uint8_t *pbuf, const OFFSET_TYPE &offset) {
|
||||
#ifdef DEBUG
|
||||
if(UsbDEBUGlvl >= 0x80) { // Fully bypass this block of code if we do not debug.
|
||||
for(LEN_TYPE j = 0; j < len; j++, byteCount++, byteTotal++) {
|
||||
if(!byteCount) {
|
||||
PrintHex<OFFSET_TYPE > (byteTotal, 0x80);
|
||||
Notify(PSTR(": "), 0x80);
|
||||
E_Notify(PSTR(": "), 0x80);
|
||||
}
|
||||
PrintHex<uint8_t > (pbuf[j], 0x80);
|
||||
Notify(PSTR(" "), 0x80);
|
||||
E_Notify(PSTR(" "), 0x80);
|
||||
|
||||
if(byteCount == 15) {
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
E_Notify(PSTR("\r\n"), 0x80);
|
||||
byteCount = 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // __HEXDUMP_H__
|
26
hid.cpp
26
hid.cpp
|
@ -44,39 +44,39 @@ uint8_t HID::GetProtocol(uint8_t iface, uint8_t* dataptr) {
|
|||
void HID::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr) {
|
||||
Notify(PSTR("Endpoint descriptor:"), 0x80);
|
||||
Notify(PSTR("\r\nLength:\t\t"), 0x80);
|
||||
PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
|
||||
D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
|
||||
Notify(PSTR("\r\nType:\t\t"), 0x80);
|
||||
PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
|
||||
D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
|
||||
Notify(PSTR("\r\nAddress:\t"), 0x80);
|
||||
PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
|
||||
D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
|
||||
Notify(PSTR("\r\nAttributes:\t"), 0x80);
|
||||
PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
|
||||
D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
|
||||
Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
|
||||
PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
|
||||
D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
|
||||
Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
|
||||
PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
|
||||
D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
|
||||
}
|
||||
|
||||
void HID::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
|
||||
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
|
||||
Notify(PSTR("bDescLength:\t\t"), 0x80);
|
||||
PrintHex<uint8_t > (pDesc->bLength, 0x80);
|
||||
D_PrintHex<uint8_t > (pDesc->bLength, 0x80);
|
||||
|
||||
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
|
||||
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
|
||||
D_PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
|
||||
|
||||
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
|
||||
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
|
||||
D_PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
|
||||
|
||||
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
|
||||
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
|
||||
D_PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
|
||||
|
||||
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
|
||||
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
|
||||
D_PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
|
||||
|
||||
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
|
||||
PrintHex<uint8_t > (pDesc->bDescrType, 0x80);
|
||||
D_PrintHex<uint8_t > (pDesc->bDescrType, 0x80);
|
||||
|
||||
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
|
||||
PrintHex<uint16_t > (pDesc->wDescriptorLength, 0x80);
|
||||
D_PrintHex<uint16_t > (pDesc->wDescriptorLength, 0x80);
|
||||
}
|
||||
|
|
18
hid.h
18
hid.h
|
@ -17,25 +17,7 @@ e-mail : support@circuitsathome.com
|
|||
#if !defined(__HID_H__)
|
||||
#define __HID_H__
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >=100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "avrpins.h"
|
||||
#include "max3421e.h"
|
||||
#include "usbhost.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "Usb.h"
|
||||
|
||||
#include "printhex.h"
|
||||
#include "hexdump.h"
|
||||
#include "message.h"
|
||||
|
||||
#include "confdescparser.h"
|
||||
#include "hidusagestr.h"
|
||||
|
||||
#define DATA_SIZE_MASK 0x03
|
||||
|
|
140
hidboot.h
140
hidboot.h
|
@ -17,27 +17,8 @@ e-mail : support@circuitsathome.com
|
|||
#if !defined(__HIDBOOT_H__)
|
||||
#define __HIDBOOT_H__
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >=100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "avrpins.h"
|
||||
#include "max3421e.h"
|
||||
#include "usbhost.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "Usb.h"
|
||||
#include "hid.h"
|
||||
|
||||
#include "printhex.h"
|
||||
#include "hexdump.h"
|
||||
#include "message.h"
|
||||
|
||||
#include "confdescparser.h"
|
||||
|
||||
#define KEY_SPACE 0x2c
|
||||
#define KEY_ZERO 0x27
|
||||
#define KEY_ZERO2 0x62
|
||||
|
@ -171,16 +152,15 @@ protected:
|
|||
};
|
||||
};
|
||||
|
||||
#define totalEndpoints 2
|
||||
|
||||
#define totalEndpoints (((BOOT_PROTOCOL & HID_PROTOCOL_KEYBOARD)? 2 : 0)+((BOOT_PROTOCOL & HID_PROTOCOL_MOUSE)? 1 : 0))
|
||||
#define epMUL (((BOOT_PROTOCOL & HID_PROTOCOL_KEYBOARD)? 1 : 0)+((BOOT_PROTOCOL & HID_PROTOCOL_MOUSE)? 1 : 0))
|
||||
#define HID_MAX_HID_CLASS_DESCRIPTORS 5
|
||||
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
class HIDBoot : public HID //public USBDeviceConfig, public UsbConfigXtracter
|
||||
{
|
||||
EpInfo epInfo[totalEndpoints];
|
||||
|
||||
HIDReportParser *pRptParser;
|
||||
HIDReportParser *pRptParser[epMUL];
|
||||
|
||||
uint8_t bConfNum; // configuration number
|
||||
uint8_t bIfaceNum; // Interface Number
|
||||
|
@ -192,14 +172,14 @@ class HIDBoot : public HID //public USBDeviceConfig, public UsbConfigXtracter
|
|||
void Initialize();
|
||||
|
||||
virtual HIDReportParser* GetReportParser(uint8_t id) {
|
||||
return pRptParser;
|
||||
return pRptParser[id];
|
||||
};
|
||||
|
||||
public:
|
||||
HIDBoot(USB *p);
|
||||
|
||||
virtual bool SetReportParser(uint8_t id, HIDReportParser *prs) {
|
||||
pRptParser = prs;
|
||||
pRptParser[id] = prs;
|
||||
return true;
|
||||
};
|
||||
|
||||
|
@ -220,10 +200,12 @@ template <const uint8_t BOOT_PROTOCOL>
|
|||
HIDBoot<BOOT_PROTOCOL>::HIDBoot(USB *p) :
|
||||
HID(p),
|
||||
qNextPollTime(0),
|
||||
bPollEnable(false),
|
||||
pRptParser(NULL) {
|
||||
bPollEnable(false) {
|
||||
Initialize();
|
||||
|
||||
for(uint8_t i = 0; i < epMUL; i++) {
|
||||
pRptParser[i] = NULL;
|
||||
}
|
||||
if(pUsb)
|
||||
pUsb->RegisterDeviceClass(this);
|
||||
}
|
||||
|
@ -250,10 +232,10 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed
|
|||
UsbDevice *p = NULL;
|
||||
EpInfo *oldep_ptr = NULL;
|
||||
uint8_t len = 0;
|
||||
uint16_t cd_len = 0;
|
||||
//uint16_t cd_len = 0;
|
||||
|
||||
uint8_t num_of_conf; // number of configurations
|
||||
uint8_t num_of_intf; // number of interfaces
|
||||
//uint8_t num_of_intf; // number of interfaces
|
||||
|
||||
AddressPool &addrPool = pUsb->GetAddressPool();
|
||||
|
||||
|
@ -344,29 +326,48 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed
|
|||
|
||||
//USBTRACE2("NC:", num_of_conf);
|
||||
|
||||
// GCC will optimize unused stuff away.
|
||||
if(BOOT_PROTOCOL & HID_PROTOCOL_KEYBOARD) {
|
||||
for(uint8_t i = 0; i < num_of_conf; i++) {
|
||||
ConfigDescParser<
|
||||
USB_CLASS_HID,
|
||||
HID_BOOT_INTF_SUBCLASS,
|
||||
BOOT_PROTOCOL,
|
||||
CP_MASK_COMPARE_ALL> confDescrParser(this);
|
||||
HID_PROTOCOL_KEYBOARD,
|
||||
CP_MASK_COMPARE_ALL> confDescrParserA(this);
|
||||
|
||||
rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
|
||||
|
||||
if(bNumEP > 1)
|
||||
if(bNumEP == totalEndpoints)
|
||||
break;
|
||||
} // for
|
||||
pUsb->getConfDescr(bAddress, 0, i, &confDescrParserA);
|
||||
}
|
||||
}
|
||||
|
||||
if(bNumEP < 2)
|
||||
return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
// GCC will optimize unused stuff away.
|
||||
if(BOOT_PROTOCOL & HID_PROTOCOL_MOUSE) {
|
||||
for(uint8_t i = 0; i < num_of_conf; i++) {
|
||||
ConfigDescParser<
|
||||
USB_CLASS_HID,
|
||||
HID_BOOT_INTF_SUBCLASS,
|
||||
HID_PROTOCOL_MOUSE,
|
||||
CP_MASK_COMPARE_ALL> confDescrParserB(this);
|
||||
if(bNumEP == totalEndpoints)
|
||||
break;
|
||||
|
||||
//USBTRACE2("\r\nbAddr:", bAddress);
|
||||
//USBTRACE2("\r\nbNumEP:", bNumEP);
|
||||
pUsb->getConfDescr(bAddress, 0, i, &confDescrParserB);
|
||||
}
|
||||
}
|
||||
|
||||
USBTRACE2("\r\nbAddr:", bAddress);
|
||||
USBTRACE2("\r\nbNumEP:", bNumEP);
|
||||
USBTRACE2("\r\ntotalEndpoints:", totalEndpoints);
|
||||
if(bNumEP != totalEndpoints) {
|
||||
rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
// Assign epInfo to epinfo pointer
|
||||
rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
|
||||
|
||||
//USBTRACE2("\r\nCnf:", bConfNum);
|
||||
USBTRACE2("\r\nCnf:", bConfNum);
|
||||
|
||||
// Set Configuration Value
|
||||
rcode = pUsb->setConf(bAddress, 0, bConfNum);
|
||||
|
@ -374,15 +375,16 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed
|
|||
if(rcode)
|
||||
goto FailSetConfDescr;
|
||||
|
||||
//USBTRACE2("\r\nIf:", bIfaceNum);
|
||||
USBTRACE2("\r\nIf:", bIfaceNum);
|
||||
|
||||
rcode = SetProtocol(bIfaceNum, HID_BOOT_PROTOCOL);
|
||||
|
||||
if(rcode)
|
||||
goto FailSetProtocol;
|
||||
|
||||
if(BOOT_PROTOCOL == 1) {
|
||||
rcode = SetIdle(bIfaceNum, 0, 0);
|
||||
// GCC will optimize unused stuff away.
|
||||
if(BOOT_PROTOCOL & HID_PROTOCOL_KEYBOARD) {
|
||||
rcode = SetIdle(0/* bIfaceNum*/, 0, 0);
|
||||
|
||||
if(rcode)
|
||||
goto FailSetIdle;
|
||||
|
@ -393,57 +395,67 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Init(uint8_t parent, uint8_t port, bool lowspeed
|
|||
return 0;
|
||||
|
||||
FailGetDevDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetDevDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetDevTblEntry:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetDevTblEntry();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailGetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetConfDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetConfDescr();
|
||||
goto Fail;
|
||||
|
||||
#endif
|
||||
|
||||
FailSetProtocol:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
USBTRACE("SetProto:");
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetIdle:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
USBTRACE("SetIdle:");
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
Fail:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFail(rcode);
|
||||
#endif
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
||||
template <const uint8_t BOOT_PROTOCOL>
|
||||
void HIDBoot<BOOT_PROTOCOL>::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
|
||||
// If the first configuration satisfies, the others are not concidered.
|
||||
// If the first configuration satisfies, the others are not considered.
|
||||
if(bNumEP > 1 && conf != bConfNum)
|
||||
return;
|
||||
|
||||
bConfNum = conf;
|
||||
bIfaceNum = iface;
|
||||
|
||||
uint8_t index;
|
||||
|
||||
if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) {
|
||||
index = epInterruptInIndex;
|
||||
uint8_t index = bNumEP;//epInterruptInIndex; //+ bNumEP;
|
||||
|
||||
// Fill in the endpoint info structure
|
||||
epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
|
||||
epInfo[index].maxPktSize = (uint8_t) pep->wMaxPacketSize;
|
||||
epInfo[index].epAttribs = 0;
|
||||
epInfo[index].bmNakPower = USB_NAK_NOWAIT;
|
||||
|
||||
bNumEP++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -470,28 +482,32 @@ uint8_t HIDBoot<BOOT_PROTOCOL>::Poll() {
|
|||
if(qNextPollTime <= millis()) {
|
||||
qNextPollTime = millis() + 10;
|
||||
|
||||
// To-do: optimize manually, getting rid of the loop
|
||||
for(uint8_t i = 0; i < epMUL; i++) {
|
||||
const uint8_t const_buff_len = 16;
|
||||
uint8_t buf[const_buff_len];
|
||||
|
||||
uint16_t read = (uint16_t) epInfo[epInterruptInIndex].maxPktSize;
|
||||
|
||||
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf);
|
||||
uint16_t read = (uint16_t) epInfo[epInterruptInIndex + i].maxPktSize;
|
||||
|
||||
uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex + i].epAddr, &read, buf);
|
||||
if(!rcode) {
|
||||
if(pRptParser[i])
|
||||
pRptParser[i]->Parse((HID*)this, 0, (uint8_t) read, buf);
|
||||
|
||||
if(rcode) {
|
||||
if(rcode != hrNAK)
|
||||
USBTRACE2("Poll:", rcode);
|
||||
return rcode;
|
||||
}
|
||||
//for (uint8_t i=0; i<read; i++)
|
||||
// PrintHex<uint8_t>(buf[i]);
|
||||
//if (read)
|
||||
// Serial.println("");
|
||||
|
||||
if(pRptParser)
|
||||
pRptParser->Parse((HID*)this, 0, (uint8_t) read, buf);
|
||||
// USB_HOST_SERIAL.println("");
|
||||
} else {
|
||||
if(rcode != hrNAK) {
|
||||
USBTRACE2("Poll:", rcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rcode;
|
||||
}
|
||||
|
||||
|
||||
#endif // __HIDBOOTMOUSE_H__
|
||||
|
|
|
@ -981,9 +981,9 @@ void ReportDescParserBase::Parse(const uint16_t len, const uint8_t *pbuf, const
|
|||
totalSize = 0;
|
||||
|
||||
while (cntdn) {
|
||||
//Serial.println("");
|
||||
//USB_HOST_SERIAL.println("");
|
||||
//PrintHex<uint16_t>(offset + len - cntdn);
|
||||
//Serial.print(":");
|
||||
//USB_HOST_SERIAL.print(":");
|
||||
|
||||
ParseItem(&p, &cntdn);
|
||||
|
||||
|
@ -994,79 +994,79 @@ void ReportDescParserBase::Parse(const uint16_t len, const uint8_t *pbuf, const
|
|||
}
|
||||
|
||||
void ReportDescParserBase::PrintValue(uint8_t *p, uint8_t len) {
|
||||
Notify(PSTR("("), 0x80);
|
||||
E_Notify(PSTR("("), 0x80);
|
||||
for (; len; p++, len--)
|
||||
PrintHex<uint8_t > (*p, 0x80);
|
||||
Notify(PSTR(")"), 0x80);
|
||||
E_Notify(PSTR(")"), 0x80);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintByteValue(uint8_t data) {
|
||||
Notify(PSTR("("), 0x80);
|
||||
E_Notify(PSTR("("), 0x80);
|
||||
PrintHex<uint8_t > (data, 0x80);
|
||||
Notify(PSTR(")"), 0x80);
|
||||
E_Notify(PSTR(")"), 0x80);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintItemTitle(uint8_t prefix) {
|
||||
switch (prefix & (TYPE_MASK | TAG_MASK)) {
|
||||
case (TYPE_GLOBAL | TAG_GLOBAL_PUSH):
|
||||
Notify(PSTR("\r\nPush"), 0x80);
|
||||
E_Notify(PSTR("\r\nPush"), 0x80);
|
||||
break;
|
||||
case (TYPE_GLOBAL | TAG_GLOBAL_POP):
|
||||
Notify(PSTR("\r\nPop"), 0x80);
|
||||
E_Notify(PSTR("\r\nPop"), 0x80);
|
||||
break;
|
||||
case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE):
|
||||
Notify(PSTR("\r\nUsage Page"), 0x80);
|
||||
E_Notify(PSTR("\r\nUsage Page"), 0x80);
|
||||
break;
|
||||
case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN):
|
||||
Notify(PSTR("\r\nLogical Min"), 0x80);
|
||||
E_Notify(PSTR("\r\nLogical Min"), 0x80);
|
||||
break;
|
||||
case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX):
|
||||
Notify(PSTR("\r\nLogical Max"), 0x80);
|
||||
E_Notify(PSTR("\r\nLogical Max"), 0x80);
|
||||
break;
|
||||
case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN):
|
||||
Notify(PSTR("\r\nPhysical Min"), 0x80);
|
||||
E_Notify(PSTR("\r\nPhysical Min"), 0x80);
|
||||
break;
|
||||
case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX):
|
||||
Notify(PSTR("\r\nPhysical Max"), 0x80);
|
||||
E_Notify(PSTR("\r\nPhysical Max"), 0x80);
|
||||
break;
|
||||
case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP):
|
||||
Notify(PSTR("\r\nUnit Exp"), 0x80);
|
||||
E_Notify(PSTR("\r\nUnit Exp"), 0x80);
|
||||
break;
|
||||
case (TYPE_GLOBAL | TAG_GLOBAL_UNIT):
|
||||
Notify(PSTR("\r\nUnit"), 0x80);
|
||||
E_Notify(PSTR("\r\nUnit"), 0x80);
|
||||
break;
|
||||
case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE):
|
||||
Notify(PSTR("\r\nReport Size"), 0x80);
|
||||
E_Notify(PSTR("\r\nReport Size"), 0x80);
|
||||
break;
|
||||
case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT):
|
||||
Notify(PSTR("\r\nReport Count"), 0x80);
|
||||
E_Notify(PSTR("\r\nReport Count"), 0x80);
|
||||
break;
|
||||
case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID):
|
||||
Notify(PSTR("\r\nReport Id"), 0x80);
|
||||
E_Notify(PSTR("\r\nReport Id"), 0x80);
|
||||
break;
|
||||
case (TYPE_LOCAL | TAG_LOCAL_USAGE):
|
||||
Notify(PSTR("\r\nUsage"), 0x80);
|
||||
E_Notify(PSTR("\r\nUsage"), 0x80);
|
||||
break;
|
||||
case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN):
|
||||
Notify(PSTR("\r\nUsage Min"), 0x80);
|
||||
E_Notify(PSTR("\r\nUsage Min"), 0x80);
|
||||
break;
|
||||
case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX):
|
||||
Notify(PSTR("\r\nUsage Max"), 0x80);
|
||||
E_Notify(PSTR("\r\nUsage Max"), 0x80);
|
||||
break;
|
||||
case (TYPE_MAIN | TAG_MAIN_COLLECTION):
|
||||
Notify(PSTR("\r\nCollection"), 0x80);
|
||||
E_Notify(PSTR("\r\nCollection"), 0x80);
|
||||
break;
|
||||
case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION):
|
||||
Notify(PSTR("\r\nEnd Collection"), 0x80);
|
||||
E_Notify(PSTR("\r\nEnd Collection"), 0x80);
|
||||
break;
|
||||
case (TYPE_MAIN | TAG_MAIN_INPUT):
|
||||
Notify(PSTR("\r\nInput"), 0x80);
|
||||
E_Notify(PSTR("\r\nInput"), 0x80);
|
||||
break;
|
||||
case (TYPE_MAIN | TAG_MAIN_OUTPUT):
|
||||
Notify(PSTR("\r\nOutput"), 0x80);
|
||||
E_Notify(PSTR("\r\nOutput"), 0x80);
|
||||
break;
|
||||
case (TYPE_MAIN | TAG_MAIN_FEATURE):
|
||||
Notify(PSTR("\r\nFeature"), 0x80);
|
||||
E_Notify(PSTR("\r\nFeature"), 0x80);
|
||||
break;
|
||||
} // switch (**pp & (TYPE_MASK | TAG_MASK))
|
||||
}
|
||||
|
@ -1150,30 +1150,30 @@ uint8_t ReportDescParserBase::ParseItem(uint8_t **pp, uint16_t *pcntdn) {
|
|||
case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION):
|
||||
switch (data) {
|
||||
case 0x00:
|
||||
Notify(PSTR(" Physical"), 0x80);
|
||||
E_Notify(PSTR(" Physical"), 0x80);
|
||||
break;
|
||||
case 0x01:
|
||||
Notify(PSTR(" Application"), 0x80);
|
||||
E_Notify(PSTR(" Application"), 0x80);
|
||||
break;
|
||||
case 0x02:
|
||||
Notify(PSTR(" Logical"), 0x80);
|
||||
E_Notify(PSTR(" Logical"), 0x80);
|
||||
break;
|
||||
case 0x03:
|
||||
Notify(PSTR(" Report"), 0x80);
|
||||
E_Notify(PSTR(" Report"), 0x80);
|
||||
break;
|
||||
case 0x04:
|
||||
Notify(PSTR(" Named Array"), 0x80);
|
||||
E_Notify(PSTR(" Named Array"), 0x80);
|
||||
break;
|
||||
case 0x05:
|
||||
Notify(PSTR(" Usage Switch"), 0x80);
|
||||
E_Notify(PSTR(" Usage Switch"), 0x80);
|
||||
break;
|
||||
case 0x06:
|
||||
Notify(PSTR(" Usage Modifier"), 0x80);
|
||||
E_Notify(PSTR(" Usage Modifier"), 0x80);
|
||||
break;
|
||||
default:
|
||||
Notify(PSTR(" Vendor Defined("), 0x80);
|
||||
E_Notify(PSTR(" Vendor Defined("), 0x80);
|
||||
PrintHex<uint8_t > (data, 0x80);
|
||||
Notify(PSTR(")"), 0x80);
|
||||
E_Notify(PSTR(")"), 0x80);
|
||||
}
|
||||
break;
|
||||
case (TYPE_MAIN | TAG_MAIN_INPUT):
|
||||
|
@ -1182,9 +1182,9 @@ uint8_t ReportDescParserBase::ParseItem(uint8_t **pp, uint16_t *pcntdn) {
|
|||
totalSize += (uint16_t)rptSize * (uint16_t)rptCount;
|
||||
rptSize = 0;
|
||||
rptCount = 0;
|
||||
Notify(PSTR("("), 0x80);
|
||||
E_Notify(PSTR("("), 0x80);
|
||||
PrintBin<uint8_t > (data, 0x80);
|
||||
Notify(PSTR(")"), 0x80);
|
||||
E_Notify(PSTR(")"), 0x80);
|
||||
break;
|
||||
} // switch (**pp & (TYPE_MASK | TAG_MASK))
|
||||
}
|
||||
|
@ -1216,15 +1216,15 @@ void ReportDescParserBase::SetUsagePage(uint16_t page) {
|
|||
pfUsage = NULL;
|
||||
|
||||
if (page > 0x00 && page < 0x11)
|
||||
pfUsage = /*(UsagePageFunc)pgm_read_word*/(usagePageFunctions[page - 1]);
|
||||
pfUsage = /*(UsagePageFunc)pgm_read_pointer*/(usagePageFunctions[page - 1]);
|
||||
//else if (page > 0x7f && page < 0x84)
|
||||
// Notify(pstrUsagePageMonitor);
|
||||
// E_Notify(pstrUsagePageMonitor);
|
||||
//else if (page > 0x83 && page < 0x8c)
|
||||
// Notify(pstrUsagePagePower);
|
||||
// E_Notify(pstrUsagePagePower);
|
||||
//else if (page > 0x8b && page < 0x92)
|
||||
// Notify((char*)pgm_read_pointer(&usagePageTitles1[page - 0x8c]));
|
||||
// E_Notify((char*)pgm_read_pointer(&usagePageTitles1[page - 0x8c]));
|
||||
//else if (page > 0xfeff && page <= 0xffff)
|
||||
// Notify(pstrUsagePageVendorDefined);
|
||||
// E_Notify(pstrUsagePageVendorDefined);
|
||||
else
|
||||
switch (page) {
|
||||
case 0x14:
|
||||
|
@ -1237,232 +1237,232 @@ void ReportDescParserBase::SetUsagePage(uint16_t page) {
|
|||
}
|
||||
|
||||
void ReportDescParserBase::PrintUsagePage(uint16_t page) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
|
||||
if (page > 0x00 && page < 0x11)
|
||||
Notify((char*)pgm_read_pointer(&usagePageTitles0[page - 1]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&usagePageTitles0[page - 1]), 0x80);
|
||||
else if (page > 0x7f && page < 0x84)
|
||||
Notify(pstrUsagePageMonitor, 0x80);
|
||||
E_Notify(pstrUsagePageMonitor, 0x80);
|
||||
else if (page > 0x83 && page < 0x8c)
|
||||
Notify(pstrUsagePagePower, 0x80);
|
||||
E_Notify(pstrUsagePagePower, 0x80);
|
||||
else if (page > 0x8b && page < 0x92)
|
||||
Notify((char*)pgm_read_pointer(&usagePageTitles1[page - 0x8c]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&usagePageTitles1[page - 0x8c]), 0x80);
|
||||
else if (page > 0xfeff && page <= 0xffff)
|
||||
Notify(pstrUsagePageVendorDefined, 0x80);
|
||||
E_Notify(pstrUsagePageVendorDefined, 0x80);
|
||||
else
|
||||
switch (page) {
|
||||
case 0x14:
|
||||
Notify(pstrUsagePageAlphaNumericDisplay, 0x80);
|
||||
E_Notify(pstrUsagePageAlphaNumericDisplay, 0x80);
|
||||
break;
|
||||
case 0x40:
|
||||
Notify(pstrUsagePageMedicalInstruments, 0x80);
|
||||
E_Notify(pstrUsagePageMedicalInstruments, 0x80);
|
||||
break;
|
||||
default:
|
||||
Notify(pstrUsagePageUndefined, 0x80);
|
||||
E_Notify(pstrUsagePageUndefined, 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintButtonPageUsage(uint16_t usage) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
Notify(PSTR("Btn"), 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
E_Notify(PSTR("Btn"), 0x80);
|
||||
PrintHex<uint16_t > (usage, 0x80);
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
//Serial.print(usage, HEX);
|
||||
E_Notify(PSTR("\r\n"), 0x80);
|
||||
//USB_HOST_SERIAL.print(usage, HEX);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintOrdinalPageUsage(uint16_t usage) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
Notify(PSTR("Inst"), 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
E_Notify(PSTR("Inst"), 0x80);
|
||||
// Sorry, HEX for now...
|
||||
PrintHex<uint16_t > (usage, 0x80);
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
//Serial.print(usage, DEC);
|
||||
E_Notify(PSTR("\r\n"), 0x80);
|
||||
//USB_HOST_SERIAL.print(usage, DEC);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintGenericDesktopPageUsage(uint16_t usage) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
|
||||
if (usage > 0x00 && usage < 0x0a)
|
||||
Notify((char*)pgm_read_pointer(&genDesktopTitles0[usage - 1]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&genDesktopTitles0[usage - 1]), 0x80);
|
||||
else if (usage > 0x2f && usage < 0x49)
|
||||
Notify((char*)pgm_read_pointer(&genDesktopTitles1[usage - 0x30]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&genDesktopTitles1[usage - 0x30]), 0x80);
|
||||
else if (usage > 0x7f && usage < 0x94)
|
||||
Notify((char*)pgm_read_pointer(&genDesktopTitles2[usage - 0x80]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&genDesktopTitles2[usage - 0x80]), 0x80);
|
||||
else if (usage > 0x9f && usage < 0xa9)
|
||||
Notify((char*)pgm_read_pointer(&genDesktopTitles3[usage - 0xa0]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&genDesktopTitles3[usage - 0xa0]), 0x80);
|
||||
else if (usage > 0xaf && usage < 0xb8)
|
||||
Notify((char*)pgm_read_pointer(&genDesktopTitles4[usage - 0xb0]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&genDesktopTitles4[usage - 0xb0]), 0x80);
|
||||
else
|
||||
Notify(pstrUsagePageUndefined, 0x80);
|
||||
E_Notify(pstrUsagePageUndefined, 0x80);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintSimulationControlsPageUsage(uint16_t usage) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
|
||||
if (usage > 0x00 && usage < 0x0d)
|
||||
Notify((char*)pgm_read_pointer(&simuTitles0[usage - 1]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&simuTitles0[usage - 1]), 0x80);
|
||||
else if (usage > 0x1f && usage < 0x26)
|
||||
Notify((char*)pgm_read_pointer(&simuTitles1[usage - 0x20]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&simuTitles1[usage - 0x20]), 0x80);
|
||||
else if (usage > 0xaf && usage < 0xd1)
|
||||
Notify((char*)pgm_read_pointer(&simuTitles2[usage - 0xb0]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&simuTitles2[usage - 0xb0]), 0x80);
|
||||
else
|
||||
Notify(pstrUsagePageUndefined, 0x80);
|
||||
E_Notify(pstrUsagePageUndefined, 0x80);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintVRControlsPageUsage(uint16_t usage) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
|
||||
if (usage > 0x00 && usage < 0x0b)
|
||||
Notify((char*)pgm_read_pointer(&vrTitles0[usage - 1]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&vrTitles0[usage - 1]), 0x80);
|
||||
else if (usage > 0x1f && usage < 0x22)
|
||||
Notify((char*)pgm_read_pointer(&vrTitles1[usage - 0x20]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&vrTitles1[usage - 0x20]), 0x80);
|
||||
else
|
||||
Notify(pstrUsagePageUndefined, 0x80);
|
||||
E_Notify(pstrUsagePageUndefined, 0x80);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintSportsControlsPageUsage(uint16_t usage) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
|
||||
if (usage > 0x00 && usage < 0x05)
|
||||
Notify((char*)pgm_read_pointer(&sportsCtrlTitles0[usage - 1]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&sportsCtrlTitles0[usage - 1]), 0x80);
|
||||
else if (usage > 0x2f && usage < 0x3a)
|
||||
Notify((char*)pgm_read_pointer(&sportsCtrlTitles1[usage - 0x30]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&sportsCtrlTitles1[usage - 0x30]), 0x80);
|
||||
else if (usage > 0x4f && usage < 0x64)
|
||||
Notify((char*)pgm_read_pointer(&sportsCtrlTitles2[usage - 0x50]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&sportsCtrlTitles2[usage - 0x50]), 0x80);
|
||||
else
|
||||
Notify(pstrUsagePageUndefined, 0x80);
|
||||
E_Notify(pstrUsagePageUndefined, 0x80);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintGameControlsPageUsage(uint16_t usage) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
|
||||
if (usage > 0x00 && usage < 0x04)
|
||||
Notify((char*)pgm_read_pointer(&gameTitles0[usage - 1]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&gameTitles0[usage - 1]), 0x80);
|
||||
else if (usage > 0x1f && usage < 0x3a)
|
||||
Notify((char*)pgm_read_pointer(&gameTitles1[usage - 0x20]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&gameTitles1[usage - 0x20]), 0x80);
|
||||
else
|
||||
Notify(pstrUsagePageUndefined, 0x80);
|
||||
E_Notify(pstrUsagePageUndefined, 0x80);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintGenericDeviceControlsPageUsage(uint16_t usage) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
|
||||
if (usage > 0x1f && usage < 0x27)
|
||||
Notify((char*)pgm_read_pointer(&genDevCtrlTitles[usage - 0x20]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&genDevCtrlTitles[usage - 0x20]), 0x80);
|
||||
else
|
||||
Notify(pstrUsagePageUndefined, 0x80);
|
||||
E_Notify(pstrUsagePageUndefined, 0x80);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintLEDPageUsage(uint16_t usage) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
|
||||
if (usage > 0x00 && usage < 0x4e)
|
||||
Notify((char*)pgm_read_pointer(&ledTitles[usage - 1]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&ledTitles[usage - 1]), 0x80);
|
||||
else
|
||||
Notify(pstrUsagePageUndefined, 0x80);
|
||||
E_Notify(pstrUsagePageUndefined, 0x80);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintTelephonyPageUsage(uint16_t usage) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
|
||||
if (usage > 0x00 && usage < 0x08)
|
||||
Notify((char*)pgm_read_pointer(&telTitles0[usage - 1]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&telTitles0[usage - 1]), 0x80);
|
||||
else if (usage > 0x1f && usage < 0x32)
|
||||
Notify((char*)pgm_read_pointer(&telTitles1[usage - 0x1f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&telTitles1[usage - 0x1f]), 0x80);
|
||||
else if (usage > 0x4f && usage < 0x54)
|
||||
Notify((char*)pgm_read_pointer(&telTitles2[usage - 0x4f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&telTitles2[usage - 0x4f]), 0x80);
|
||||
else if (usage > 0x6f && usage < 0x75)
|
||||
Notify((char*)pgm_read_pointer(&telTitles3[usage - 0x6f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&telTitles3[usage - 0x6f]), 0x80);
|
||||
else if (usage > 0x8f && usage < 0x9f)
|
||||
Notify((char*)pgm_read_pointer(&telTitles4[usage - 0x8f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&telTitles4[usage - 0x8f]), 0x80);
|
||||
else if (usage > 0xaf && usage < 0xc0)
|
||||
Notify((char*)pgm_read_pointer(&telTitles5[usage - 0xaf]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&telTitles5[usage - 0xaf]), 0x80);
|
||||
else
|
||||
Notify(pstrUsagePageUndefined, 0x80);
|
||||
E_Notify(pstrUsagePageUndefined, 0x80);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintConsumerPageUsage(uint16_t usage) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
|
||||
if (usage > 0x00 && usage < 0x07)
|
||||
Notify((char*)pgm_read_pointer(&consTitles0[usage - 1]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitles0[usage - 1]), 0x80);
|
||||
else if (usage > 0x1f && usage < 0x23)
|
||||
Notify((char*)pgm_read_pointer(&consTitles1[usage - 0x1f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitles1[usage - 0x1f]), 0x80);
|
||||
else if (usage > 0x2f && usage < 0x37)
|
||||
Notify((char*)pgm_read_pointer(&consTitles2[usage - 0x2f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitles2[usage - 0x2f]), 0x80);
|
||||
else if (usage > 0x3f && usage < 0x49)
|
||||
Notify((char*)pgm_read_pointer(&consTitles3[usage - 0x3f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitles3[usage - 0x3f]), 0x80);
|
||||
else if (usage > 0x5f && usage < 0x67)
|
||||
Notify((char*)pgm_read_pointer(&consTitles4[usage - 0x5f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitles4[usage - 0x5f]), 0x80);
|
||||
else if (usage > 0x7f && usage < 0xa5)
|
||||
Notify((char*)pgm_read_pointer(&consTitles5[usage - 0x7f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitles5[usage - 0x7f]), 0x80);
|
||||
else if (usage > 0xaf && usage < 0xcf)
|
||||
Notify((char*)pgm_read_pointer(&consTitles6[usage - 0xaf]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitles6[usage - 0xaf]), 0x80);
|
||||
else if (usage > 0xdf && usage < 0xeb)
|
||||
Notify((char*)pgm_read_pointer(&consTitles7[usage - 0xdf]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitles7[usage - 0xdf]), 0x80);
|
||||
else if (usage > 0xef && usage < 0xf6)
|
||||
Notify((char*)pgm_read_pointer(&consTitles8[usage - 0xef]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitles8[usage - 0xef]), 0x80);
|
||||
else if (usage > 0xff && usage < 0x10e)
|
||||
Notify((char*)pgm_read_pointer(&consTitles9[usage - 0xff]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitles9[usage - 0xff]), 0x80);
|
||||
else if (usage > 0x14f && usage < 0x156)
|
||||
Notify((char*)pgm_read_pointer(&consTitlesA[usage - 0x14f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitlesA[usage - 0x14f]), 0x80);
|
||||
else if (usage > 0x15f && usage < 0x16b)
|
||||
Notify((char*)pgm_read_pointer(&consTitlesB[usage - 0x15f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitlesB[usage - 0x15f]), 0x80);
|
||||
else if (usage > 0x16f && usage < 0x175)
|
||||
Notify((char*)pgm_read_pointer(&consTitlesC[usage - 0x16f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitlesC[usage - 0x16f]), 0x80);
|
||||
else if (usage > 0x17f && usage < 0x1c8)
|
||||
Notify((char*)pgm_read_pointer(&consTitlesD[usage - 0x17f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitlesD[usage - 0x17f]), 0x80);
|
||||
else if (usage > 0x1ff && usage < 0x29d)
|
||||
Notify((char*)pgm_read_pointer(&consTitlesE[usage - 0x1ff]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&consTitlesE[usage - 0x1ff]), 0x80);
|
||||
else
|
||||
Notify(pstrUsagePageUndefined, 0x80);
|
||||
E_Notify(pstrUsagePageUndefined, 0x80);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintDigitizerPageUsage(uint16_t usage) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
|
||||
if (usage > 0x00 && usage < 0x0e)
|
||||
Notify((char*)pgm_read_pointer(&digitTitles0[usage - 1]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&digitTitles0[usage - 1]), 0x80);
|
||||
else if (usage > 0x1f && usage < 0x23)
|
||||
Notify((char*)pgm_read_pointer(&digitTitles1[usage - 0x1f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&digitTitles1[usage - 0x1f]), 0x80);
|
||||
else if (usage > 0x2f && usage < 0x47)
|
||||
Notify((char*)pgm_read_pointer(&digitTitles2[usage - 0x2f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&digitTitles2[usage - 0x2f]), 0x80);
|
||||
else
|
||||
Notify(pstrUsagePageUndefined, 0x80);
|
||||
E_Notify(pstrUsagePageUndefined, 0x80);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintAlphanumDisplayPageUsage(uint16_t usage) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
|
||||
if (usage > 0x00 && usage < 0x03)
|
||||
Notify((char*)pgm_read_pointer(&aplphanumTitles0[usage - 1]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&aplphanumTitles0[usage - 1]), 0x80);
|
||||
else if (usage > 0x1f && usage < 0x4e)
|
||||
Notify((char*)pgm_read_pointer(&aplphanumTitles1[usage - 0x1f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&aplphanumTitles1[usage - 0x1f]), 0x80);
|
||||
else if (usage > 0x7f && usage < 0x96)
|
||||
Notify((char*)pgm_read_pointer(&digitTitles2[usage - 0x80]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&digitTitles2[usage - 0x80]), 0x80);
|
||||
else
|
||||
Notify(pstrUsagePageUndefined, 0x80);
|
||||
E_Notify(pstrUsagePageUndefined, 0x80);
|
||||
}
|
||||
|
||||
void ReportDescParserBase::PrintMedicalInstrumentPageUsage(uint16_t usage) {
|
||||
Notify(pstrSpace, 0x80);
|
||||
E_Notify(pstrSpace, 0x80);
|
||||
|
||||
if (usage == 1)
|
||||
Notify(pstrUsageMedicalUltrasound, 0x80);
|
||||
E_Notify(pstrUsageMedicalUltrasound, 0x80);
|
||||
else if (usage > 0x1f && usage < 0x28)
|
||||
Notify((char*)pgm_read_pointer(&medInstrTitles0[usage - 0x1f]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&medInstrTitles0[usage - 0x1f]), 0x80);
|
||||
else if (usage > 0x3f && usage < 0x45)
|
||||
Notify((char*)pgm_read_pointer(&medInstrTitles1[usage - 0x40]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&medInstrTitles1[usage - 0x40]), 0x80);
|
||||
else if (usage > 0x5f && usage < 0x62)
|
||||
Notify((char*)pgm_read_pointer(&medInstrTitles2[usage - 0x60]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&medInstrTitles2[usage - 0x60]), 0x80);
|
||||
else if (usage == 0x70)
|
||||
Notify(pstrUsageDepthGainCompensation, 0x80);
|
||||
E_Notify(pstrUsageDepthGainCompensation, 0x80);
|
||||
else if (usage > 0x7f && usage < 0x8a)
|
||||
Notify((char*)pgm_read_pointer(&medInstrTitles3[usage - 0x80]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&medInstrTitles3[usage - 0x80]), 0x80);
|
||||
else if (usage > 0x9f && usage < 0xa2)
|
||||
Notify((char*)pgm_read_pointer(&medInstrTitles4[usage - 0xa0]), 0x80);
|
||||
E_Notify((char*)pgm_read_pointer(&medInstrTitles4[usage - 0xa0]), 0x80);
|
||||
else
|
||||
Notify(pstrUsagePageUndefined, 0x80);
|
||||
E_Notify(pstrUsagePageUndefined, 0x80);
|
||||
}
|
||||
|
||||
uint8_t ReportDescParser2::ParseItem(uint8_t **pp, uint16_t *pcntdn) {
|
||||
|
@ -1613,7 +1613,7 @@ void ReportDescParser2::OnInputItem(uint8_t itm) {
|
|||
}
|
||||
PrintByteValue(result.dwResult);
|
||||
}
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
E_Notify(PSTR("\r\n"), 0x80);
|
||||
}
|
||||
|
||||
void UniversalReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
|
||||
|
|
|
@ -17,24 +17,6 @@ e-mail : support@circuitsathome.com
|
|||
#if !defined(__HIDDESCRIPTORPARSER_H__)
|
||||
#define __HIDDESCRIPTORPARSER_H__
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >=100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "avrpins.h"
|
||||
#include "max3421e.h"
|
||||
#include "usbhost.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "Usb.h"
|
||||
|
||||
#include "printhex.h"
|
||||
#include "hexdump.h"
|
||||
#include "message.h"
|
||||
#include "confdescparser.h"
|
||||
#include "hid.h"
|
||||
|
||||
class ReportDescParserBase : public USBReadParser {
|
||||
|
|
|
@ -147,6 +147,8 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
return rcode;
|
||||
}
|
||||
|
||||
delay( 2 ); //per USB 2.0 sect.9.2.6.3
|
||||
|
||||
USBTRACE2("Addr:", bAddress);
|
||||
|
||||
p->lowspeed = false;
|
||||
|
@ -221,27 +223,39 @@ uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
|
|||
return 0;
|
||||
|
||||
FailGetDevDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetDevDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetDevTblEntry:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetDevTblEntry();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailGetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailGetConfDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
FailSetConfDescr:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFailSetConfDescr();
|
||||
goto Fail;
|
||||
#endif
|
||||
|
||||
|
||||
FailSetIdle:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
USBTRACE("SetIdle:");
|
||||
#endif
|
||||
|
||||
Fail:
|
||||
#ifdef DEBUG_USB_HOST
|
||||
NotifyFail(rcode);
|
||||
#endif
|
||||
Release();
|
||||
return rcode;
|
||||
}
|
||||
|
@ -362,7 +376,7 @@ uint8_t HIDUniversal::Poll() {
|
|||
Notify(PSTR("\r\nBuf: "), 0x80);
|
||||
|
||||
for (uint8_t i = 0; i < read; i++)
|
||||
PrintHex<uint8_t > (buf[i], 0x80);
|
||||
D_PrintHex<uint8_t > (buf[i], 0x80);
|
||||
|
||||
Notify(PSTR("\r\n"), 0x80);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
####################################################
|
||||
|
||||
USB KEYWORD1
|
||||
USBHub KEYWORD1
|
||||
|
||||
####################################################
|
||||
# Syntax Coloring Map For BTD (Bluetooth) Library
|
||||
|
@ -56,10 +57,13 @@ setLedToggle KEYWORD2
|
|||
moveSetBulb KEYWORD2
|
||||
moveSetRumble KEYWORD2
|
||||
|
||||
attachOnInit KEYWORD2
|
||||
|
||||
PS3Connected KEYWORD2
|
||||
PS3MoveConnected KEYWORD2
|
||||
PS3NavigationConnected KEYWORD2
|
||||
|
||||
isReady KEYWORD2
|
||||
watingForConnection KEYWORD2
|
||||
|
||||
####################################################
|
||||
|
@ -161,6 +165,7 @@ RumbleLow LITERAL1
|
|||
####################################################
|
||||
|
||||
XBOXUSB KEYWORD1
|
||||
XBOXOLD KEYWORD1
|
||||
XBOXRECV KEYWORD1
|
||||
|
||||
####################################################
|
||||
|
@ -192,6 +197,9 @@ BACK LITERAL1
|
|||
XBOX LITERAL1
|
||||
SYNC LITERAL1
|
||||
|
||||
BLACK LITERAL1
|
||||
WHITE LITERAL1
|
||||
|
||||
A LITERAL1
|
||||
B LITERAL1
|
||||
X LITERAL1
|
||||
|
|
65
macros.h
Normal file
65
macros.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* File: macros.h
|
||||
* Author: AJK
|
||||
*
|
||||
* Created on September 23, 2013, 12:31 AM
|
||||
*/
|
||||
|
||||
#if !defined(_usb_h_) || defined(MACROS_H)
|
||||
#error "Never include macros.h directly; include Usb.h instead"
|
||||
#else
|
||||
#define MACROS_H
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// HANDY MACROS
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
|
||||
#ifndef __BYTE_GRABBING_DEFINED__
|
||||
#define __BYTE_GRABBING_DEFINED__ 1
|
||||
#ifdef BROKEN_OPTIMIZER_LITTLE_ENDIAN
|
||||
// Note: Use this if your compiler generates horrible assembler!
|
||||
#define BGRAB0(__usi__) (((uint8_t *)&(__usi__))[0])
|
||||
#define BGRAB1(__usi__) (((uint8_t *)&(__usi__))[1])
|
||||
#define BGRAB2(__usi__) (((uint8_t *)&(__usi__))[2])
|
||||
#define BGRAB3(__usi__) (((uint8_t *)&(__usi__))[3])
|
||||
#define BGRAB4(__usi__) (((uint8_t *)&(__usi__))[4])
|
||||
#define BGRAB5(__usi__) (((uint8_t *)&(__usi__))[5])
|
||||
#define BGRAB6(__usi__) (((uint8_t *)&(__usi__))[6])
|
||||
#define BGRAB7(__usi__) (((uint8_t *)&(__usi__))[7])
|
||||
#else
|
||||
// Note: The cast alone to uint8_t is actually enough.
|
||||
// GCC throws out the "& 0xff", and the size is no different.
|
||||
// Some compilers need it.
|
||||
#define BGRAB0(__usi__) ((uint8_t)((__usi__) & 0xff ))
|
||||
#define BGRAB1(__usi__) ((uint8_t)(((__usi__) >> 8) & 0xff))
|
||||
#define BGRAB2(__usi__) ((uint8_t)(((__usi__) >> 16) & 0xff))
|
||||
#define BGRAB3(__usi__) ((uint8_t)(((__usi__) >> 24) & 0xff))
|
||||
#define BGRAB4(__usi__) ((uint8_t)(((__usi__) >> 32) & 0xff))
|
||||
#define BGRAB5(__usi__) ((uint8_t)(((__usi__) >> 40) & 0xff))
|
||||
#define BGRAB6(__usi__) ((uint8_t)(((__usi__) >> 48) & 0xff))
|
||||
#define BGRAB7(__usi__) ((uint8_t)(((__usi__) >> 56) & 0xff))
|
||||
#endif
|
||||
#define BOVER1(__usi__) ((uint16_t)(__usi__) << 8)
|
||||
#define BOVER2(__usi__) ((uint32_t)(__usi__) << 16)
|
||||
#define BOVER3(__usi__) ((uint32_t)(__usi__) << 24)
|
||||
#define BOVER4(__usi__) ((uint64_t)(__usi__) << 32)
|
||||
#define BOVER5(__usi__) ((uint64_t)(__usi__) << 40)
|
||||
#define BOVER6(__usi__) ((uint64_t)(__usi__) << 48)
|
||||
#define BOVER7(__usi__) ((uint64_t)(__usi__) << 56)
|
||||
|
||||
// These are the smallest and fastest ways I have found so far in pure C/C++.
|
||||
#define BMAKE16(__usc1__,__usc0__) ((uint16_t)((uint16_t)(__usc0__) | (uint16_t)BOVER1(__usc1__)))
|
||||
#define BMAKE32(__usc3__,__usc2__,__usc1__,__usc0__) ((uint32_t)((uint32_t)(__usc0__) | (uint32_t)BOVER1(__usc1__) | (uint32_t)BOVER2(__usc2__) | (uint32_t)BOVER3(__usc3__)))
|
||||
#define BMAKE64(__usc7__,__usc6__,__usc5__,__usc4__,__usc3__,__usc2__,__usc1__,__usc0__) ((uint64_t)((uint64_t)__usc0__ | (uint64_t)BOVER1(__usc1__) | (uint64_t)BOVER2(__usc2__) | (uint64_t)BOVER3(__usc3__) | (uint64_t)BOVER4(__usc4__) | (uint64_t)BOVER5(__usc5__) | (uint64_t)BOVER6(__usc6__) | (uint64_t)BOVER1(__usc7__)))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Debug macros: Strings are stored in progmem (flash) instead of RAM.
|
||||
*/
|
||||
#define USBTRACE(s) (Notify(PSTR(s), 0x80))
|
||||
#define USBTRACE2(s,r) (Notify(PSTR(s), 0x80), D_PrintHex((r), 0x80), Notify(PSTR("\r\n"), 0x80))
|
||||
|
||||
|
||||
#endif /* MACROS_H */
|
||||
|
1398
masstorage.cpp
1398
masstorage.cpp
File diff suppressed because it is too large
Load diff
392
masstorage.h
392
masstorage.h
|
@ -1,26 +1,13 @@
|
|||
#if !defined(__MASSTORAGE_H__)
|
||||
#define __MASSTORAGE_H__
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >=100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
// Cruft removal, makes driver smaller, faster.
|
||||
#ifndef MS_WANT_PARSER
|
||||
#define MS_WANT_PARSER 0
|
||||
#endif
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "avrpins.h"
|
||||
#include <avr/pgmspace.h>
|
||||
#include "max3421e.h"
|
||||
#include "usbhost.h"
|
||||
#include "usb_ch9.h"
|
||||
#include "Usb.h"
|
||||
|
||||
#include <confdescparser.h>
|
||||
|
||||
#define SWAP(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
|
||||
|
||||
#define bmREQ_MASSOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||
#define bmREQ_MASSIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
|
||||
|
||||
|
@ -52,32 +39,98 @@
|
|||
#define MASS_CBW_SIGNATURE 0x43425355
|
||||
#define MASS_CSW_SIGNATURE 0x53425355
|
||||
|
||||
#define MASS_CMD_DIR_OUT (0 << 7)
|
||||
#define MASS_CMD_DIR_IN (1 << 7)
|
||||
#define MASS_CMD_DIR_OUT 0 // (0 << 7)
|
||||
#define MASS_CMD_DIR_IN 0x80 //(1 << 7)
|
||||
|
||||
#define SCSI_CMD_INQUIRY 0x12
|
||||
#define SCSI_CMD_REPORT_LUNS 0xA0
|
||||
/*
|
||||
* Reference documents from T10 (http://www.t10.org)
|
||||
* SCSI Primary Commands - 3 (SPC-3)
|
||||
* SCSI Block Commands - 2 (SBC-2)
|
||||
* Multi-Media Commands - 5 (MMC-5)
|
||||
*/
|
||||
|
||||
/* Group 1 commands (CDB's here are should all be 6-bytes) */
|
||||
#define SCSI_CMD_TEST_UNIT_READY 0x00
|
||||
#define SCSI_CMD_REQUEST_SENSE 0x03
|
||||
#define SCSI_CMD_FORMAT_UNIT 0x04
|
||||
#define SCSI_CMD_READ_6 0x08
|
||||
#define SCSI_CMD_READ_10 0x28
|
||||
#define SCSI_CMD_READ_CAPACITY_10 0x25
|
||||
#define SCSI_CMD_TEST_UNIT_READY 0x00
|
||||
#define SCSI_CMD_WRITE_6 0x0A
|
||||
#define SCSI_CMD_WRITE_10 0x2A
|
||||
#define SCSI_CMD_INQUIRY 0x12
|
||||
#define SCSI_CMD_MODE_SELECT_6 0x15
|
||||
#define SCSI_CMD_MODE_SENSE_6 0x1A
|
||||
#define SCSI_CMD_MODE_SENSE_10 0x5A
|
||||
#define SCSI_CMD_START_STOP_UNIT 0x1B
|
||||
#define SCSI_CMD_PREVENT_REMOVAL 0x1E
|
||||
/* Group 2 Commands (CDB's here are 10-bytes) */
|
||||
#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23
|
||||
#define SCSI_CMD_READ_CAPACITY_10 0x25
|
||||
#define SCSI_CMD_READ_10 0x28
|
||||
#define SCSI_CMD_WRITE_10 0x2A
|
||||
#define SCSI_CMD_SEEK_10 0x2B
|
||||
#define SCSI_CMD_ERASE_10 0x2C
|
||||
#define SCSI_CMD_WRITE_AND_VERIFY_10 0x2E
|
||||
#define SCSI_CMD_VERIFY_10 0x2F
|
||||
#define SCSI_CMD_SYNCHRONIZE_CACHE 0x35
|
||||
#define SCSI_CMD_WRITE_BUFFER 0x3B
|
||||
#define SCSI_CMD_READ_BUFFER 0x3C
|
||||
#define SCSI_CMD_READ_SUBCHANNEL 0x42
|
||||
#define SCSI_CMD_READ_TOC 0x43
|
||||
#define SCSI_CMD_READ_HEADER 0x44
|
||||
#define SCSI_CMD_PLAY_AUDIO_10 0x45
|
||||
#define SCSI_CMD_GET_CONFIGURATION 0x46
|
||||
#define SCSI_CMD_PLAY_AUDIO_MSF 0x47
|
||||
#define SCSI_CMD_PLAY_AUDIO_TI 0x48
|
||||
#define SCSI_CMD_PLAY_TRACK_REL_10 0x49
|
||||
#define SCSI_CMD_GET_EVENT_STATUS 0x4A
|
||||
#define SCSI_CMD_PAUSE_RESUME 0x4B
|
||||
#define SCSI_CMD_READ_DISC_INFORMATION 0x51
|
||||
#define SCSI_CMD_READ_TRACK_INFORMATION 0x52
|
||||
#define SCSI_CMD_RESERVE_TRACK 0x53
|
||||
#define SCSI_CMD_SEND_OPC_INFORMATION 0x54
|
||||
#define SCSI_CMD_MODE_SELECT_10 0x55
|
||||
#define SCSI_CMD_REPAIR_TRACK 0x58
|
||||
#define SCSI_CMD_MODE_SENSE_10 0x5A
|
||||
#define SCSI_CMD_CLOSE_TRACK_SESSION 0x5B
|
||||
#define SCSI_CMD_READ_BUFFER_CAPACITY 0x5C
|
||||
#define SCSI_CMD_SEND_CUE_SHEET 0x5D
|
||||
/* Group 5 Commands (CDB's here are 12-bytes) */
|
||||
#define SCSI_CMD_REPORT_LUNS 0xA0
|
||||
#define SCSI_CMD_BLANK 0xA1
|
||||
#define SCSI_CMD_SECURITY_PROTOCOL_IN 0xA2
|
||||
#define SCSI_CMD_SEND_KEY 0xA3
|
||||
#define SCSI_CMD_REPORT_KEY 0xA4
|
||||
#define SCSI_CMD_PLAY_AUDIO_12 0xA5
|
||||
#define SCSI_CMD_LOAD_UNLOAD 0xA6
|
||||
#define SCSI_CMD_SET_READ_AHEAD 0xA7
|
||||
#define SCSI_CMD_READ_12 0xA8
|
||||
#define SCSI_CMD_PLAY_TRACK_REL_12 0xA9
|
||||
#define SCSI_CMD_WRITE_12 0xAA
|
||||
#define SCSI_CMD_READ_MEDIA_SERIAL_12 0xAB
|
||||
#define SCSI_CMD_GET_PERFORMANCE 0xAC
|
||||
#define SCSI_CMD_READ_DVD_STRUCTURE 0xAD
|
||||
#define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xB5
|
||||
#define SCSI_CMD_SET_STREAMING 0xB6
|
||||
#define SCSI_CMD_READ_MSF 0xB9
|
||||
#define SCSI_CMD_SET_SPEED 0xBB
|
||||
#define SCSI_CMD_MECHANISM_STATUS 0xBD
|
||||
#define SCSI_CMD_READ_CD 0xBE
|
||||
#define SCSI_CMD_SEND_DISC_STRUCTURE 0xBF
|
||||
/* Vendor-unique Commands, included for completeness */
|
||||
#define SCSI_CMD_CD_PLAYBACK_STATUS 0xC4 /* SONY unique */
|
||||
#define SCSI_CMD_PLAYBACK_CONTROL 0xC9 /* SONY unique */
|
||||
#define SCSI_CMD_READ_CDDA 0xD8 /* Vendor unique */
|
||||
#define SCSI_CMD_READ_CDXA 0xDB /* Vendor unique */
|
||||
#define SCSI_CMD_READ_ALL_SUBCODES 0xDF /* Vendor unique */
|
||||
|
||||
/* SCSI error codes */
|
||||
#define SCSI_S_NOT_READY 0x02
|
||||
#define SCSI_S_MEDIUM_ERROR 0x03
|
||||
#define SCSI_S_ILLEGAL_REQUEST 0x05
|
||||
#define SCSI_S_UNIT_ATTENTION 0x06
|
||||
|
||||
#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
|
||||
#define SCSI_ASC_LBA_OUT_OF_RANGE 0x21
|
||||
#define SCSI_ASC_MEDIA_CHANGED 0x28
|
||||
#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
|
||||
|
||||
|
||||
/* USB error codes */
|
||||
#define MASS_ERR_SUCCESS 0x00
|
||||
#define MASS_ERR_PHASE_ERROR 0x02
|
||||
#define MASS_ERR_UNIT_NOT_READY 0x03
|
||||
|
@ -87,9 +140,15 @@
|
|||
#define MASS_ERR_INVALID_CSW 0x07
|
||||
#define MASS_ERR_NO_MEDIA 0x08
|
||||
#define MASS_ERR_BAD_LBA 0x09
|
||||
#define MASS_ERR_MEDIA_CHANGED 0x0A
|
||||
#define MASS_ERR_DEVICE_DISCONNECTED 0x11
|
||||
#define MASS_ERR_UNABLE_TO_RECOVER 0x12 // Reset recovery error
|
||||
#define MASS_ERR_INVALID_LUN 0x13
|
||||
#define MASS_ERR_WRITE_STALL 0x14
|
||||
#define MASS_ERR_READ_NAKS 0x15
|
||||
#define MASS_ERR_WRITE_NAKS 0x16
|
||||
#define MASS_ERR_WRITE_PROTECTED 0x17
|
||||
#define MASS_ERR_NOT_IMPLEMENTED 0xFD
|
||||
#define MASS_ERR_GENERAL_SCSI_ERROR 0xFE
|
||||
#define MASS_ERR_GENERAL_USB_ERROR 0xFF
|
||||
#define MASS_ERR_USER 0xA0 // For subclasses to define their own error codes
|
||||
|
@ -98,12 +157,151 @@
|
|||
#define MASS_TRANS_FLG_NO_STALL_CHECK 0x02 // STALL condition is not checked
|
||||
#define MASS_TRANS_FLG_NO_PHASE_CHECK 0x04 // PHASE_ERROR is not checked
|
||||
|
||||
#define MASS_MAX_ENDPOINTS 3
|
||||
|
||||
struct Capacity {
|
||||
uint8_t data[8];
|
||||
//uint32_t dwBlockAddress;
|
||||
//uint32_t dwBlockLength;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct BASICCDB {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned unused : 5;
|
||||
unsigned LUN : 3;
|
||||
|
||||
uint8_t info[12];
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef BASICCDB BASICCDB_t;
|
||||
|
||||
struct CDB6 {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned LBAMSB : 5;
|
||||
unsigned LUN : 3;
|
||||
|
||||
uint8_t LBAHB;
|
||||
uint8_t LBALB;
|
||||
uint8_t AllocationLength;
|
||||
uint8_t Control;
|
||||
|
||||
public:
|
||||
|
||||
CDB6(uint8_t _Opcode, uint8_t _LUN, uint32_t LBA, uint8_t _AllocationLength, uint8_t _Control) :
|
||||
Opcode(_Opcode), LUN(_LUN), LBAMSB(BGRAB2(LBA) & 0x1f), LBAHB(BGRAB1(LBA)), LBALB(BGRAB0(LBA)),
|
||||
AllocationLength(_AllocationLength), Control(_Control) {
|
||||
}
|
||||
|
||||
CDB6(uint8_t _Opcode, uint8_t _LUN, uint8_t _AllocationLength, uint8_t _Control) :
|
||||
Opcode(_Opcode), LUN(_LUN), LBAMSB(0), LBAHB(0), LBALB(0),
|
||||
AllocationLength(_AllocationLength), Control(_Control) {
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef CDB6 CDB6_t;
|
||||
|
||||
struct CDB10 {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned Service_Action : 5;
|
||||
unsigned LUN : 3;
|
||||
|
||||
uint8_t LBA_L_M_MB;
|
||||
uint8_t LBA_L_M_LB;
|
||||
uint8_t LBA_L_L_MB;
|
||||
uint8_t LBA_L_L_LB;
|
||||
|
||||
uint8_t Misc2;
|
||||
|
||||
uint8_t ALC_MB;
|
||||
uint8_t ALC_LB;
|
||||
|
||||
uint8_t Control;
|
||||
public:
|
||||
|
||||
CDB10(uint8_t _Opcode, uint8_t _LUN) :
|
||||
Opcode(_Opcode), Service_Action(0), LUN(_LUN),
|
||||
LBA_L_M_MB(0), LBA_L_M_LB(0), LBA_L_L_MB(0), LBA_L_L_LB(0),
|
||||
Misc2(0), ALC_MB(0), ALC_LB(0), Control(0) {
|
||||
}
|
||||
|
||||
CDB10(uint8_t _Opcode, uint8_t _LUN, uint16_t xflen, uint32_t _LBA) :
|
||||
Opcode(_Opcode), Service_Action(0), LUN(_LUN),
|
||||
LBA_L_M_MB(BGRAB3(_LBA)), LBA_L_M_LB(BGRAB2(_LBA)), LBA_L_L_MB(BGRAB1(_LBA)), LBA_L_L_LB(BGRAB0(_LBA)),
|
||||
Misc2(0), ALC_MB(BGRAB1(xflen)), ALC_LB(BGRAB0(xflen)), Control(0) {
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef CDB10 CDB10_t;
|
||||
|
||||
struct CDB12 {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned Service_Action : 5;
|
||||
unsigned Misc : 3;
|
||||
|
||||
uint8_t LBA_L_M_LB;
|
||||
uint8_t LBA_L_L_MB;
|
||||
uint8_t LBA_L_L_LB;
|
||||
|
||||
uint8_t ALC_M_LB;
|
||||
uint8_t ALC_L_MB;
|
||||
uint8_t ALC_L_LB;
|
||||
uint8_t Control;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef CDB12 CDB12_t;
|
||||
|
||||
struct CDB_LBA32_16 {
|
||||
uint8_t Opcode;
|
||||
|
||||
unsigned Service_Action : 5;
|
||||
unsigned Misc : 3;
|
||||
|
||||
uint8_t LBA_L_M_MB;
|
||||
uint8_t LBA_L_M_LB;
|
||||
uint8_t LBA_L_L_MB;
|
||||
uint8_t LBA_L_L_LB;
|
||||
|
||||
uint8_t A_M_M_MB;
|
||||
uint8_t A_M_M_LB;
|
||||
uint8_t A_M_L_MB;
|
||||
uint8_t A_M_L_LB;
|
||||
|
||||
uint8_t ALC_M_MB;
|
||||
uint8_t ALC_M_LB;
|
||||
uint8_t ALC_L_MB;
|
||||
uint8_t ALC_L_LB;
|
||||
|
||||
uint8_t Misc2;
|
||||
uint8_t Control;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CDB_LBA64_16 {
|
||||
uint8_t Opcode;
|
||||
uint8_t Misc;
|
||||
|
||||
uint8_t LBA_M_M_MB;
|
||||
uint8_t LBA_M_M_LB;
|
||||
uint8_t LBA_M_L_MB;
|
||||
uint8_t LBA_M_L_LB;
|
||||
|
||||
uint8_t LBA_L_M_MB;
|
||||
uint8_t LBA_L_M_LB;
|
||||
uint8_t LBA_L_L_MB;
|
||||
uint8_t LBA_L_L_LB;
|
||||
|
||||
uint8_t ALC_M_MB;
|
||||
uint8_t ALC_M_LB;
|
||||
uint8_t ALC_L_MB;
|
||||
uint8_t ALC_L_LB;
|
||||
|
||||
uint8_t Misc2;
|
||||
uint8_t Control;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct InquiryResponse {
|
||||
uint8_t DeviceType : 5;
|
||||
uint8_t PeripheralQualifier : 3;
|
||||
|
@ -114,13 +312,29 @@ struct InquiryResponse {
|
|||
uint8_t Version;
|
||||
|
||||
unsigned ResponseDataFormat : 4;
|
||||
unsigned Reserved2 : 1;
|
||||
unsigned HISUP : 1;
|
||||
unsigned NormACA : 1;
|
||||
unsigned TrmTsk : 1;
|
||||
unsigned AERC : 1;
|
||||
|
||||
uint8_t AdditionalLength;
|
||||
uint8_t Reserved3[2];
|
||||
//uint8_t Reserved3[2];
|
||||
|
||||
unsigned PROTECT : 1;
|
||||
unsigned Res : 2;
|
||||
unsigned ThreePC : 1;
|
||||
unsigned TPGS : 2;
|
||||
unsigned ACC : 1;
|
||||
unsigned SCCS : 1;
|
||||
|
||||
unsigned ADDR16 : 1;
|
||||
unsigned R1 : 1;
|
||||
unsigned R2 : 1;
|
||||
unsigned MCHNGR : 1;
|
||||
unsigned MULTIP : 1;
|
||||
unsigned VS : 1;
|
||||
unsigned ENCSERV : 1;
|
||||
unsigned BQUE : 1;
|
||||
|
||||
unsigned SoftReset : 1;
|
||||
unsigned CmdQue : 1;
|
||||
|
@ -141,6 +355,14 @@ struct CommandBlockWrapperBase {
|
|||
uint32_t dCBWTag;
|
||||
uint32_t dCBWDataTransferLength;
|
||||
uint8_t bmCBWFlags;
|
||||
public:
|
||||
|
||||
CommandBlockWrapperBase() {
|
||||
}
|
||||
|
||||
CommandBlockWrapperBase(uint32_t tag, uint32_t xflen, uint8_t flgs) :
|
||||
dCBWSignature(MASS_CBW_SIGNATURE), dCBWTag(tag), dCBWDataTransferLength(xflen), bmCBWFlags(flgs) {
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CommandBlockWrapper : public CommandBlockWrapperBase {
|
||||
|
@ -156,6 +378,38 @@ struct CommandBlockWrapper : public CommandBlockWrapperBase {
|
|||
};
|
||||
|
||||
uint8_t CBWCB[16];
|
||||
|
||||
public:
|
||||
// All zeroed.
|
||||
|
||||
CommandBlockWrapper() :
|
||||
CommandBlockWrapperBase(0, 0, 0), bmReserved1(0), bmReserved2(0) {
|
||||
for(int i = 0; i < 16; i++) CBWCB[i] = 0;
|
||||
}
|
||||
|
||||
// Generic Wrap, CDB zeroed.
|
||||
|
||||
CommandBlockWrapper(uint32_t tag, uint32_t xflen, uint8_t flgs, uint8_t lu, uint8_t cmdlen, uint8_t cmd) :
|
||||
CommandBlockWrapperBase(tag, xflen, flgs),
|
||||
bmReserved1(0), bmReserved2(0), bmCBWLUN(lu), bmCBWCBLength(cmdlen) {
|
||||
for(int i = 0; i < 16; i++) CBWCB[i] = 0;
|
||||
((BASICCDB_t *) CBWCB)->LUN = cmd;
|
||||
}
|
||||
|
||||
// Wrap for CDB of 6
|
||||
|
||||
CommandBlockWrapper(uint32_t tag, uint32_t xflen, CDB6_t *cdb, uint8_t dir) :
|
||||
CommandBlockWrapperBase(tag, xflen, dir),
|
||||
bmReserved1(0), bmReserved2(0), bmCBWLUN(cdb->LUN), bmCBWCBLength(6) {
|
||||
memcpy(&CBWCB, cdb, 6);
|
||||
}
|
||||
// Wrap for CDB of 10
|
||||
|
||||
CommandBlockWrapper(uint32_t tag, uint32_t xflen, CDB10_t *cdb, uint8_t dir) :
|
||||
CommandBlockWrapperBase(tag, xflen, dir),
|
||||
bmReserved1(0), bmReserved2(0), bmCBWLUN(cdb->LUN), bmCBWCBLength(10) {
|
||||
memcpy(&CBWCB, cdb, 10);
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CommandStatusWrapper {
|
||||
|
@ -184,8 +438,6 @@ struct RequestSenseResponce {
|
|||
uint8_t SenseKeySpecific[3];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define MASS_MAX_ENDPOINTS 3
|
||||
|
||||
class BulkOnly : public USBDeviceConfig, public UsbConfigXtracter {
|
||||
protected:
|
||||
static const uint8_t epDataInIndex; // DataIn endpoint index
|
||||
|
@ -203,24 +455,22 @@ protected:
|
|||
EpInfo epInfo[MASS_MAX_ENDPOINTS];
|
||||
|
||||
uint32_t dCBWTag; // Tag
|
||||
uint32_t dCBWDataTransferLength; // Data Transfer Length
|
||||
//uint32_t dCBWDataTransferLength; // Data Transfer Length
|
||||
uint8_t bLastUsbError; // Last USB error
|
||||
uint8_t bMaxLUN; // Max LUN
|
||||
uint8_t bTheLUN; // Active LUN
|
||||
|
||||
protected:
|
||||
uint32_t CurrentCapacity[MASS_MAX_SUPPORTED_LUN]; // Total sectors
|
||||
uint16_t CurrentSectorSize[MASS_MAX_SUPPORTED_LUN]; // Sector size, clipped to 16 bits
|
||||
bool LUNOk[MASS_MAX_SUPPORTED_LUN]; // use this to check for media changes.
|
||||
bool WriteOk[MASS_MAX_SUPPORTED_LUN];
|
||||
void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr);
|
||||
|
||||
bool IsValidCBW(uint8_t size, uint8_t *pcbw);
|
||||
bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
|
||||
|
||||
bool IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw);
|
||||
|
||||
uint8_t ClearEpHalt(uint8_t index);
|
||||
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf, uint8_t flags);
|
||||
uint8_t HandleUsbError(uint8_t error, uint8_t index);
|
||||
uint8_t HandleSCSIError(uint8_t status);
|
||||
// Additional Initialization Method for Subclasses
|
||||
|
||||
virtual uint8_t OnInit() {
|
||||
return 0;
|
||||
};
|
||||
public:
|
||||
BulkOnly(USB *p);
|
||||
|
||||
|
@ -236,23 +486,21 @@ public:
|
|||
return bTheLUN; // Active LUN
|
||||
}
|
||||
|
||||
uint8_t Reset();
|
||||
uint8_t GetMaxLUN(uint8_t *max_lun);
|
||||
uint8_t SetCurLUN(uint8_t lun);
|
||||
|
||||
uint8_t ResetRecovery();
|
||||
uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf);
|
||||
uint8_t TestUnitReady(uint8_t lun);
|
||||
uint8_t ReadCapacity(uint8_t lun, uint16_t size, uint8_t *buf);
|
||||
uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf);
|
||||
uint8_t ModeSense(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *buf);
|
||||
boolean WriteProtected(uint8_t lun);
|
||||
uint8_t MediaCTL(uint8_t lun, uint8_t ctl);
|
||||
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf);
|
||||
uint8_t Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, USBReadParser *prs);
|
||||
uint8_t Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t *buf);
|
||||
uint8_t LockMedia(uint8_t lun, uint8_t lock);
|
||||
|
||||
bool LUNIsGood(uint8_t lun);
|
||||
uint32_t GetCapacity(uint8_t lun);
|
||||
uint16_t GetSectorSize(uint8_t lun);
|
||||
|
||||
// USBDeviceConfig implementation
|
||||
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
virtual uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
|
||||
virtual uint8_t Release();
|
||||
virtual uint8_t Poll();
|
||||
|
||||
|
@ -263,12 +511,40 @@ public:
|
|||
// UsbConfigXtracter implementation
|
||||
virtual void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||
|
||||
protected:
|
||||
// Additional Initialization Method for Subclasses
|
||||
virtual boolean DEVCLASSOK(uint8_t klass) {
|
||||
return(klass == USB_CLASS_MASS_STORAGE);
|
||||
}
|
||||
|
||||
uint8_t SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
|
||||
uint8_t SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir);
|
||||
|
||||
private:
|
||||
uint8_t Inquiry(uint8_t lun, uint16_t size, uint8_t *buf);
|
||||
uint8_t TestUnitReady(uint8_t lun);
|
||||
uint8_t RequestSense(uint8_t lun, uint16_t size, uint8_t *buf);
|
||||
uint8_t ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t *buf);
|
||||
uint8_t GetMaxLUN(uint8_t *max_lun);
|
||||
uint8_t SetCurLUN(uint8_t lun);
|
||||
void Reset();
|
||||
uint8_t ResetRecovery();
|
||||
uint8_t ReadCapacity10(uint8_t lun, uint8_t *buf);
|
||||
void ClearAllEP();
|
||||
void CheckMedia();
|
||||
boolean CheckLUN(uint8_t lun);
|
||||
uint8_t Page3F(uint8_t lun);
|
||||
bool IsValidCBW(uint8_t size, uint8_t *pcbw);
|
||||
bool IsMeaningfulCBW(uint8_t size, uint8_t *pcbw);
|
||||
|
||||
bool IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw);
|
||||
|
||||
uint8_t ClearEpHalt(uint8_t index);
|
||||
#if MS_WANT_PARSER
|
||||
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf, uint8_t flags);
|
||||
#endif
|
||||
uint8_t Transaction(CommandBlockWrapper *cbw, uint16_t bsize, void *buf);
|
||||
uint8_t HandleUsbError(uint8_t error, uint8_t index);
|
||||
uint8_t HandleSCSIError(uint8_t status);
|
||||
|
||||
virtual uint8_t OnInit() {
|
||||
return 0;
|
||||
};
|
||||
};
|
||||
|
||||
#endif // __MASSTORAGE_H__
|
||||
|
|
10
max3421e.h
10
max3421e.h
|
@ -14,11 +14,14 @@ Circuits At Home, LTD
|
|||
Web : http://www.circuitsathome.com
|
||||
e-mail : support@circuitsathome.com
|
||||
*/
|
||||
/* MAX3421E register/bit names and bitmasks */
|
||||
#if !defined(_usb_h_) || defined(_max3421e_h_)
|
||||
#error "Never include max3421e.h directly; include Usb.h instead"
|
||||
#else
|
||||
|
||||
#ifndef _max3421e_h_
|
||||
#define _max3421e_h_
|
||||
|
||||
/* MAX3421E register/bit names and bitmasks */
|
||||
|
||||
/* Arduino pin definitions */
|
||||
/* pin numbers to port numbers */
|
||||
|
||||
|
@ -27,9 +30,6 @@ e-mail : support@circuitsathome.com
|
|||
|
||||
//#define MAX_GPX 8
|
||||
|
||||
#define ON true
|
||||
#define OFF false
|
||||
|
||||
#define SE0 0
|
||||
#define SE1 1
|
||||
#define FSHOST 2
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue